diff --git a/.poggit.yml b/.poggit.yml index 79c2bec..d4ff13b 100644 --- a/.poggit.yml +++ b/.poggit.yml @@ -1,16 +1,14 @@ ---- # Poggit-CI Manifest. Open the CI at https://poggit.pmmp.io/ci/brokiem/SimpleNPC +--- # Poggit-CI Manifest. Open the CI at https://poggit.pmmp.io/ci/supercrafter333/SimpleNPC +build-by-default: true branches: - - master - - pm4-new - - use-nbt +- pm5 projects: SimpleNPC: path: "" - icon: "/assets/icon.png" libs: - src: brokiem-pm-pl/EasyUI/libEasyUI version: 3.0.0 - src: brokiem-pm-pl/UpdateChecker/UpdateChecker version: ^1.0.0 branch: "pm4" -... \ No newline at end of file +... diff --git a/plugin.yml b/plugin.yml index 55527d5..36669a3 100644 --- a/plugin.yml +++ b/plugin.yml @@ -1,8 +1,10 @@ name: SimpleNPC main: brokiem\snpc\SimpleNPC -version: 4.0.1-dev -api: 4.0.0 -author: brokiem +version: 4.2.0 +api: 5.0.0 +authors: + - brokiem + - supercrafter333 # I hope that's okay :) website: https://github.com/brokiem/SimpleNPC @@ -27,3 +29,5 @@ permissions: default: op simplenpc.rca: default: op + simplenpc.cmd: + default: true \ No newline at end of file diff --git a/resources/config.yml b/resources/config.yml index fc693fe..70e25d9 100644 --- a/resources/config.yml +++ b/resources/config.yml @@ -18,4 +18,7 @@ max-look-distance: 8 enable-command-cooldown: true # Coldown executing command when hit the NPC # Default: 1.0 (float) -command-execute-cooldown: 1.0 \ No newline at end of file +command-execute-cooldown: 1.0 + +# Here you can choose the emote interval. 6-7 seconds are recommended. +emote-interval-seconds: 7 \ No newline at end of file diff --git a/src/brokiem/snpc/EventHandler.php b/src/brokiem/snpc/EventHandler.php index ee24c28..b655f80 100644 --- a/src/brokiem/snpc/EventHandler.php +++ b/src/brokiem/snpc/EventHandler.php @@ -11,6 +11,8 @@ use brokiem\snpc\entity\BaseNPC; use brokiem\snpc\entity\CustomHuman; +use pocketmine\entity\projectile\Arrow; +use pocketmine\event\entity\EntityDamageByChildEntityEvent; use pocketmine\event\entity\EntityDamageByEntityEvent; use pocketmine\event\entity\EntityDamageEvent; use pocketmine\event\Listener; @@ -50,6 +52,7 @@ public function onDamage(EntityDamageEvent $event): void { if ($event instanceof EntityDamageByEntityEvent) { if ($entity instanceof CustomHuman || $entity instanceof BaseNPC) { + $event->setKnockBack(0.0); $event->cancel(); $damager = $event->getDamager(); @@ -127,4 +130,25 @@ public function onMove(PlayerMoveEvent $event): void { } } } + + /** + * @priority MONITOR + * @param EntityDamageByChildEntityEvent $ev + * @return void + */ + public static function oneEntityDamageByChildEntity(EntityDamageByChildEntityEvent $ev): void + { + $entity = $ev->getEntity(); + $child = $ev->getChild(); + if (!$entity instanceof BaseNPC || !$child instanceof Arrow) return; + + $ev->setKnockBack(0); + $child->setPunchKnockback(0); + $ev->cancel(); + } + + /*public function onWorldLoad(WorldLoadEvent $ev): void //TODO: not working!! + { + NPCManager::getInstance()->updateOldNPCs($ev->getWorld()); + }*/ } \ No newline at end of file diff --git a/src/brokiem/snpc/SimpleNPC.php b/src/brokiem/snpc/SimpleNPC.php index c79b42e..c83f745 100644 --- a/src/brokiem/snpc/SimpleNPC.php +++ b/src/brokiem/snpc/SimpleNPC.php @@ -15,8 +15,7 @@ use brokiem\snpc\entity\CustomHuman; use brokiem\snpc\entity\WalkingHuman; use brokiem\snpc\manager\NPCManager; -use brokiem\updatechecker\Promise; -use brokiem\updatechecker\UpdateChecker; +use brokiem\snpc\task\DoEmoteTask; use EasyUI\Form; use pocketmine\entity\Entity; use pocketmine\entity\EntityDataHelper; @@ -24,7 +23,6 @@ use pocketmine\entity\Human; use pocketmine\nbt\tag\CompoundTag; use pocketmine\plugin\PluginBase; -use pocketmine\scheduler\ClosureTask; use pocketmine\utils\SingletonTrait; use pocketmine\world\World; @@ -41,7 +39,7 @@ class SimpleNPC extends PluginBase { public array $lastHit = []; public array $cachedUpdate = []; public array $idPlayers = []; - private bool $isDev = true; + public const IS_DEV = true; protected function onEnable(): void { if (!class_exists(Form::class)) { @@ -50,7 +48,7 @@ protected function onEnable(): void { return; } - if ($this->isDev) { + if (self::IS_DEV) { $this->getLogger()->warning("You are using the Development version of SimpleNPC. The plugin will experience errors, crashes, or bugs. Only use this version if you are testing. Don't use the Dev version in production!"); } @@ -63,13 +61,15 @@ protected function onEnable(): void { $this->getServer()->getCommandMap()->registerAll("SimpleNPC", [new Commands("snpc", $this), new RcaCommand("rca", $this)]); $this->getServer()->getPluginManager()->registerEvents(new EventHandler($this), $this); - $this->getScheduler()->scheduleRepeatingTask(new ClosureTask(function(): void { - UpdateChecker::checkUpdate($this->getDescription()->getName(), $promise = new Promise()); + $this->getScheduler()->scheduleRepeatingTask(new DoEmoteTask(), $this->getConfig()->get("emote-interval-seconds", 7) * 20); + + /*$this->getScheduler()->scheduleRepeatingTask(new ClosureTask(function(): void { + UpdateChecker::checkUpdate($this->getDescription()->getName(), $this->getDescription()->getVersion(), $promise = new Promise()); $promise->then(function($data) { $this->cachedUpdate = [$data["version"], $data["last_state_change_date"], $data["html_url"]]; }); - }), 864000); // 12 hours + }), 864000); // 12 hours*/ } public static function registerEntity(string $entityClass, string $name, array $saveNames = []): void { diff --git a/src/brokiem/snpc/commands/Commands.php b/src/brokiem/snpc/commands/Commands.php index b49bd04..a630dfc 100644 --- a/src/brokiem/snpc/commands/Commands.php +++ b/src/brokiem/snpc/commands/Commands.php @@ -22,6 +22,7 @@ class Commands extends Command implements PluginOwned { public function __construct(string $name, private SimpleNPC $owner) { parent::__construct($name, "SimpleNPC commands"); + $this->setPermission("simplenpc.cmd"); } public function execute(CommandSender $sender, string $commandLabel, array $args): bool { diff --git a/src/brokiem/snpc/entity/BaseNPC.php b/src/brokiem/snpc/entity/BaseNPC.php index 9d8b452..5df86c6 100644 --- a/src/brokiem/snpc/entity/BaseNPC.php +++ b/src/brokiem/snpc/entity/BaseNPC.php @@ -15,6 +15,7 @@ use pocketmine\console\ConsoleCommandSender; use pocketmine\entity\Entity; use pocketmine\entity\EntitySizeInfo; +use pocketmine\event\entity\EntityDamageEvent; use pocketmine\nbt\NBT; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\ListTag; @@ -25,8 +26,6 @@ abstract class BaseNPC extends Entity { - protected $gravity = 0.0; - protected bool $lookToPlayers; protected CommandManager $commandManager; @@ -42,6 +41,8 @@ protected function initEntity(CompoundTag $nbt): void { $this->setNameTagAlwaysVisible((bool)$nbt->getByte("ShowNametag", 1)); $this->setNameTagVisible((bool)$nbt->getByte("ShowNametag", 1)); $this->setScale($nbt->getFloat("Scale", 1)); + + $this->setNoClientPredictions(); } public function saveNBT(): CompoundTag { @@ -124,4 +125,10 @@ public function getCommandManager(): CommandManager { abstract protected function getInitialSizeInfo(): EntitySizeInfo; abstract public static function getNetworkTypeId(): string; + + protected function getInitialDragMultiplier() : float{ return 0.00; } + + protected function getInitialGravity() : float{ return 0.00; } + + public function attack(EntityDamageEvent $source): void { $source->cancel(); } } \ No newline at end of file diff --git a/src/brokiem/snpc/entity/CustomHuman.php b/src/brokiem/snpc/entity/CustomHuman.php index 6037396..0f8b6d3 100644 --- a/src/brokiem/snpc/entity/CustomHuman.php +++ b/src/brokiem/snpc/entity/CustomHuman.php @@ -15,18 +15,24 @@ use pocketmine\console\ConsoleCommandSender; use pocketmine\entity\Human; use pocketmine\nbt\NBT; +use pocketmine\nbt\NoSuchTagException; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\StringTag; +use pocketmine\network\mcpe\protocol\EmotePacket; use pocketmine\player\Player; use pocketmine\utils\TextFormat; +use function in_array; class CustomHuman extends Human { - protected $gravity = 0.0; protected bool $canWalk = false; protected bool $lookToPlayers; + protected string|null $clickEmoteId = null; + + protected string|null $emoteId = null; + protected CommandManager $commandManager; protected function initEntity(CompoundTag $nbt): void { @@ -44,6 +50,12 @@ protected function initEntity(CompoundTag $nbt): void { $this->setNameTagAlwaysVisible((bool)$nbt->getByte("ShowNametag", 1)); $this->setNameTagVisible((bool)$nbt->getByte("ShowNametag", 1)); $this->setScale($nbt->getFloat("Scale", 1)); + try { + $this->setClickEmoteId($nbt->getString("ClickEmote") === "NULL" ? null : $nbt->getString("ClickEmote")); + } catch (NoSuchTagException) {} + try { + $this->setEmoteId($nbt->getString("Emote") === "NULL" ? null : $nbt->getString("Emote")); + } catch (NoSuchTagException) {} } public function saveNBT(): CompoundTag { @@ -51,6 +63,8 @@ public function saveNBT(): CompoundTag { $nbt->setFloat("Scale", $this->getScale()); //pm doesn't save this to the nbt $nbt->setByte("EnableRotation", (int)$this->lookToPlayers); $nbt->setByte("ShowNametag", (int)$this->isNameTagAlwaysVisible()); + $nbt->setString("ClickEmote", $this->getClickEmoteId() === null ? "NULL" : $this->getClickEmoteId()); + $nbt->setString("Emote", $this->getEmoteId() === null ? "NULL" : $this->getEmoteId()); $listTag = new ListTag([], NBT::TAG_String); //commands foreach ($this->commandManager->getAll() as $command) { @@ -60,6 +74,40 @@ public function saveNBT(): CompoundTag { return $nbt; } + /** + * @param string|null $clickEmoteId + */ + public function setClickEmoteId(?string $clickEmoteId): void + { + $this->clickEmoteId = $clickEmoteId; + $this->saveNBT(); + } + + /** + * @return string|null + */ + public function getClickEmoteId(): ?string + { + return $this->clickEmoteId === "NULL" ? null : $this->clickEmoteId; + } + + /** + * @param string|null $emoteId + */ + public function setEmoteId(?string $emoteId): void + { + $this->emoteId = $emoteId; + $this->saveNBT(); + } + + /** + * @return string|null + */ + public function getEmoteId(): ?string + { + return $this->emoteId === "NULL" ? null : $this->emoteId; + } + public function despawn(Player $deletor = null): bool { (new SNPCDeletionEvent($this, $deletor))->call(); @@ -104,6 +152,8 @@ public function interact(Player $player): void { } execute: + if ($this->getClickEmoteId() !== null) + $this->broadcastEmote($this->getClickEmoteId(), [$player]); if (!empty($commands = $this->getCommandManager()->getAll())) { foreach ($commands as $command) { $plugin->getServer()->getCommandMap()->dispatch(new ConsoleCommandSender($player->getServer(), $plugin->getServer()->getLanguage()), str_replace("{player}", '"' . $player->getName() . '"', $command)); @@ -134,4 +184,20 @@ public function canLookToPlayers(): bool { public function getCommandManager(): CommandManager { return $this->commandManager; } + + public function broadcastEmote(string $emoteId, array|null $targets = null): void + { + if (!in_array($emoteId, EmoteIds::EMOTES)) return; + + $pk = EmotePacket::create($this->getId(), $emoteId, "", "", EmotePacket::FLAG_MUTE_ANNOUNCEMENT); + if ($targets === null) + foreach ($this->getViewers() as $player) + $player->getNetworkSession()->sendDataPacket($pk); + else + foreach ($targets as $player) + $player->getNetworkSession()->sendDataPacket($pk); + } + + public function knockBack(float $x, float $z, float $force = 0.4, ?float $verticalLimit = 0.4): void + { return; } } \ No newline at end of file diff --git a/src/brokiem/snpc/entity/EmoteIds.php b/src/brokiem/snpc/entity/EmoteIds.php new file mode 100644 index 0000000..8a1e96f --- /dev/null +++ b/src/brokiem/snpc/entity/EmoteIds.php @@ -0,0 +1,110 @@ + '18891e6c-bb3d-47f6-bc15-265605d86525', + "Acting Like a Dragon" => 'c2a47805-c792-4882-a56d-17c80b6c57a8', + "Ahh Choo!" => 'f9345ebb-4ba3-40e6-ad9b-6bfb10c92890', + "Airplane" => 'e7bb3d8c-811d-442a-bfc5-775556d05d7a', + "Anger Management" => 'a0b1a9f2-0ea4-48d0-8641-ada998beee4d', + "Ballerina Twirl" => '79452f7e-ffa0-470f-8283-f5063348471d', + "Big Chuckles" => '819f2f36-2a16-440c-8e46-94c6b003a2e0', + "Bored" => '7a314ecf-f94c-42c0-945f-76903c923808', + "Bow" => 'ddfa6f0e-88ca-46de-b189-2bd5b18e96a0', + "Breakdance" => '1dbaa006-0ec6-42c3-9440-a3bfa0c6fdbe', + "Calling a Dragon" => '9f5d4732-0513-4a0a-8ea2-b6b8d7587e74', + "Cartwheel" => '5cf9d5a3-6fa0-424e-8ae4-d1f877b836da', + "Chatting" => '59d9e78c-f0bb-4f14-9e9b-7ab4f58ffbf5', + "Cheer Routine" => '3d10a8c7-213c-4fbe-a208-a0f7990d5bbb', + "Chun-Li Spinning Kick" => 'af61c759-6252-431d-a7de-94d477cfb54c', + "Clicking Heels" => '495d686a-4cb3-4f0b-beb5-bebdcb95eed9', + "Cowpoke Dancin'" => 'f99ccd35-ebda-4122-b458-ff8c9f9a432f', + "DJing" => 'beb74219-e90c-46aa-8a4b-a1c175f6cab5', + "Dancing Like Rapunzel" => 'f15ceb56-6651-41c0-8bd5-087951204d81', + "Dancing Like Toothless" => 'a12252fa-4ec8-42e0-a7d0-d44fbc90d753', + "Diamonds To You!" => '86b34976-8f41-475b-a386-385080dc6e83', + "Disappointed" => 'a98ea25e-4e6a-477f-8fc2-9e8a18ab7004', + "Doing Aerobics" => '2647f538-6fc6-4775-85ae-7f6f2a8065b2', + "Doing Hakuna Matata" => '71afa8ed-03b6-4808-b537-330daf9dbf50', + "Doing the Conga" => '5e1ef7ed-efdf-44a9-8ace-6cca6275d80d', + "Enamoured" => 'c4d87a21-d4c4-498b-8bc1-5dd78c895e9f', + "Excitedly Dancing" => 'd9d1192d-1262-470d-bc0c-5ba46bedab72', + "Exhausted" => '2391b018-3b8a-4bb0-9596-8edfc502d302', + "Facepalm" => '402efb2d-6607-47f2-b8e5-bc422bcd8304', + "Faceplant" => '6d9f24c0-6246-4c92-8169-4648d1981cbb', + "Fake Death" => 'efc2f0f5-af00-4d9e-a4b1-78f18d63be79', + "Feeling Sick" => ' bb6f1764-2b0b-4a3a-adfd-3334627cdee4', + "Flight" => 'b310ea06-0485-4ad1-8424-df271ca6ec37', + "Fluttering" => '9c939344-f9d6-4a3a-95a5-f64dd3d94e45', + "Flying Like Peter Pan" => '949c4f24-6aa6-4f2a-bad5-1b3de7e12749', + "Foot Stomp!" => '13334afa-bd66-4285-b3d9-d974046db479', + "Found Inspiration" => 'b690c36b-bd02-45df-a60b-00c0dbbf265f', + "Ghast Dance" => '5a5b2c0c-a924-4e13-a99b-4c12e3f02e1e', + "Giddy" => '738497ce-539f-4e06-9a03-dc528506a468', + "Giving R2-D2 a Message" => 'e1090020-cbe0-4b64-9c41-a3b9619da029', + "Going Hero" => 'f14d652f-18ed-42dc-831f-7f6a2eab1246', + "Golf Clap" => '434489fd-ed42-4814-961a-df14161d67e0', + "Got Chills" => 'af6ad96c-5754-4cf9-a463-49a8190e6b0e', + "Groovin'" => 'd863b9cc-9f8c-498b-a8a3-7ebd542cb08e', + "Hadoken!" => '6453480a-54ac-435d-899d-4e6f7fe57591', + "Hand Stand" => '5dd129f9-cfc3-4fc1-b464-c66a03061545', + "Hard Landing" => 'c2b9dd03-7258-4813-b6f5-37ef9b4a3326', + "Hitting the Omnitrix" => '1e30e8f4-2991-4aac-a58a-a6bf90a080c5', + "Hooray!" => 'c4b5b251-24d3-43eb-9c05-46be246aeefb', + "Hoppin'" => 'fb9b884a-b217-46a2-85fd-d3ab0f2f33e6', + "Hugging Themselves" => '54e2209a-41ec-4502-8500-dd51e569ab69', + "Intercom and Attack" => '87c039b7-7bdc-45d1-8684-e940a131ec0a', + "Jumping Jacks" => 'b13966b3-1f7c-4f07-8ab8-9d85170203f5', + "Kneeling" => '24444aea-cb6e-451f-90fc-b74e57cc7c5d', + "Laughing Out Loud" => '310b41de-1c7a-4098-928d-addcd905bf65', + "Mad Falling" => '63cb3c45-b3b3-4c02-a4f3-fb4b9853dbe9', + "Meditating Like Luke" => '85957448-e7bb-4bb4-9182-510b4428e52c', + "Minion Cheering" => '6174a111-19ac-41d1-a483-0e0b37f9d049', + "Minion Panicking" => '79e93b59-38f0-4796-8033-f99d7aa9334e', + "Minion Taunting" => 'a51f8e7c-a4dd-4ce1-9fc9-2c3cad66cede', + "Offering" => '21e0054a-5bf4-468d-bfc4-fc4b49bd44ac', + "Over Here!" => '71721c51-b7d1-46b1-b7ea-eb4c4126c3db', + "Pekaboo" => '2ecc0fd1-312b-4664-9bfa-a06429838706', + "Playing Dead" => '9d4019d0-db3f-4859-a579-f6c37532d2a6', + "Playing Zombie" => '5d644007-3cdf-4246-b4ca-cfd7a4318a1c', + "Posing Like a Hero" => '7102c0f7-6113-44f5-b37c-4e94841b0e81', + "ROLF" => '6f82688e-e549-408c-946d-f8e99b91808d', + "Rebooting" => 'a602063f-1ded-4959-b978-b5ae7f353536', + "Pouting" => '34259925-44dd-46f0-98e5-80ccebc086d0', + "Ryu Guarding" => '0c141653-1166-448b-87a2-38d0679bb549', + "Sad Sigh" => '98a68056-e025-4c0f-a959-d6e330ccb5f5', + "Salsa Dancing" => '6bcf44bd-ff8a-48a5-9254-3983a0b0f702', + "Saluting" => '1ea5f771-827d-408d-ae8e-1af00d7aa416', + "Shrug" => '4ff73ed2-3c2f-4d74-9055-5fa24e59dc7a', + "Shy Higgling" => 'f1e18201-729d-472d-9e4f-5cdd7f6bba0c', + "Sid Dance" => '946f04ea-8ff0-416e-a66d-8b0d0751e8bf', + "Simple Clap" => '9a469a61-c83b-4ba9-b507-bdbe64430582', + "Slimin'" => '70831936-d97d-48fe-a7e7-d8894e7c5507', + "Sonic-Finger-Wagging" => 'e8a91ad4-6f7a-479e-9556-e1a7c058351b', + "Sonic-Running" => 'b8e54924-ec3f-409c-8914-bca61fbe9242', + "Sonic-Victory-Spinning" => 'cd8c3bc6-f455-43d2-836e-62c1a19474c7', + "Surrendering" => 'daeaaa6f-db91-4461-8617-400c5d1b8646', + "Swinging Energy Sword" => 'd7680c67-8e54-482a-903d-622ddb43485f', + "Sword Flourish" => 'a57277d5-0693-4c8a-9b5c-45c33fdf7c26', + "The Elytra" => '7393aa53-9145-4e66-b23b-ec86def6c6f2', + "The Hammer" => '7cec98d8-55cc-44fe-b0ae-2672b0b2bd37', + "The Master Chief" => '88dc7deb-21bb-48c3-8b5a-00757a06aef9', + "The Pickaxe" => 'd7519b5a-45ec-4d27-997c-89d402c6b57f', + "The Splits" => '51871829-e9ef-40aa-939c-b8952295d50e', + "The Woodpunch" => '42fde774-37d4-4422-b374-89ff13a6535a', + "Thinking" => '20bcb500-af82-4c2f-9239-e78191c61375', + "To Infinity and Beyond" => '79e8cb30-c1b4-4e41-8aa8-96492c6f390c', + "Underwater Dancing" => '05af18ca-920f-4232-83cb-133b2d913dd6', + "Using Jedi Mind Trick" => '4b9b9f17-3722-4d38-a6a9-9ba0e8cf5044', + "Victorious" => '77053f59-c79b-4d5c-8dc5-539ed28002e9', + "Victory Cheer" => 'd0c60245-538e-4ea2-bdd4-33477db5aa89', + "Warm Up Drills" => '6b9c7731-7422-4333-950f-cf3d147ffa47', + "Wave" => '4c8ae710-df2e-47cd-814d-cc7bf21a3d67', + "Waving Like C-3PO" => 'c2d6091d-9f91-4a9e-badd-ef8481353cb0', + "Yoga" => '3f1bdf46-80b0-4a64-b631-4ac2f2491165' + ]; +} \ No newline at end of file diff --git a/src/brokiem/snpc/entity/WalkingHuman.php b/src/brokiem/snpc/entity/WalkingHuman.php index 557b4b0..83def3f 100644 --- a/src/brokiem/snpc/entity/WalkingHuman.php +++ b/src/brokiem/snpc/entity/WalkingHuman.php @@ -10,6 +10,7 @@ namespace brokiem\snpc\entity; use pocketmine\block\Air; +use pocketmine\block\BlockTypeIds; use pocketmine\block\Flowable; use pocketmine\block\Liquid; use pocketmine\math\Vector3; @@ -18,8 +19,7 @@ final class WalkingHuman extends CustomHuman { public Vector3 $randomPosition; - protected $gravity = 0.08; - protected $jumpVelocity = 0.45; + protected float $jumpVelocity = 0.45; private int $findNewPosition = 0; private float $speed = 0.35; private int $jumpTick = 30; @@ -27,6 +27,7 @@ final class WalkingHuman extends CustomHuman { protected function initEntity(CompoundTag $nbt): void { $this->canWalk = true; + $this->setNoClientPredictions(false); parent::initEntity($nbt); } @@ -107,7 +108,7 @@ public function shouldJump(): bool { if ($this->jumpTick === 0) { $this->jumpTick = 20; $pos = $this->getLocation()->add($this->getDirectionVector()->x * $this->getScale(), 0, $this->getDirectionVector()->z * $this->getScale())->round(); - return $this->getWorld()->getBlock($pos)->getId() !== 0 and !$this->getWorld()->getBlock($pos) instanceof Flowable; + return $this->getWorld()->getBlock($pos)->getTypeId() !== BlockTypeIds::AIR and !$this->getWorld()->getBlock($pos) instanceof Flowable; } return false; diff --git a/src/brokiem/snpc/entity/npc/AllayNPC.php b/src/brokiem/snpc/entity/npc/AllayNPC.php new file mode 100644 index 0000000..e0c4cd6 --- /dev/null +++ b/src/brokiem/snpc/entity/npc/AllayNPC.php @@ -0,0 +1,24 @@ +height, $this->width); + } + + public static function getNetworkTypeId(): string + { + return EntityIds::ALLAY; + } +} \ No newline at end of file diff --git a/src/brokiem/snpc/entity/npc/BeeNPC.php b/src/brokiem/snpc/entity/npc/BeeNPC.php new file mode 100644 index 0000000..a2620ef --- /dev/null +++ b/src/brokiem/snpc/entity/npc/BeeNPC.php @@ -0,0 +1,26 @@ +height, $this->width); + } + + public static function getNetworkTypeId(): string + { + return EntityIds::BEE; + } +} \ No newline at end of file diff --git a/src/brokiem/snpc/entity/npc/FoxNPC.php b/src/brokiem/snpc/entity/npc/FoxNPC.php new file mode 100644 index 0000000..082e583 --- /dev/null +++ b/src/brokiem/snpc/entity/npc/FoxNPC.php @@ -0,0 +1,24 @@ +height, $this->width); + } + + public static function getNetworkTypeId(): string + { + return EntityIds::FOX; + } +} \ No newline at end of file diff --git a/src/brokiem/snpc/entity/npc/FrogNPC.php b/src/brokiem/snpc/entity/npc/FrogNPC.php new file mode 100644 index 0000000..b3e12a4 --- /dev/null +++ b/src/brokiem/snpc/entity/npc/FrogNPC.php @@ -0,0 +1,24 @@ +height, $this->width); + } + + public static function getNetworkTypeId(): string + { + return EntityIds::FROG; + } +} \ No newline at end of file diff --git a/src/brokiem/snpc/entity/npc/PandaNPC.php b/src/brokiem/snpc/entity/npc/PandaNPC.php new file mode 100644 index 0000000..778b254 --- /dev/null +++ b/src/brokiem/snpc/entity/npc/PandaNPC.php @@ -0,0 +1,24 @@ +height, $this->width); + } + + public static function getNetworkTypeId(): string + { + return EntityIds::PANDA; + } +} \ No newline at end of file diff --git a/src/brokiem/snpc/entity/npc/RavagerNPC.php b/src/brokiem/snpc/entity/npc/RavagerNPC.php new file mode 100644 index 0000000..a1f567c --- /dev/null +++ b/src/brokiem/snpc/entity/npc/RavagerNPC.php @@ -0,0 +1,24 @@ +height, $this->width); + } + + public static function getNetworkTypeId(): string + { + return EntityIds::RAVAGER; + } +} \ No newline at end of file diff --git a/src/brokiem/snpc/entity/npc/StriderNPC.php b/src/brokiem/snpc/entity/npc/StriderNPC.php new file mode 100644 index 0000000..e593df7 --- /dev/null +++ b/src/brokiem/snpc/entity/npc/StriderNPC.php @@ -0,0 +1,24 @@ +height, $this->width); + } + + public static function getNetworkTypeId(): string + { + return EntityIds::STRIDER; + } +} \ No newline at end of file diff --git a/src/brokiem/snpc/entity/npc/TurtleNPC.php b/src/brokiem/snpc/entity/npc/TurtleNPC.php new file mode 100644 index 0000000..5744cbb --- /dev/null +++ b/src/brokiem/snpc/entity/npc/TurtleNPC.php @@ -0,0 +1,26 @@ +height, $this->width); + } + + public static function getNetworkTypeId(): string + { + return EntityIds::TURTLE; + } +} \ No newline at end of file diff --git a/src/brokiem/snpc/manager/NPCManager.php b/src/brokiem/snpc/manager/NPCManager.php index 3f04558..b0773bb 100644 --- a/src/brokiem/snpc/manager/NPCManager.php +++ b/src/brokiem/snpc/manager/NPCManager.php @@ -11,25 +11,33 @@ use brokiem\snpc\entity\BaseNPC; use brokiem\snpc\entity\CustomHuman; +use brokiem\snpc\entity\npc\AllayNPC; use brokiem\snpc\entity\npc\AxolotlNPC; use brokiem\snpc\entity\npc\BatNPC; +use brokiem\snpc\entity\npc\BeeNPC; use brokiem\snpc\entity\npc\BlazeNPC; use brokiem\snpc\entity\npc\ChickenNPC; use brokiem\snpc\entity\npc\CowNPC; use brokiem\snpc\entity\npc\CreeperNPC; use brokiem\snpc\entity\npc\EndermanNPC; +use brokiem\snpc\entity\npc\FoxNPC; +use brokiem\snpc\entity\npc\FrogNPC; use brokiem\snpc\entity\npc\GlowsquidNPC; use brokiem\snpc\entity\npc\GoatNPC; use brokiem\snpc\entity\npc\HorseNPC; use brokiem\snpc\entity\npc\OcelotNPC; +use brokiem\snpc\entity\npc\PandaNPC; use brokiem\snpc\entity\npc\PigNPC; use brokiem\snpc\entity\npc\PolarBearNPC; +use brokiem\snpc\entity\npc\RavagerNPC; use brokiem\snpc\entity\npc\SheepNPC; use brokiem\snpc\entity\npc\ShulkerNPC; use brokiem\snpc\entity\npc\SkeletonNPC; use brokiem\snpc\entity\npc\SlimeNPC; use brokiem\snpc\entity\npc\SnowGolem; use brokiem\snpc\entity\npc\SpiderNPC; +use brokiem\snpc\entity\npc\StriderNPC; +use brokiem\snpc\entity\npc\TurtleNPC; use brokiem\snpc\entity\npc\VillagerNPC; use brokiem\snpc\entity\npc\WitchNPC; use brokiem\snpc\entity\npc\WolfNPC; @@ -40,13 +48,18 @@ use pocketmine\entity\Human; use pocketmine\entity\Location; use pocketmine\math\Vector3; +use pocketmine\nbt\NoSuchTagException; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\DoubleTag; use pocketmine\nbt\tag\FloatTag; use pocketmine\nbt\tag\ListTag; use pocketmine\player\Player; +use pocketmine\utils\Config; use pocketmine\utils\SingletonTrait; use pocketmine\utils\TextFormat; +use pocketmine\world\World; +use function is_string; +use function unlink; class NPCManager { use SingletonTrait; @@ -74,7 +87,15 @@ class NPCManager { VillagerNPC::class => ["villager_snpc", "simplenpc:villager"], WitchNPC::class => ["witch_snpc", "simplenpc:witch"], WolfNPC::class => ["wolf_snpc", "simplenpc:wolf"], - ZombieNPC::class => ["zombie_snpc", "simplenpc:zombie"] + ZombieNPC::class => ["zombie_snpc", "simplenpc:zombie"], + BeeNPC::class => ["bee_snpc", "simplenpc:bee"], + AllayNPC::class => ["allay_snpc", "simplenpc:allay"], + FoxNPC::class => ["fox_snpc", "simplenpc:fox"], + FrogNPC::class => ["frog_snpc", "simplenpc:frog"], + PandaNPC::class => ["panda_snpc", "simplenpc:panda"], + RavagerNPC::class => ["ravager_snpc", "simplenpc:ravager"], + StriderNPC::class => ["strider_snpc", "simplenpc:strider"], + TurtleNPC::class => ["turtle_snpc", "simplenpc:turtle"] ]; public function getDefaultNPCs(): array { @@ -178,4 +199,39 @@ public function getAllNPCs(): ?array { return $npcs; } + + public function getOldNPCData(string $identifier): array + { + $path = SimpleNPC::getInstance()->getDataFolder() . "npcs/$identifier.json"; + return file_exists($path) + ? (new Config($path, Config::JSON))->getAll() + : []; + } + + public function updateOldNPCs(World $world): void + { + foreach ($world->getEntities() as $entity) + if ($entity instanceof BaseNPC) { + $ident = null; + try { + $ident = $entity->saveNBT()->getString("Identifier"); + } catch (NoSuchTagException $e) {} + + if (is_string($ident)) { + $data = $this->getOldNPCData($ident); + if (isset($data["nametag"])) + $entity->setNameTag($data["nametag"]); + if (isset($data["showNametag"])) + $entity->setNameTagVisible($data["showNametag"]); + if (isset($data["scale"])) + $entity->setScale($data["scale"]); + if (isset($data["commands"])) + foreach ($data["commands"] as $command) + $entity->getCommandManager()->add($command); + + unlink(SimpleNPC::getInstance()->getDataFolder() . "npcs/$ident.json"); + $entity->respawnToAll(); + } + } + } } diff --git a/src/brokiem/snpc/manager/command/CommandManager.php b/src/brokiem/snpc/manager/command/CommandManager.php index babd4a0..0c60b6d 100644 --- a/src/brokiem/snpc/manager/command/CommandManager.php +++ b/src/brokiem/snpc/manager/command/CommandManager.php @@ -30,11 +30,7 @@ public function add($command): bool { } public function exists(string $command): bool { - if (in_array($command, $this->commands, true)) { - return true; - } - - return false; + return in_array($command, $this->commands, true); } public function getAll(): array { @@ -43,7 +39,7 @@ public function getAll(): array { public function remove($command): bool { if ($this->exists($command)) { - unset($this->commands[$command]); + unset($this->commands[array_search($command, $this->commands, true)]); return true; } diff --git a/src/brokiem/snpc/manager/form/ButtonManager.php b/src/brokiem/snpc/manager/form/ButtonManager.php index 9234a82..4821474 100644 --- a/src/brokiem/snpc/manager/form/ButtonManager.php +++ b/src/brokiem/snpc/manager/form/ButtonManager.php @@ -39,11 +39,6 @@ public function getUIButtons(): array { "command" => "snpc id", "function" => null - ], "Migrate NPC" => [ - "text" => "Migrate NPC", - "icon" => null, - "command" => "snpc migrate", - "function" => null ], "Remove NPC" => [ "text" => "Remove NPC", "icon" => null, @@ -179,6 +174,32 @@ public function getEditButtons(): array { "force" => true ] ] + ], "Set Click-Emote" => [ + "text" => "Set Click-Emote", + "icon" => null, + "element" => [], + "additional" => [ + "form" => "editUI", + "button" => [ + "text" => "Set Click-Emote", + "icon" => null, + "function" => "setClickEmote", + "force" => true + ] + ] + ], "Set Emote" => [ + "text" => "Set Emote", + "icon" => null, + "element" => [], + "additional" => [ + "form" => "editUI", + "button" => [ + "text" => "Set Emote", + "icon" => null, + "function" => "setEmote", + "force" => true + ] + ] ], "Command List" => [ "text" => "Command List", "icon" => null, diff --git a/src/brokiem/snpc/manager/form/FormManager.php b/src/brokiem/snpc/manager/form/FormManager.php index 218fc07..1c509dd 100644 --- a/src/brokiem/snpc/manager/form/FormManager.php +++ b/src/brokiem/snpc/manager/form/FormManager.php @@ -11,6 +11,7 @@ use brokiem\snpc\entity\BaseNPC; use brokiem\snpc\entity\CustomHuman; +use brokiem\snpc\entity\EmoteIds; use brokiem\snpc\entity\WalkingHuman; use brokiem\snpc\SimpleNPC; use brokiem\snpc\task\async\URLToCapeTask; @@ -22,9 +23,10 @@ use EasyUI\utils\FormResponse; use EasyUI\variant\CustomForm; use EasyUI\variant\SimpleForm; +use InvalidArgumentException; use pocketmine\entity\Entity; use pocketmine\entity\Skin; -use pocketmine\item\ItemIds; +use pocketmine\item\VanillaItems; use pocketmine\player\Player; use pocketmine\utils\SingletonTrait; use pocketmine\utils\TextFormat; @@ -144,6 +146,38 @@ public function sendEditForm(Player $sender, array $args, int $entityId): void { $entity->setCanLookToPlayers(true); $sender->sendMessage(TextFormat::GREEN . "Successfully enable npc rotate (NPC ID: " . $entity->getId() . ")"); break; + case "setClickEmote": + $clickEmoteUI = new SimpleForm("Edit Click-Emote", "Please choose a new click-emote."); + if ($entity->getClickEmoteId() !== null) $clickEmoteUI->addButton(new Button( + "§cRemove Click-Emote", null, + function (Player $player) use ($entity) { + $entity->setClickEmoteId(null); + $player->sendMessage("§aSuccessfully removed the click-emote of NPC ID: " . $entity->getId()); + })); + foreach (EmoteIds::EMOTES as $emoteName => $emoteId) + $clickEmoteUI->addButton(new Button($emoteName, null, + function (Player $player) use ($entity, $emoteId, $emoteName) { + $entity->setClickEmoteId($emoteId); + $player->sendMessage("§aSuccessfully set the click-emote of NPC ID: " . $entity->getId() . " to §7" . $emoteName); + })); + $sender->sendForm($clickEmoteUI); + break; + case "setEmote": + $emoteUI = new SimpleForm("Edit Emote", "Please choose a new emote."); + if ($entity->getEmoteId() !== null) $emoteUI->addButton(new Button( + "§cRemove Emote", null, + function (Player $player) use ($entity) { + $entity->setEmoteId(null); + $player->sendMessage("§aSuccessfully removed the emote of NPC ID: " . $entity->getId()); + })); + foreach (EmoteIds::EMOTES as $emoteName => $emoteId) + $emoteUI->addButton(new Button($emoteName, null, + function (Player $player) use ($entity, $emoteId, $emoteName) { + $entity->setEmoteId($emoteId); + $player->sendMessage("§aSuccessfully set the emote of NPC ID: " . $entity->getId() . " to §7" . $emoteName); + })); + $sender->sendForm($emoteUI); + break; case "setArmor": if ($entity instanceof CustomHuman) { $entity->applyArmorFrom($sender); @@ -154,7 +188,7 @@ public function sendEditForm(Player $sender, array $args, int $entityId): void { break; case "setHeld": if ($entity instanceof CustomHuman) { - if ($sender->getInventory()->getItemInHand()->getId() === ItemIds::AIR) { + if ($sender->getInventory()->getItemInHand()->equals(VanillaItems::AIR(), false ,false)) { $sender->sendMessage(TextFormat::RED . "Please hold the item in your hand"); } else { $entity->sendHeldItemFrom($sender); @@ -219,14 +253,38 @@ public function sendEditForm(Player $sender, array $args, int $entityId): void { } $customForm->setSubmitListener(function(Player $player, FormResponse $response) use ($plugin, $entity) { - $addcmd = $response->getInputSubmittedText("addcmd"); - $rmcmd = $response->getInputSubmittedText("removecmd"); - $chnmtd = $response->getInputSubmittedText("changenametag"); - $scale = $response->getInputSubmittedText("changescale"); - $skin = $response->getInputSubmittedText("changeskin"); - $cape = $response->getInputSubmittedText("changecape"); - - if ($rmcmd != "") { + try { + $addcmd = $response->getInputSubmittedText("addcmd"); + } catch (InvalidArgumentException) { + $addcmd = null; + } + try { + $rmcmd = $response->getInputSubmittedText("removecmd"); + } catch (InvalidArgumentException) { + $rmcmd = null; + } + try { + $chnmtd = $response->getInputSubmittedText("changenametag"); + } catch (InvalidArgumentException) { + $chnmtd = null; + } + try { + $scale = $response->getInputSubmittedText("changescale"); + } catch (InvalidArgumentException) { + $scale = null; + } + try { + $skin = $response->getInputSubmittedText("changeskin"); + } catch (InvalidArgumentException) { + $skin = null; + } + try { + $cape = $response->getInputSubmittedText("changecape"); + } catch (InvalidArgumentException) { + $cape = null; + } + + if ($rmcmd !== null) { if (!in_array($rmcmd, $entity->getCommandManager()->getAll(), true)) { $player->sendMessage(TextFormat::RED . "Command '$rmcmd' not found in command list."); return; @@ -234,7 +292,7 @@ public function sendEditForm(Player $sender, array $args, int $entityId): void { $entity->getCommandManager()->remove($rmcmd); $player->sendMessage(TextFormat::GREEN . "Successfully remove command '$rmcmd' (NPC ID: " . $entity->getId() . ")"); - } elseif ($addcmd != "") { + } elseif ($addcmd !== null) { if (in_array($addcmd, $entity->getCommandManager()->getAll(), true)) { $player->sendMessage(TextFormat::RED . "Command '$addcmd' has already been added."); return; @@ -242,12 +300,12 @@ public function sendEditForm(Player $sender, array $args, int $entityId): void { $entity->getCommandManager()->add($addcmd); $player->sendMessage(TextFormat::GREEN . "Successfully added command '$addcmd' (NPC ID: " . $entity->getId() . ")"); - } elseif ($chnmtd != "") { + } elseif ($chnmtd !== null) { $player->sendMessage(TextFormat::GREEN . "Successfully change npc nametag from '{$entity->getNameTag()}' to '$chnmtd' (NPC ID: " . $entity->getId() . ")"); $entity->setNameTag(str_replace("{line}", "\n", $chnmtd)); $entity->setNameTagAlwaysVisible(); - } elseif ($cape != "") { + } elseif ($cape !== null) { if (!$entity instanceof CustomHuman) { $player->sendMessage(TextFormat::RED . "Only human NPC can change cape!"); return; @@ -265,7 +323,7 @@ public function sendEditForm(Player $sender, array $args, int $entityId): void { } $plugin->getServer()->getAsyncPool()->submitTask(new URLToCapeTask($cape, $plugin->getDataFolder(), $entity, $player->getName())); - } elseif ($skin != "") { + } elseif ($skin !== null) { if (!$entity instanceof CustomHuman) { $player->sendMessage(TextFormat::RED . "Only human NPC can change skin!"); return; @@ -288,7 +346,7 @@ public function sendEditForm(Player $sender, array $args, int $entityId): void { $plugin->getServer()->getAsyncPool()->submitTask(new URLToSkinTask($player->getName(), $plugin->getDataFolder(), $skin, $entity)); $player->sendMessage(TextFormat::GREEN . "Successfully change npc skin (NPC ID: " . $entity->getId() . ")"); - } elseif ($scale != "") { + } elseif ($scale !== null) { if ((float)$scale <= 0) { $player->sendMessage("Scale must be greater than 0"); return; diff --git a/src/brokiem/snpc/task/DoEmoteTask.php b/src/brokiem/snpc/task/DoEmoteTask.php new file mode 100644 index 0000000..e927296 --- /dev/null +++ b/src/brokiem/snpc/task/DoEmoteTask.php @@ -0,0 +1,24 @@ +getWorldManager()->getWorlds() as $world) + if ($world->isLoaded()) + foreach ($world->getEntities() as $NPC) + if ($NPC instanceof CustomHuman && $NPC->getEmoteId() !== null) + $NPC->broadcastEmote($NPC->getEmoteId()); + + /*foreach (NPCManager::getInstance()->getAllNPCs() as $NPC) + if ($NPC instanceof CustomHuman && $NPC->getEmoteId() !== null) + $NPC->broadcastEmote($NPC->getEmoteId());*/ + } +} \ No newline at end of file