diff --git a/plugin.yml b/plugin.yml index 43bf81f..ddf3fd5 100644 --- a/plugin.yml +++ b/plugin.yml @@ -1,17 +1,7 @@ name: NPC author: alvin0319 -main: alvin0319\NPC\NPCPlugin -version: 1.0.10 +main: alvin0319\NPC\NPCLoader +version: 2.0.0 api: 3.0.0 -mcpe-protocol: 408 - -commands: - npc: - description: NPC command. - permission: npc.command - -permissions: - npc.command: - default: op - description: Allow to control command npc. \ No newline at end of file +mcpe-protocol: 408 \ No newline at end of file diff --git a/resources/config.yml b/resources/config.yml deleted file mode 100644 index d852e85..0000000 --- a/resources/config.yml +++ /dev/null @@ -1,9 +0,0 @@ -images: [] - -lang: eng - -spawn-radius: 10 - -disable-see-player: false - -config-version: 1.0.1 \ No newline at end of file diff --git a/resources/eng.yml b/resources/eng.yml deleted file mode 100644 index 20d6a21..0000000 --- a/resources/eng.yml +++ /dev/null @@ -1,22 +0,0 @@ -plugin.prefix: "§b§l[NPC] §r§7" -ext-gd.missing: "The gd-extension is not installed" -path.notExist: "The file {%0} is not exist" -entity.spawn: "{%0} entity created" -entity.path: "Please input the Skin or Geometry file path" -entity.geometry: "GeometryName does not exist in the geometry file" -entity.notExist: "That entity is not exist" -entity.delete: "Entity delete successfully" -entity.notExistId: "That entity is not exist" -command.create.usage: "/npc create [type] [name] [skinPath(optional)] [geometryPath(optional)] - Create entity" -command.delete.usage: "/npc remove [id] - Delete entity" -command.edit.usage: "/npc edit [command|message|scale] [text...] - Edit entity" -command.get.usage: "/npc get - Get entities" -command.item.usage: "/npc item - Set item to NPC" -command.onlyAccept: "{%0} is only accept {%1}" -command.entity.list: "Entity list: " -command.list.empty: "The list is empty" -command.list: "The entity list: " -command.remove.message: "Please attack the entity that want to remove npc" -command.edit.message: "Please attack the entity that want to edit" -message.notExtend: "That entity is not NPC" -message.noGeometryName: "Please insert geometryName in {%0}" \ No newline at end of file diff --git a/resources/kor.yml b/resources/kor.yml deleted file mode 100644 index c7b8704..0000000 --- a/resources/kor.yml +++ /dev/null @@ -1,22 +0,0 @@ -plugin.prefix: "§b§l[NPC] §r§7" -ext-gd.missing: "현재 실행중인 PHP 바이너리에 gd 라이브러리가 설치되어 있지 않습니다." -path.notExist: "{%0} 파일이 존재하지 않습니다." -entity.spawn: "{%0} 엔티티가 생성되었습니다." -entity.path: "스킨 파일이나 모델링 파일의 경로를 입력해주세요." -entity.geometry: "해당 geometry 파일에 geometryName이 존재하지 않습니다." -entity.notExist: "해당 종류의 엔티티가 존재하지 않습니다." -entity.delete: "엔티티를 성공적으로 제거했습니다." -entity.notExistId: "해당 엔티티는 존재하지 않습니다." -command.create.usage: "/npc create [타입] [이름] [스킨 경로(필요시)] [geometry 경로(필요시)] - 엔티티를 생성합니다." -command.delete.usage: "/npc remove [아이디] - 엔티티를 제거합니다." -command.edit.usage: "/npc edit [command|message|scale] [text...] - 엔티티를 수정합니다." -command.get.usage: "/npc get - 엔티티 목록을 불러옵니다." -command.item.usage: "/npc item - 엔피시의 아이템을 설정합니다." -command.onlyAccept: "{%0}은(는) {%1}만 허용합니다." -command.entity.list: "사용 가능한 엔티티: " -command.list.empty: "등록된 엔티티가 없습니다." -command.list: "엔티티 목록: " -command.remove.message: "제거되길 원하는 엔티티를 터치해주세요." -command.edit.message: "적용되길 원하는 엔티티를 터치해주세요." -message.notExtend: "해당 엔티티는 NPC가 아닙니다." -message.edit.success: "성공적으로 엔티티를 수정했습니다." \ No newline at end of file diff --git a/src/alvin0319/NPC/EventListener.php b/src/alvin0319/NPC/EventListener.php deleted file mode 100644 index 0bd8e06..0000000 --- a/src/alvin0319/NPC/EventListener.php +++ /dev/null @@ -1,123 +0,0 @@ -getPlayer(); - $packet = $event->getPacket(); - - if($packet instanceof InventoryTransactionPacket){ - if($packet->transactionType === InventoryTransactionPacket::TYPE_USE_ITEM_ON_ENTITY){ - $entity = NPCPlugin::getInstance()->getEntity($packet->trData->entityRuntimeId); - - if(isset(Queue::$removeQueue[$player->getName()])){ - if($entity instanceof EntityBase){ - $player->sendMessage(PluginLang::$prefix . NPCPlugin::getInstance()->getLanguage()->translateLanguage("entity.delete")); - foreach($entity->getViewers() as $player){ - $entity->despawnTo($player); - } - - NPCPlugin::getInstance()->removeEntity($entity); - unset(Queue::$removeQueue[$player->getName()]); - }else{ - $player->sendMessage(PluginLang::$prefix . NPCPlugin::getInstance()->getLanguage()->translateLanguage("message.notExtend")); - } - return; - } - - if(isset(Queue::$editQueue[$player->getName()])){ - if($entity instanceof EntityBase){ - if(Queue::$editQueue[$player->getName()] ["mode"] === "command"){ - $entity->setCommand(Queue::$editQueue[$player->getName()] ["target"]); - }elseif(Queue::$editQueue[$player->getName()] ["mode"] === "message"){ - $entity->setMessage(Queue::$editQueue[$player->getName()] ["target"]); - }else{ - if(is_numeric(Queue::$editQueue[$player->getName()] ["target"])){ - $entity->setScale((float) Queue::$editQueue[$player->getName()] ["target"]); - }else{ - $player->sendMessage(PluginLang::$prefix . NPCPlugin::getInstance()->getLanguage()->translateLanguage("command.onlyAccept", [ - "scale", - "float" - ])); - } - } - $player->sendMessage(PluginLang::$prefix . "Edit success."); - unset(Queue::$editQueue[$player->getName()]); - }else{ - $player->sendMessage(PluginLang::$prefix . NPCPlugin::getInstance()->getLanguage()->translateLanguage("message.notExtend")); - } - return; - } - - if(isset(Queue::$itemQueue[$player->getName()])){ - if($entity instanceof EntityBase){ - if($entity instanceof NPCHuman){ - $entity->setItem(Queue::$itemQueue[$player->getName()]); - unset(Queue::$itemQueue[$player->getName()]); - $player->sendMessage(PluginLang::$prefix . "Succeed to set item."); - }else{ - $player->sendMessage(PluginLang::$prefix . "That entity is not NPCHuman"); - } - }else{ - $player->sendMessage(PluginLang::$prefix . NPCPlugin::getInstance()->getLanguage()->translateLanguage("message.notExtend")); - } - return; - } - - if(isset(Queue::$offItemQueue[$player->getName()])){ - if($entity instanceof NPCHuman){ - $entity->setItem(Queue::$offItemQueue[$player->getName()], true); - unset(Queue::$offItemQueue[$player->getName()]); - $player->sendMessage(PluginLang::$prefix . "Succeed to set offhand item."); - }else{ - $player->sendMessage(PluginLang::$prefix . "That entity is not NPCHuman"); - } - } - - if($entity instanceof EntityBase || $entity instanceof NPCHuman){ - $entity->interact($player); - } - } - } - } - - public function handleQuit(PlayerQuitEvent $event){ - $player = $event->getPlayer(); - foreach(NPCPlugin::getInstance()->getEntities() as $entityBase){ - $entityBase->despawnTo($player); - } - } - - public function handleMove(PlayerMoveEvent $event){ - $player = $event->getPlayer(); - if(NPCPlugin::getInstance()->getConfig()->getNested("disable-see-player", false)){ - return; - } - foreach(NPCPlugin::getInstance()->getEntities() as $entityBase){ - if($entityBase->getLocation()->getLevel()->getFolderName() === $player->getLevel()->getFolderName()){ - if($entityBase->getLocation()->distance($player->getLocation()) <= (int) NPCPlugin::getInstance()->getConfig()->getNested("spawn-radius", 10)){ - $entityBase->spawnTo($player); - $entityBase->lookAt($player); - }else{ - $entityBase->despawnTo($player); - } - }else{ - $entityBase->despawnTo($player); - } - } - } -} \ No newline at end of file diff --git a/src/alvin0319/NPC/NPCLoader.php b/src/alvin0319/NPC/NPCLoader.php new file mode 100644 index 0000000..a432d72 --- /dev/null +++ b/src/alvin0319/NPC/NPCLoader.php @@ -0,0 +1,31 @@ +getDataFolder() . "images/") or !is_dir($this->getDataFolder() . "images/")){ - mkdir($this->getDataFolder() . "images/"); - } - - $this->lang = new PluginLang($this); - - $this->saveResource("config.yml"); - - if(version_compare(self::CONFIG_VERSION, $this->getConfig()->getNested("config-version", self::CONFIG_VERSION)) > 0){ - $this->getLogger()->debug("Found old config data, replacing..."); - unlink($this->getDataFolder() . "config.yml"); - $this->saveResource("config.yml"); - $this->lang->saveNewLang(); - } - - $this->getServer()->getPluginManager()->registerEvents(new EventListener(), $this); - - $this->data = $this->getConfig()->getAll(); - - if(!file_exists($file = $this->getDataFolder() . "npc.dat")){ - $nbt = new CompoundTag(); - $nbt->setTag(new ListTag("npc")); - file_put_contents($file, (new LittleEndianNBTStream())->writeCompressed($nbt)); - } - - $data = (new LittleEndianNBTStream())->readCompressed(file_get_contents($file)); - - foreach($data->getListTag("npc")->getValue() as $tag){ - if($tag instanceof CompoundTag){ - switch($tag->getInt("type")){ - case NPCHuman::NETWORK_ID: - $class = NPCHuman::nbtDeserialize($tag); - break; - case CustomEntity::NETWORK_ID: - $class = CustomEntity::nbtDeserialize($tag); - break; - default: - throw new \InvalidStateException("Unknown entity type " . $tag->getInt("type")); - } - - if(!$class->getLocation()->getLevel() instanceof Level){ - $this->getLogger()->debug("Skip registering " . $class->getRealName() . " due to not level loaded."); - continue; - } - - $this->entities[$class->getId()] = $class; - } - } - - $promise = new Promise(); - - $this->getServer()->getAsyncPool()->submitTask(new CheckVersionAsyncTask($promise)); - - $promise->then(function(array $result){ - $ver = $this->getDescription()->getVersion(); - - $lastVer = $result["version"]; - - if(version_compare($lastVer, $ver) > 0){ - $mustUpdate = $result["update"] ?? false; - $message = $result["message"] ?? ""; - - $this->getLogger()->notice("The New version of NPC was released. Now version: " . $ver . ", Last version: " . $lastVer); - $this->getLogger()->info("Update message: " . $message); - - if($mustUpdate){ - $this->getLogger()->emergency("You must update this plugin before you can use it."); - $this->getServer()->getPluginManager()->disablePlugin($this); - } - }else{ - $this->getLogger()->info("The latest version."); - } - })->catch(function(string $err){ - $this->getLogger()->critical($err); - }); - - $this->imageConfig = new ImageConfig($this); - } - - public function onDisable() : void{ - $nbt = new CompoundTag(); - $tag = new ListTag("npc"); - - foreach(array_values($this->entities) as $baseEntity){ - $tag->push($baseEntity->nbtSerialize()); - } - $nbt->setTag($tag); - file_put_contents($this->getDataFolder() . "npc.dat", (new LittleEndianNBTStream())->writeCompressed($nbt)); - - $this->imageConfig->save(); - } - - public function onCommand(CommandSender $sender, Command $command, string $label, array $args) : bool{ - if(!$sender instanceof Player){ - return false; - } - switch($args[0] ?? "x"){ - case "create": - if(isset($args[1])){// type - if(isset($args[2])){// nametag - if($args[1] === "npc"){ - if(isset($args[3])){// path, or something - $path = $args[3]; - $bool = true; - if(isset($args[4])){// geometry path, or something - if(file_exists($this->getDataFolder() . "images/" . $args[4])){ - $data = json_decode(file_get_contents($this->getDataFolder() . "images/" . $args[4]), true); - - if(!is_string($geometryName = $this->findGeometryName($data))){ - $sender->sendMessage(PluginLang::$prefix . $this->lang->translateLanguage("entity.geometry")); - break; - } - - $geometryData = json_encode($data); - }else{ - $sender->sendMessage(PluginLang::$prefix . $this->lang->translateLanguage("path.notExist", [$args[4]])); - break; - } - } - try{ - $skin = $this->imageToSkin($sender, $path, isset($geometryName) ? $geometryName : "", isset($geometryData) ? $geometryData : ""); - }catch(ExtensionNotLoadedException $e){ - $bool = false; - $sender->sendMessage(PluginLang::$prefix . $e->getMessage()); - }catch(FileNotFoundException $e){ - $bool = false; - $sender->sendMessage(PluginLang::$prefix . $e->getMessage()); - } - - $nbt = new CompoundTag("Skin"); - - if($bool && isset($skin)){ - $nbt->setString("name", $args[2]); - $nbt->setByte("isCustomSkin", 1); - $nbt->setTag($this->getSkinCompound($skin)); - - /** @var NPCHuman $entity */ - $entity = new NPCHuman($sender->getLocation(), $nbt); - $this->entities[$entity->getId()] = $entity; - - $sender->sendMessage(PluginLang::$prefix . $this->lang->translateLanguage("entity.spawn", [$entity->getRealName()])); - } - }else{ - $skin = $sender->getSkin(); - $nbt = new CompoundTag(); - $nbt->setString("name", $args[2]); - $nbt->setTag($this->getSkinCompound($skin)); - - /** @var NPCHuman $entity */ - $entity = new NPCHuman($sender->getLocation(), $nbt); - $this->entities[$entity->getId()] = $entity; - - $sender->sendMessage(PluginLang::$prefix . $this->lang->translateLanguage("entity.spawn", [$entity->getRealName()])); - } - }else{ - if(in_array($args[1], array_keys(EntityConfig::NETWORK_IDS))){ - $nbt = new CompoundTag(); - $nbt->setString("name", $args[2]); - /** @var EntityBase $entity */ - $entity = new CustomEntity(EntityConfig::NETWORK_IDS[$args[1]], $sender->getLocation(), $nbt); - $this->entities[$entity->getId()] = $entity; - $sender->sendMessage(PluginLang::$prefix . $this->lang->translateLanguage("entity.spawn", [$entity->getRealName()])); - }else{ - $sender->sendMessage(PluginLang::$prefix . $this->lang->translateLanguage("entity.notExist")); - } - } - }else{ - $sender->sendMessage(PluginLang::$prefix . $this->lang->translateLanguage("command.create.usage")); - } - }else{ - $sender->sendMessage(PluginLang::$prefix . $this->lang->translateLanguage("command.create.usage")); - } - break; - case "remove": - Queue::$removeQueue[$sender->getName()] = time(); - $sender->sendMessage(PluginLang::$prefix . $this->lang->translateLanguage("command.remove.message")); - break; - case "get": - if(count($this->entities) === 0){ - $sender->sendMessage(PluginLang::$prefix . $this->lang->translateLanguage("command.list.empty")); - break; - } - - $sender->sendMessage(PluginLang::$prefix . $this->lang->translateLanguage("command.list") . implode(", ", array_map(function(EntityBase $entityBase) : string{ - return "#" . $entityBase->getId() . " " . $entityBase->getRealName() . ": " . self::pos2hash($entityBase->getLocation()); - }, array_values($this->entities)))); - break; - case "edit": - if(isset($args[1])){ - if(isset($args[2])){ - if(in_array($args[1], ["command", "message", "scale"])){ - Queue::$editQueue[$sender->getName()] = [ - "mode" => $args[1], - "target" => $args[2] - ]; - $sender->sendMessage(PluginLang::$prefix . $this->lang->translateLanguage("command.edit.message")); - }else{ - $sender->sendMessage(PluginLang::$prefix . $this->lang->translateLanguage("command.edit.usage")); - } - }else{ - $sender->sendMessage(PluginLang::$prefix . $this->lang->translateLanguage("command.edit.usage")); - } - }else{ - $sender->sendMessage(PluginLang::$prefix . $this->lang->translateLanguage("command.edit.usage")); - } - break; - case "item": - $item = $sender->getInventory()->getItemInHand(); - Queue::$itemQueue[$sender->getName()] = $item; - $sender->sendMessage(PluginLang::$prefix . "Please attack the entity that you want to set item."); - break; - case "offhand": - $item = $sender->getInventory()->getItemInHand(); - Queue::$offItemQueue[$sender->getName()] = $item; - $sender->sendMessage(PluginLang::$prefix . "Please attack the entity that you want to set offhand item."); - break; - default: - $sender->sendMessage(PluginLang::$prefix . $this->lang->translateLanguage("command.create.usage")); - $sender->sendMessage(PluginLang::$prefix . $this->lang->translateLanguage("command.delete.usage")); - $sender->sendMessage(PluginLang::$prefix . $this->lang->translateLanguage("command.edit.usage")); - $sender->sendMessage(PluginLang::$prefix . $this->lang->translateLanguage("command.get.usage")); - $sender->sendMessage(PluginLang::$prefix . $this->lang->translateLanguage("command.item.usage")); - $sender->sendMessage(PluginLang::$prefix . $this->lang->translateLanguage("command.entity.list") . implode(", ", array_keys(EntityConfig::NETWORK_IDS)) . ", npc"); - } - return true; - } - - /** - * @param Player $player - * @param string $path - * @param string $geometryName - * @param string $geometryData - * - * @return Skin - * @throws ExtensionNotLoadedException - * @throws FileNotFoundException - * - * TO-DO: Process this as asynchronous - */ - private function imageToSkin(Player $player, string $path, string $geometryName = "", string $geometryData = "") : Skin{ - if(!extension_loaded("gd")){ - throw new ExtensionNotLoadedException($this->lang->translateLanguage("ext-gd.missing")); - } - - if(!file_exists($path = $this->getDataFolder() . "images/" . $path)){ - throw new FileNotFoundException($this->lang->translateLanguage("path.notExist", [$path])); - } - - $img = imagecreatefrompng($path); - $bytes = ''; - for($y = 0; $y < imagesy($img); $y++){ - for($x = 0; $x < imagesx($img); $x++){ - $rgba = @imagecolorat($img, $x, $y); - $a = ((~((int) ($rgba >> 24))) << 1) & 0xff; - $r = ($rgba >> 16) & 0xff; - $g = ($rgba >> 8) & 0xff; - $b = $rgba & 0xff; - $bytes .= chr($r) . chr($g) . chr($b) . chr($a); - } - } - @imagedestroy($img); - return new Skin($player->getSkin()->getSkinId(), $bytes, "", $geometryName, $geometryData); - } - - private function findGeometryName(array $decodedJsonData) : ?string{ - if(isset($decodedJsonData["geometryName"])){ - return $decodedJsonData["geometryName"]; - } - if(isset($decodedJsonData["minecraft:geometry"][0]["description"]["identifier"])) - return $decodedJsonData["minecraft:geometry"][0]["description"]["identifier"]; - return null; - } - - /** - * @param Skin $skin - * - * @return CompoundTag - */ - public function getSkinCompound(Skin $skin) : CompoundTag{ - $nbt = new CompoundTag("Skin"); - $nbt->setString("Name", $skin->getSkinId()); - $nbt->setByteArray("Data", $skin->getSkinData()); - $nbt->setByteArray("CapeData", $skin->getCapeData()); - $nbt->setString("GeometryName", $skin->getGeometryName()); - $nbt->setByteArray("GeometryData", $skin->getGeometryData()); - - return $nbt; - } - - /** - * @param Location $pos - * - * @return string - */ - public static function pos2hash(Location $pos) : string{ - return implode(":", [$pos->x, $pos->y, $pos->z, $pos->level->getFolderName()]); - } - - /** - * @return PluginLang - * @internal - */ - public function getLanguage() : PluginLang{ - return $this->lang; - } - - /** - * @return ImageConfig - * @deprecated - */ - public function getImageConfig() : ImageConfig{ - return $this->imageConfig; - } - - /** - * @param EntityBase $entityBase - */ - public function removeEntity(EntityBase $entityBase){ - unset($this->entities[$entityBase->getId()]); - } - - /** - * @return EntityBase[] - */ - public function getEntities() : array{ - return array_values($this->entities); - } - - /** - * @param int $runtimeId - * - * @return EntityBase|null - */ - public function getEntity(int $runtimeId) : ?EntityBase{ - return $this->entities[$runtimeId] ?? null; - } -} \ No newline at end of file diff --git a/src/alvin0319/NPC/Queue.php b/src/alvin0319/NPC/Queue.php deleted file mode 100644 index 55794f8..0000000 --- a/src/alvin0319/NPC/Queue.php +++ /dev/null @@ -1,15 +0,0 @@ - 19, - "blaze" => 43, - "cave_spider" => 40, - "chicken" => 10, - "cod" => 112, - "cow" => 11, - "creeper" => 33, - "dolphin" => 31, - "donkey" => 24, - "elder_guardian" => 50, - "ender_charge" => 79, - "ender_dragon" => 53, - "enderman" => 38, - "endermite" => 55, - "evoker" => 104, - "ghast" => 41, - "guardian" => 49, - "horse" => 23, - "husk" => 47, - "iron_golem" => 20, - "large_fireball" => 85, - "llama" => 29, - "magma_cube" => 42, - "mooshroom" => 16, - "mule" => 25, - "ocelot" => 22, - "parrot" => 30, - "pig" => 12, - "pig_zombie" => 36, - "polar_bear" => 28, - "pufferfish" => 108, - "rabbit" => 18, - "salmon" => 109, - "sheep" => 13, - "shulker" => 54, - "silverfish" => 39, - "skeleton" => 34, - "skeleton_horse" => 26, - "slime" => 37, - "small_fireball" => 94, - "snow_golem" => 21, - "spider" => 35, - "squid" => 17, - "stray" => 46, - "tropicalfish" => 111, - "vex" => 105, - "villager" => 15, - "vindicator" => 57, - "witch" => 45, - "wither_skeleton" => 48, - "wither" => 52, - "wolf" => 14, - "zombie" => 32, - "zombie_pigman" => 36, - "zombie_villager" => 44 - ]; - - public const WIDTHS = [ - self::NETWORK_IDS["bat"] => 0.484, - self::NETWORK_IDS["blaze"] => 1.25, - self::NETWORK_IDS["cave_spider"] => 1.438, - self::NETWORK_IDS["chicken"] => 1, - self::NETWORK_IDS["cod"] => 0.5, - self::NETWORK_IDS["cow"] => 1.5, - self::NETWORK_IDS["creeper"] => 0.7, - self::NETWORK_IDS["donkey"] => 1.2, - self::NETWORK_IDS["dolphin"] => 1.2, - self::NETWORK_IDS["elder_guardian"] => 1.9975, - self::NETWORK_IDS["ender_charge"] => 1.0, - self::NETWORK_IDS["ender_dragon"] => 2.5, - self::NETWORK_IDS["enderman"] => 1.094, - self::NETWORK_IDS["endermite"] => 0.4, - self::NETWORK_IDS["evoker"] => 1.031, - self::NETWORK_IDS["ghast"] => 4.5, - self::NETWORK_IDS["guardian"] => 0, - self::NETWORK_IDS["horse"] => 1.3, - self::NETWORK_IDS["husk"] => 1.031, - self::NETWORK_IDS["iron_golem"] => 2.688, - self::NETWORK_IDS["large_fireball"] => 0.5, - self::NETWORK_IDS["llama"] => 0.9, - self::NETWORK_IDS["magma_cube"] => 1.2, - self::NETWORK_IDS["mooshroom"] => 1.781, - self::NETWORK_IDS["mule"] => 1.2, - self::NETWORK_IDS["ocelot"] => 0.8, - self::NETWORK_IDS["parrot"] => 0.5, - self::NETWORK_IDS["pig"] => 1.5, - self::NETWORK_IDS["pig_zombie"] => 1.125, - self::NETWORK_IDS["polar_bear"] => 1.3, - self::NETWORK_IDS["pufferfish"] => 0.35, - self::NETWORK_IDS["rabbit"] => 0.4, - self::NETWORK_IDS["sheep"] => 0.9, - self::NETWORK_IDS["shulker"] => 1.0, - self::NETWORK_IDS["silverfish"] => 1.094, - self::NETWORK_IDS["skeleton"] => 0.875, - self::NETWORK_IDS["skeleton_horse"] => 1.3, - self::NETWORK_IDS["slime"] => 1.2, - self::NETWORK_IDS["small_fireball"] => 0.25, - self::NETWORK_IDS["snow_golem"] => 1.281, - self::NETWORK_IDS["stray"] => 0.875, - self::NETWORK_IDS["spider"] => 2.062, - self::NETWORK_IDS["squid"] => 0, - self::NETWORK_IDS["tropicalfish"] => 0.5, - self::NETWORK_IDS["vex"] => 0.4, - self::NETWORK_IDS["villager"] => 0.938, - self::NETWORK_IDS["vindicator"] => 0.6, - self::NETWORK_IDS["witch"] => 0.6, - self::NETWORK_IDS["wither"] => 0.9, - self::NETWORK_IDS["wither_skeleton"] => 0.875, - self::NETWORK_IDS["wolf"] => 1.2, - self::NETWORK_IDS["zombie"] => 1.031, - self::NETWORK_IDS["zombie_pigman"] => 2.0, - self::NETWORK_IDS["zombie_villager"] => 1.031 - ]; - // Entity Heights - const HEIGHTS = [ - self::NETWORK_IDS["bat"] => 0.5, - self::NETWORK_IDS["blaze"] => 1.5, - self::NETWORK_IDS["cave_spider"] => 0.547, - self::NETWORK_IDS["chicken"] => 0.8, - self::NETWORK_IDS["cod"] => 0.3, - self::NETWORK_IDS["cow"] => 1.2, - self::NETWORK_IDS["creeper"] => 1.7, - self::NETWORK_IDS["donkey"] => 1.562, - self::NETWORK_IDS["dolphin"] => 1.562, - self::NETWORK_IDS["elder_guardian"] => 1.9975, - self::NETWORK_IDS["ender_charge"] => 1.0, - self::NETWORK_IDS["ender_dragon"] => 1.0, - self::NETWORK_IDS["enderman"] => 2.875, - self::NETWORK_IDS["endermite"] => 0.3, - self::NETWORK_IDS["evoker"] => 2.125, - self::NETWORK_IDS["ghast"] => 4.5, - self::NETWORK_IDS["guardian"] => 0, - self::NETWORK_IDS["horse"] => 1.5, - self::NETWORK_IDS["husk"] => 2.0, - self::NETWORK_IDS["iron_golem"] => 1.625, - self::NETWORK_IDS["large_fireball"] => 0.5, - self::NETWORK_IDS["llama"] => 1.87, - self::NETWORK_IDS["magma_cube"] => 1.2, - self::NETWORK_IDS["mooshroom"] => 1.875, - self::NETWORK_IDS["mule"] => 1.562, - self::NETWORK_IDS["ocelot"] => 0.8, - self::NETWORK_IDS["parrot"] => 0.9, - self::NETWORK_IDS["pig"] => 1.0, - self::NETWORK_IDS["pig_zombie"] => 2.03, - self::NETWORK_IDS["polar_bear"] => 1.4, - self::NETWORK_IDS["pufferfish"] => 0.35, - self::NETWORK_IDS["rabbit"] => 0.5, - self::NETWORK_IDS["sheep"] => 1.3, - self::NETWORK_IDS["shulker"] => 1.0, - self::NETWORK_IDS["silverfish"] => 0.438, - self::NETWORK_IDS["skeleton"] => 2.0, - self::NETWORK_IDS["skeleton_horse"] => 1.5, - self::NETWORK_IDS["slime"] => 1.2, - self::NETWORK_IDS["small_fireball"] => 0.25, - self::NETWORK_IDS["snow_golem"] => 1.875, - self::NETWORK_IDS["stray"] => 2.0, - self::NETWORK_IDS["spider"] => 0.781, - self::NETWORK_IDS["squid"] => 0.0, - self::NETWORK_IDS["tropicalfish"] => 0.5, - self::NETWORK_IDS["vex"] => 0.8, - self::NETWORK_IDS["villager"] => 2.0, - self::NETWORK_IDS["vindicator"] => 1.95, - self::NETWORK_IDS["witch"] => 1.95, - self::NETWORK_IDS["wither"] => 3.5, - self::NETWORK_IDS["wither_skeleton"] => 2.0, - self::NETWORK_IDS["wolf"] => 0.969, - self::NETWORK_IDS["zombie"] => 2.01, - self::NETWORK_IDS["zombie_pigman"] => 2.0, - self::NETWORK_IDS["zombie_villager"] => 2.125 - ]; -} \ No newline at end of file diff --git a/src/alvin0319/NPC/config/ImageConfig.php b/src/alvin0319/NPC/config/ImageConfig.php deleted file mode 100644 index 9eaa2f3..0000000 --- a/src/alvin0319/NPC/config/ImageConfig.php +++ /dev/null @@ -1,73 +0,0 @@ -plugin = $plugin; - - $data = (new Config($plugin->getDataFolder() . "ImageData.yml", Config::YAML))->getAll(); - - foreach($data as $name => $datum){ - $image = new Image($datum["skinBytes"], $datum["geometryName"], $datum["geometryData"]); - $this->images[$name] = $image; - } - } - - /** - * @param string $key - * - * @return Image|null - */ - public function getImageData(string $key) : ?Image{ - return $this->images[$key] ?? null; - } - - /** - * @return Image[] - */ - public function getAllImages() : array{ - return $this->images; - } - - public function addImage(string $name, string $skinBytes, string $geometryName, string $geometryData){ - $this->images[$name] = new Image($skinBytes, $geometryName, $geometryData); - } - - public function removeImage(string $name){ - unset($this->images[$name]); - } - - public function save(){ - $config = new Config($this->plugin->getDataFolder() . "ImageData.yml", Config::YAML); - $arr = []; - - foreach($this->images as $name => $image){ - $arr[$name] = [ - "skinBytes" => $image->getSkinBytes(), - "geometryName" => $image->getGeometryName(), - "geometryData" => $image->getGeometryData() - ]; - } - - $config->setAll($arr); - $config->save(); - } -} \ No newline at end of file diff --git a/src/alvin0319/NPC/entity/CustomEntity.php b/src/alvin0319/NPC/entity/CustomEntity.php index 3bd4777..163253d 100644 --- a/src/alvin0319/NPC/entity/CustomEntity.php +++ b/src/alvin0319/NPC/entity/CustomEntity.php @@ -3,82 +3,17 @@ namespace alvin0319\NPC\entity; -use alvin0319\NPC\config\EntityConfig; -use pocketmine\entity\Entity; -use pocketmine\level\Location; -use pocketmine\nbt\tag\CompoundTag; -use pocketmine\nbt\tag\FloatTag; -use pocketmine\network\mcpe\protocol\AddActorPacket; -use pocketmine\Player; -use pocketmine\Server; +use pocketmine\entity\Living; -use function explode; -use function in_array; +use function spl_object_id; -class CustomEntity extends EntityBase{ +class CustomEntity extends Living{ + use EntityTrait; - public const NETWORK_ID = 0xf; - - /** @var int */ + /** @var string */ protected $networkId; - protected $width; - - protected $height; - - /** - * CustomEntity constructor. - * - * @param int $networkId - * @param Location $location - * @param CompoundTag $nbt - */ - public function __construct(int $networkId, Location $location, CompoundTag $nbt){ - parent::__construct($location, $nbt); - $this->networkId = $networkId; - - $this->width = EntityConfig::WIDTHS[$this->id]; - $this->height = EntityConfig::HEIGHTS[$this->id]; - - if($nbt->hasTag("width", FloatTag::class) && $nbt->hasTag("height", FloatTag::class)){ - $this->width = $nbt->getFloat("width"); - $this->height = $nbt->getFloat("height"); - } - - $this->scale = $nbt->getFloat("scale", 1.0); - } - - public function getNetworkId() : int{ - return $this->networkId; - } - - public function spawnTo(Player $player) : void{ - if(in_array($player, $this->hasSpawned, true)){ - return; - } - $pk = new AddActorPacket(); - $pk->entityRuntimeId = $this->getId(); - $pk->type = AddActorPacket::LEGACY_ID_MAP_BC[$this->id]; - $pk->position = $this->location->asVector3(); - $pk->motion = null; - $pk->yaw = $this->location->yaw; - $pk->headYaw = $this->location->yaw; - $pk->pitch = $this->location->pitch; - $pk->metadata = $data = $this->getSyncedNetworkData(false); - - $player->sendDataPacket($pk); - $this->hasSpawned[] = $player; - } - - public static function nbtDeserialize(CompoundTag $nbt){ - [$x, $y, $z, $world] = explode(":", $nbt->getString("pos")); - return new CustomEntity($nbt->getInt("networkId"), new Location((float) $x, (float) $y, (float) $z, 0.0, 0.0, Server::getInstance()->getLevelByName($world)), $nbt); - } - - public function nbtSerialize() : CompoundTag{ - $nbt = parent::nbtSerialize(); - $nbt->setInt("networkId", $this->networkId); - $nbt->setInt("type", self::NETWORK_ID); - return $nbt; + public function getName() : string{ + return "CustomEntity #" . spl_object_id($this); } } \ No newline at end of file diff --git a/src/alvin0319/NPC/entity/EntityBase.php b/src/alvin0319/NPC/entity/EntityBase.php deleted file mode 100644 index 977508c..0000000 --- a/src/alvin0319/NPC/entity/EntityBase.php +++ /dev/null @@ -1,339 +0,0 @@ -location = $location; - $this->initEntity($nbt); - $this->id = Entity::$entityCount++; - $this->networkProperties = new DataPropertyManager(); - $this->server = Server::getInstance(); - } - - /** - * @param CompoundTag $nbt - */ - public function initEntity(CompoundTag $nbt) : void{ - if($nbt->hasTag("name", StringTag::class)){ - $this->name = $nbt->getString("name"); - } - - if($nbt->hasTag("scale", FloatTag::class)){ - $this->scale = $nbt->getFloat("scale"); - } - - $this->command = $nbt->getString("command", ""); - $this->message = $nbt->getString("message", ""); - } - - public function getRealName() : string{ - return $this->name; - } - - /** - * @param Vector3 $target - * - * @see Living::lookAt() - */ - public function lookAt(Vector3 $target){ - $horizontal = sqrt(($target->x - $this->location->x) ** 2 + ($target->z - $this->location->z) ** 2); - $vertical = $target->y - $this->location->y; - $this->location->pitch = -atan2($vertical, $horizontal) / M_PI * 180; //negative is up, positive is down - - $xDist = $target->x - $this->location->x; - $zDist = $target->z - $this->location->z; - $this->location->yaw = atan2($zDist, $xDist) / M_PI * 180 - 90; - if($this->location->yaw < 0){ - $this->location->yaw += 360.0; - } - - $pk = new MoveActorAbsolutePacket(); - $pk->xRot = $this->location->pitch; - $pk->yRot = $this->location->yaw; - $pk->zRot = $this->location->yaw; - $pk->position = $this->location; - $pk->entityRuntimeId = $this->id; - - foreach($this->getViewers() as $player){ - $player->sendDataPacket($pk); - } - } - - /** - * @return string - */ - public function getMessage() : string{ - return $this->message; - } - - /** - * @return string - */ - public function getCommand() : string{ - return $this->command; - } - - /** - * @param string $message - */ - public function setMessage(string $message){ - $this->message = $message; - } - - /** - * @param string $command - */ - public function setCommand(string $command){ - $this->command = $command; - } - - /** - * @return Location - */ - public function getLocation() : Location{ - return $this->location; - } - - /** - * @return int - */ - public function getId() : int{ - return $this->id; - } - - /** - * @return Server - */ - public function getServer() : Server{ - return $this->server; - } - - /** - * @param $player - * @param array|null $data - * - * @see Entity::sendData() - */ - public function sendData($player, ?array $data = null) : void{ - if(!is_array($player)){ - $player = [$player]; - } - - $pk = new SetActorDataPacket(); - $pk->entityRuntimeId = $this->getId(); - $pk->metadata = $data ?? $this->getSyncedNetworkData(false); - - foreach($player as $p){ - if($p === $this){ - continue; - } - $p->sendDataPacket(clone $pk); - } - } - - /** - * @see Entity::syncNetworkData() - */ - protected function syncNetworkData() : void{ - $this->networkProperties->setByte(Entity::DATA_ALWAYS_SHOW_NAMETAG, 1); - $this->networkProperties->setFloat(Entity::DATA_BOUNDING_BOX_HEIGHT, $this->height); - $this->networkProperties->setFloat(Entity::DATA_BOUNDING_BOX_WIDTH, $this->width); - $this->networkProperties->setFloat(Entity::DATA_SCALE, $this->scale); - $this->networkProperties->setLong(Entity::DATA_LEAD_HOLDER_EID, -1); - $this->networkProperties->setLong(Entity::DATA_OWNER_EID, -1); - $this->networkProperties->setLong(Entity::DATA_TARGET_EID, 0); - $this->networkProperties->setString(Entity::DATA_NAMETAG, $this->name); - - $this->setGenericFlag(Entity::DATA_FLAG_AFFECTED_BY_GRAVITY, true); - $this->setGenericFlag(Entity::DATA_FLAG_CAN_SHOW_NAMETAG, true); - $this->setGenericFlag(Entity::DATA_FLAG_HAS_COLLISION, true); - $this->setGenericFlag(Entity::DATA_FLAG_IMMOBILE, false); - $this->setGenericFlag(Entity::DATA_FLAG_INVISIBLE, false); - $this->setGenericFlag(Entity::DATA_FLAG_ONFIRE, false); - $this->setGenericFlag(Entity::DATA_FLAG_SNEAKING, false); - $this->setGenericFlag(Entity::DATA_FLAG_WALLCLIMBING, false); - $this->setGenericFlag(Entity::DATA_FLAG_ALWAYS_SHOW_NAMETAG, true); - } - - /** - * @param bool $dirtyOnly - * - * @return array - */ - final protected function getSyncedNetworkData(bool $dirtyOnly) : array{ - $this->syncNetworkData(); - - return $dirtyOnly ? $this->networkProperties->getDirty() : $this->networkProperties->getAll(); - } - - abstract public static function nbtDeserialize(CompoundTag $nbt); - - public function nbtSerialize() : CompoundTag{ - $nbt = new CompoundTag(); - $nbt->setString("name", $this->name); - $nbt->setString("message", $this->message); - $nbt->setString("command", $this->command); - $nbt->setString("pos", implode(":", [ - $this->location->x, - $this->location->y, - $this->location->z, - $this->location->level->getFolderName() - ])); - $nbt->setFloat("scale", $this->scale); - $nbt->setFloat("width", $this->width); - $nbt->setFloat("height", $this->height); - return $nbt; - } - - public function spawnTo(Player $player) : void{ - - } - - public function despawnTo(Player $player) : void{ - if(!in_array($player, $this->hasSpawned, true)){ - return; - } - - $pk = new RemoveActorPacket(); - $pk->entityUniqueId = $this->id; - $player->sendDataPacket($pk); - - $key = array_search($player, $this->hasSpawned, true); - if($key !== false){ - unset($this->hasSpawned[$key]); - } - } - - /** - * @return Player[] - */ - public function getViewers() : array{ - return $this->hasSpawned; - } - - public function setScale(float $scale){ - $this->scale = $scale; - - $multiplier = $scale / $this->scale; - - $this->width *= $multiplier; - $this->height *= $multiplier; - } - - /** - * @param int $propertyId - * @param int $flagId - * @param bool $value - * @param int $propertyType - */ - public function setDataFlag(int $propertyId, int $flagId, bool $value = true, int $propertyType = Entity::DATA_TYPE_LONG) : void{ - if($this->getDataFlag($propertyId, $flagId) !== $value){ - $flags = (int) $this->networkProperties->getPropertyValue($propertyId, $propertyType); - $flags ^= 1 << $flagId; - $this->networkProperties->setPropertyValue($propertyId, $propertyType, $flags); - } - } - - /** - * @param int $propertyId - * @param int $flagId - * - * @return bool - */ - public function getDataFlag(int $propertyId, int $flagId) : bool{ - return (((int) $this->networkProperties->getPropertyValue($propertyId, -1)) & (1 << $flagId)) > 0; - } - - /** - * Wrapper around {@link Entity#getDataFlag} for generic data flag reading. - * - * @param int $flagId - * - * @return bool - */ - public function getGenericFlag(int $flagId) : bool{ - return $this->getDataFlag($flagId >= 64 ? Entity::DATA_FLAGS2 : Entity::DATA_FLAGS, $flagId % 64); - } - - /** - * Wrapper around {@link Entity#setDataFlag} for generic data flag setting. - * - * @param int $flagId - * @param bool $value - */ - public function setGenericFlag(int $flagId, bool $value = true) : void{ - $this->setDataFlag($flagId >= 64 ? Entity::DATA_FLAGS2 : Entity::DATA_FLAGS, $flagId % 64, $value, Entity::DATA_TYPE_LONG); - } - - public function interact(Player $player){ - if(trim($this->getMessage()) !== ""){ - $player->sendMessage($this->getMessage()); - } - - if(trim($this->getCommand()) !== ""){ - $player->getServer()->dispatchCommand($player, $this->getCommand()); - } - } -} \ No newline at end of file diff --git a/src/alvin0319/NPC/entity/EntityTrait.php b/src/alvin0319/NPC/entity/EntityTrait.php new file mode 100644 index 0000000..67902b9 --- /dev/null +++ b/src/alvin0319/NPC/entity/EntityTrait.php @@ -0,0 +1,15 @@ +uuid = UUID::fromRandom(); - - $skinTag = $nbt->getCompoundTag("Skin"); - - if($skinTag === null){ - throw new \InvalidStateException((new \ReflectionClass($this))->getShortName() . " must have a valid skin set"); - } - - $this->skin = new Skin($skinTag->getString("Name"), $skinTag->hasTag("Data", StringTag::class) ? $skinTag->getString("Data") : $skinTag->getByteArray("Data"), $skinTag->getByteArray("CapeData", ""), $skinTag->getString("GeometryName", ""), $skinTag->getByteArray("GeometryData", "")); - - $this->isCustomSkin = $nbt->getByte("isCustomSkin", 0) === 1 ? true : false; - - if($nbt->hasTag("width", FloatTag::class) && $nbt->hasTag("height", FloatTag::class)){ - $this->width = $nbt->getFloat("width"); - $this->height = $nbt->getFloat("height"); - } - - $this->scale = $nbt->getFloat("scale", 1.0); - - if($nbt->hasTag("item", CompoundTag::class)){ - $this->item = Item::nbtDeserialize($nbt->getCompoundTag("item")); - }else{ - $this->item = ItemFactory::get(0); - } - if($nbt->hasTag("offHand", CompoundTag::class)){ - $this->offHandItem = Item::nbtDeserialize($nbt->getCompoundTag("offHand")); - }else{ - $this->offHandItem = ItemFactory::get(0); - } - } - - public function getName() : string{ - return (new \ReflectionClass($this))->getShortName(); - } - - public function spawnTo(Player $player) : void{ - if(in_array($player, $this->hasSpawned, true)){ - return; - } - - $pk = new PlayerListPacket(); - $pk->entries = [PlayerListEntry::createAdditionEntry($this->uuid, $this->id, $this->getName(), SkinAdapterSingleton::get()->toSkinData($this->skin))]; - $pk->type = PlayerListPacket::TYPE_ADD; - $player->sendDataPacket($pk); - - $pk = new AddPlayerPacket(); - $pk->uuid = $this->uuid; - $pk->username = $this->getRealName(); - $pk->entityRuntimeId = $this->getId(); - $pk->position = $this->location->asVector3(); - $pk->motion = null; - $pk->yaw = $this->location->yaw; - $pk->pitch = $this->location->pitch; - $pk->item = $this->item; - $pk->metadata = $this->getSyncedNetworkData(false); - $player->sendDataPacket($pk); - - $this->sendData($player, [Entity::DATA_NAMETAG => [Entity::DATA_TYPE_STRING, $this->getRealName()]]); - - $pk = new PlayerListPacket(); - $pk->entries = [PlayerListEntry::createRemovalEntry($this->uuid)]; - $pk->type = PlayerListPacket::TYPE_REMOVE; - $player->sendDataPacket($pk); - - $this->hasSpawned[] = $player; - - if($this->offHandItem->getId() !== 0){ - $pk = new MobEquipmentPacket(); - $pk->windowId = ContainerIds::OFFHAND; - $pk->entityRuntimeId = $this->getId(); - $pk->inventorySlot = $pk->hotbarSlot = 0; - $pk->item = $this->offHandItem; - $this->server->broadcastPacket($this->hasSpawned, $pk); - } - } - - public function despawnTo(Player $player) : void{ - parent::despawnTo($player); - $pk = new PlayerListPacket(); - $pk->entries = [PlayerListEntry::createAdditionEntry($this->uuid, $this->id, $this->getName(), SkinAdapterSingleton::get()->toSkinData($this->skin))]; - $pk->type = PlayerListPacket::TYPE_REMOVE; - $player->sendDataPacket($pk); - } - - public static function nbtDeserialize(CompoundTag $nbt) : NPCHuman{ - [$x, $y, $z, $world] = explode(":", $nbt->getString("pos")); - return new NPCHuman(new Location((float) $x, (float) $y, (float) $z, 0.0, 0.0, Server::getInstance()->getLevelByName($world)), $nbt); - } - - public function nbtSerialize() : CompoundTag{ - $nbt = parent::nbtSerialize(); - $nbt->setInt("type", self::NETWORK_ID); - - $nbt->setString("command", $this->command); - $nbt->setString("message", $this->message); - - $nbt->setTag(NPCPlugin::getInstance()->getSkinCompound($this->skin)); - $nbt->setByte("isCustomSkin", $this->isCustomSkin ? 1 : 0); - $nbt->setTag($this->item->nbtSerialize(-1, "item")); - $nbt->setTag($this->offHandItem->nbtSerialize(-1, "offHand")); - return $nbt; - } - - /** - * @param Vector3 $target - * - * @see Living::lookAt() - */ - public function lookAt(Vector3 $target){ - $horizontal = sqrt(($target->x - $this->location->x) ** 2 + ($target->z - $this->location->z) ** 2); - $vertical = $target->y - $this->location->y; - $this->location->pitch = -atan2($vertical, $horizontal) / M_PI * 180; //negative is up, positive is down - - $xDist = $target->x - $this->location->x; - $zDist = $target->z - $this->location->z; - $this->location->yaw = atan2($zDist, $xDist) / M_PI * 180 - 90; - if($this->location->yaw < 0){ - $this->location->yaw += 360.0; - } - - $pk = new MovePlayerPacket(); - $pk->position = $this->location->add(0, 1.62); - $pk->yaw = $this->location->yaw; - $pk->pitch = $this->location->pitch; - $pk->entityRuntimeId = $this->id; - $pk->headYaw = $this->location->yaw; - - foreach($this->getViewers() as $player){ - $player->sendDataPacket($pk); - } - } - - public function getItem() : Item{ - return $this->item; - } - - public function setItem(?Item $item, bool $offHand = false){ - if($item === null){ - $item = ItemFactory::get(0); - } - - if($offHand) - $this->offHandItem = $item;else - $this->item = $item; - } -} \ No newline at end of file diff --git a/src/alvin0319/NPC/lang/PluginLang.php b/src/alvin0319/NPC/lang/PluginLang.php deleted file mode 100644 index 4f7fda6..0000000 --- a/src/alvin0319/NPC/lang/PluginLang.php +++ /dev/null @@ -1,80 +0,0 @@ -plugin = $plugin; - - $this->lang = $plugin->getConfig()->getNested("lang", "eng"); - - $plugin->saveResource($this->lang . ".yml"); - - $this->data = yaml_parse(file_get_contents($plugin->getDataFolder() . $this->lang . ".yml")); - - if(!is_array($this->data)){ - throw new InvalidLanguageException("Language name with " . $this->lang . "is not found."); - } - - self::$prefix = $this->data["plugin.prefix"]; - } - - public function saveNewLang(){ - unlink($this->plugin->getDataFolder() . $this->lang . ".yml"); - $this->plugin->saveResource($this->lang . ".yml"); - } - - /** - * @param string $str - * @param array $params - * - * @return string - */ - public function translateLanguage(string $str, array $params = []) : string{ - $string = $this->data[$str]; - foreach($params as $i => $param){ - $string = str_replace("{%" . $i . "}", $param, $this->data[$str]); - } - - return $string; - } - - /** - * @param string $str - * - * @return string - */ - public function getRealMessage(string $str) : string{ - return $this->data[$str]; - } -} \ No newline at end of file diff --git a/src/alvin0319/NPC/task/CheckVersionAsyncTask.php b/src/alvin0319/NPC/task/CheckVersionAsyncTask.php deleted file mode 100644 index 274e3fc..0000000 --- a/src/alvin0319/NPC/task/CheckVersionAsyncTask.php +++ /dev/null @@ -1,49 +0,0 @@ -storeLocal($promise); - } - - public function onRun(){ - $url = Internet::getURL("https://raw.githubusercontent.com/alvin0319/NPC/stable/updates.json"); - - if(is_bool($url)){ - $this->setResult(null); - }else{ - $data = json_decode($url, true); - - if($data !== null){ - $lastVersion = $data["version"]; - $lastMessage = $data["updates"] [$lastVersion] ["message"]; - $mustUpdate = $data["updates"] [$lastVersion] ["mustUpdate"]; - - $this->setResult(["version" => $lastVersion, "message" => $lastMessage, "update" => $mustUpdate]); - }else{ - $this->setResult(null); - } - } - } - - public function onCompletion(Server $server){ - /** @var Promise $promise */ - $promise = $this->fetchLocal(); - if($this->getResult() === null){ - $promise->reject("Update check failed: Failed to connect Github server."); - }else{ - $promise->resolve($this->getResult()); - } - } -} \ No newline at end of file diff --git a/src/alvin0319/NPC/task/SkinFetchAsyncTask.php b/src/alvin0319/NPC/task/SkinFetchAsyncTask.php new file mode 100644 index 0000000..e15602f --- /dev/null +++ b/src/alvin0319/NPC/task/SkinFetchAsyncTask.php @@ -0,0 +1,54 @@ +path = $path; + $this->skinId = $skinId; + $this->geometryName = $geometryName; + $this->geometryData = $geometryData; + $this->storeLocal($promise); + } + + public function onRun() : void{ + $img = imagecreatefrompng($this->path); + $bytes = ''; + for($y = 0; $y < imagesy($img); $y++){ + for($x = 0; $x < imagesx($img); $x++){ + $rgba = @imagecolorat($img, $x, $y); + $a = ((~((int) ($rgba >> 24))) << 1) & 0xff; + $r = ($rgba >> 16) & 0xff; + $g = ($rgba >> 8) & 0xff; + $b = $rgba & 0xff; + $bytes .= chr($r) . chr($g) . chr($b) . chr($a); + } + } + @imagedestroy($img); + $skin = new Skin($this->skinId, $bytes, "", $this->geometryName, $this->geometryData); + $this->setResult($skin); + } + + public function onCompletion(Server $server) : void{ + /** @var Promise $promise */ + $promise = $this->fetchLocal(); + $promise->resolve($this->getResult()); + } +} \ No newline at end of file diff --git a/src/alvin0319/NPC/util/ExtensionNotLoadedException.php b/src/alvin0319/NPC/util/ExtensionNotLoadedException.php deleted file mode 100644 index 7a0c8e7..0000000 --- a/src/alvin0319/NPC/util/ExtensionNotLoadedException.php +++ /dev/null @@ -1,7 +0,0 @@ -skinBytes = $skinBytes; - $this->geometryName = $geometryName; - $this->geometryData = $geometryData; - } - - public function getSkinBytes() : string{ - return $this->skinBytes; - } - - public function getGeometryName() : string{ - return $this->geometryName; - } - - public function getGeometryData() : string{ - return $this->geometryData; - } - - public function toSkin(Player $player) : Skin{ - return new Skin($player->getSkin()->getSkinId(), $this->skinBytes, '', $this->geometryName, $this->geometryData); - } - - public function toSkinData(Player $player) : SkinData{ - $skin = new Skin($player->getSkin()->getSkinId(), $this->skinBytes, '', $this->geometryName, $this->geometryData); - - return SkinAdapterSingleton::get()->toSkinData($skin); - } -} \ No newline at end of file diff --git a/src/alvin0319/NPC/util/InvalidLanguageException.php b/src/alvin0319/NPC/util/InvalidLanguageException.php deleted file mode 100644 index 7f38ec4..0000000 --- a/src/alvin0319/NPC/util/InvalidLanguageException.php +++ /dev/null @@ -1,7 +0,0 @@ -now === self::FULFILLED){ $callback($this->value); @@ -67,4 +60,4 @@ public function setNow(string $now, $value) : Promise{ $this->fulfilled = $this->rejected = []; return $this; } -} +} \ No newline at end of file