diff --git a/src/Ad5001/BetterGen/Main.php b/src/Ad5001/BetterGen/Main.php index e3ed7ff..92d0e68 100644 --- a/src/Ad5001/BetterGen/Main.php +++ b/src/Ad5001/BetterGen/Main.php @@ -23,23 +23,23 @@ use Ad5001\BetterGen\structure\SakuraTree; use Ad5001\BetterGen\structure\Temple; use Ad5001\BetterGen\structure\Well; use pocketmine\block\Block; +use pocketmine\block\Chest; use pocketmine\command\Command; use pocketmine\command\CommandSender; use pocketmine\event\block\BlockBreakEvent; use pocketmine\event\Listener; use pocketmine\event\player\PlayerInteractEvent; +use pocketmine\item\Item; use pocketmine\level\generator\biome\Biome; use pocketmine\level\generator\Generator; use pocketmine\level\generator\object\OakTree; use pocketmine\level\Position; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\IntTag; -use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\StringTag; use pocketmine\Player; use pocketmine\plugin\PluginBase; use pocketmine\tile\Chest as TileChest; -use pocketmine\block\Chest; use pocketmine\tile\Tile; use pocketmine\utils\Config; use pocketmine\utils\Random; @@ -48,6 +48,7 @@ use pocketmine\utils\TextFormat; class Main extends PluginBase implements Listener { const PREFIX = "§l§o§b[§r§l§2Better§aGen§o§b]§r§f "; const SAKURA_FOREST = 100; // Letting some place for future biomes. + private static $instance; /** @@ -60,21 +61,39 @@ class Main extends PluginBase implements Listener { BetterNormal::registerBiome($biome); } + /** + * Places a looting chest block and creates the corresponding tile + * @param Block $block + * @param $lootfile + */ + static public function placeLootChest(Block $block, $lootfile) { + $block->getLevel()->setBlock($block, $block, true); + $nbt = new CompoundTag("", [ + new StringTag("id", Tile::CHEST), + new IntTag("x", (int)$block->x), + new IntTag("y", (int)$block->y), + new IntTag("z", (int)$block->z), + new StringTag("generateLoot", $lootfile) + ]); + $tile = new TileChest($block->getLevel(), $nbt); + $tile->spawnToAll(); + } + /** * Called when the plugin enables */ public function onEnable() { + self::$instance = $this; $this->getServer()->getPluginManager()->registerEvents($this, $this); Generator::addGenerator(BetterNormal::class, "betternormal"); if ($this->isOtherNS()) $this->getLogger()->warning("Tesseract detected. Note that Tesseract is not up to date with the generation structure and some generation features may be limited or not working"); @mkdir($this->getDataFolder()); - if (!file_exists(LootTable::getPluginFolder() . "processingLoots.json")) - file_put_contents(LootTable::getPluginFolder() . "processingLoots.json", "{}"); + if (!in_array($this->getDataFolder() . 'resources\mcpe-default-addon\.', $this->getResources())) $this->getLogger()->alert('The loot files are missing! Make sure you got all files / did git clone --recursive'); } /** * Check if it's a Tesseract like namespace - * @return bool + * @return bool */ public static function isOtherNS() { try { @@ -84,14 +103,12 @@ class Main extends PluginBase implements Listener { } } - /** * Called when the plugin disables */ public function onDisable() { } - /** * Called when one of the defined commands of the plugin has been called * @param $sender \pocketmine\command\CommandSender @@ -261,8 +278,9 @@ class Main extends PluginBase implements Listener { * Registers a forest type. * @param $name string * @param $treeClass string - * @params $infos Array(temperature, rainfall) + * @param array $infos * @return bool + * @params $infos Array(temperature, rainfall) */ public function registerForest(string $name, string $treeClass, array $infos): bool { if (!@class_exists($treeClass)) @@ -274,16 +292,54 @@ class Main extends PluginBase implements Listener { return BetterForest::registerForest($name, $treeClass, $infos); } - /** * Checks when a player attempts to open a loot chest which is not created yet * @param PlayerInteractEvent $event */ public function onInteract(PlayerInteractEvent $event) { - if (($block = $event->getBlock())->getId() !== Block::CHEST) return; + if (($block = $event->getBlock())->getId() !== Block::CHEST || $event->getAction() !== PlayerInteractEvent::RIGHT_CLICK_BLOCK) return; $this->generateLootChest($block); } + /** + * Fills a chest with loot + * @param Block $block + * @param Random|null $random + */ + static public function generateLootChest(Block $block, Random $random = null) { + if (!$block instanceof Chest) return; + $tile = $block->getLevel()->getTile($block); + if (is_null($tile)) { + //TODO new tile, but no loot, because we don't know which type of loot chest this is + $nbt = new CompoundTag("", [ + new StringTag("id", Tile::CHEST), + new IntTag("x", (int)$block->x), + new IntTag("y", (int)$block->y), + new IntTag("z", (int)$block->z) + ]); + $tile = new TileChest($block->getLevel(), $nbt); + $tile->spawnToAll(); + return; + } + if (!$tile instanceof TileChest) return; + //Check if lootchest (or already generated loot) + if (!isset($tile->namedtag->generateLoot)) return; + $table = new LootTable($config = new Config(self::getInstance()->getDataFolder() . '\\resources\\mcpe-default-addon\\' . $tile->namedtag->generateLoot . '.json')); + $size = $tile->getInventory()->getSize(); + $loot = $table->getRandomLoot($random); + $items = array_pad($loot, $size, Item::get(0)); + shuffle($items); + $tile->getInventory()->setContents($items); + unset($tile->namedtag->generateLoot); + } + + /** + * @return Main + */ + static public function getInstance() { + return self::$instance; + } + /** * Checks when a player breaks a loot chest which is not created yet * @param BlockBreakEvent $event @@ -292,16 +348,4 @@ class Main extends PluginBase implements Listener { if (($block = $event->getBlock())->getId() !== Block::CHEST) return; $this->generateLootChest($block); } - - private function generateLootChest(Block $block) { - //TODO - if (!$block instanceof Chest) return; - if (is_null($block->getLevel()->getTile($block))) { - //TODO new tile, but no loot, because we don't know which type of loot it is - return; - } - if (!($tile = $block->getLevel()->getTile($block)) instanceof TileChest) return; - /** TileChest $tile */ - $tile->getInventory()->setContents([]);//TODO - } } diff --git a/src/Ad5001/BetterGen/loot/LootTable.php b/src/Ad5001/BetterGen/loot/LootTable.php index c613ebd..51bcfbd 100644 --- a/src/Ad5001/BetterGen/loot/LootTable.php +++ b/src/Ad5001/BetterGen/loot/LootTable.php @@ -14,9 +14,9 @@ namespace Ad5001\BetterGen\loot; +use Ad5001\BetterGen\Main; use pocketmine\item\Item; use pocketmine\item\Tool; -use pocketmine\Server; use pocketmine\utils\Config; use pocketmine\utils\Random; @@ -36,114 +36,105 @@ class LootTable { } /** - * Public function to generate loot. A {@link: \pocketmine\utils\Random} can be passed. - * @param Random|null $random - * @return Item[] - */ - public function createLoot(Random $random = null) { - return self::getRandomLoot($random); - } - - /** - * Internal function. Serves as actual file reader + sub-table loader + * Public function to generate loot. A {@link: \pocketmine\utils\Random} can be passed. Serves as file reader + sub-table loader * Do _NOT_ use this in the source, use LootTable::createLoot instead * @param Random|null $random * @return Item[] */ - private function getRandomLoot(Random $random = null) { - if (is_null($random)) $random = new Random(microtime()); - $array = []; + public function getRandomLoot(Random $random = null) { + if (is_null($random)) $random = new Random(); $items = []; foreach ($this->lootFile->get("pools") as $rolls) { - $maxrolls = $rolls["rolls"];//TODO: $rolls["conditions"] + if (isset($rolls["rolls"]["min"]) && isset($rolls["rolls"]["max"])) $maxrolls = $random->nextRange($rolls["rolls"]["min"], $rolls["rolls"]["max"]); + else $maxrolls = $rolls["rolls"];//TODO: $rolls["conditions"] //Example: looting swords while ($maxrolls > 0) { + $array = []; $maxrolls--; foreach ($rolls["entries"] as $index => $entries) { $array[] = $entries["weight"]??1; } - } - $val = $rolls["entries"][$this->getRandomWeightedElement($array)]; - //typecheck - if ($val["type"] == "loot_table") { - $loottable = new self(new Config(Server::getInstance()->getFilePath() . "src/pocketmine/resources/" . $val["name"] . ".json", Config::JSON, [])); - $items = array_merge($items, $loottable->getRandomLoot()); - unset($loottable); - } elseif ($val["type"] == "item") { - print $val["name"] . PHP_EOL; - //name fix - $val["name"] = self::fixItemName($val["name"]); - $item = Item::fromString($val["name"]); - if (isset($val["functions"])) { - foreach ($val["functions"] as $function) { - switch ($functionname = $function["function"]) { - case "set_damage": { - if ($item instanceof Tool) $item->setDamage(mt_rand($function["damage"]["min"] * $item->getMaxDurability(), $function["damage"]["max"] * $item->getMaxDurability())); - else $item->setDamage($random->nextRange($function["damage"]["min"], $function["damage"]["max"])); - } - break; - case "set_data": { - //fish fix, blame mojang - if ($item->getId() == Item::RAW_FISH) { - switch ($function["data"]) { - case 1: - $item = Item::get(Item::RAW_SALMON, $item->getDamage(), $item->getCount(), $item->getCompoundTag()); - break; - case 2: - $item = Item::get(Item::CLOWN_FISH, $item->getDamage(), $item->getCount(), $item->getCompoundTag()); - break; - case 3: - $item = Item::get(Item::PUFFER_FISH, $item->getDamage(), $item->getCount(), $item->getCompoundTag()); - break; - default: - break; + $val = $rolls["entries"][$this->getRandomWeightedElement($array)]; + //typecheck + if ($val["type"] == "loot_table") { + $loottable = new LootTable(new Config(Main::getInstance()->getDataFolder() . '\\resources\\mcpe-default-addon\\' . $val["name"] . ".json")); + $items = array_merge($items, $loottable->getRandomLoot($random)); + unset($loottable); + } elseif ($val["type"] == "item") { + //name fix + $val["name"] = self::fixItemName($val["name"]); + $item = Item::fromString($val["name"]); + if (isset($val["functions"])) { + foreach ($val["functions"] as $function) { + switch ($functionname = $function["function"]) { + case "set_damage": { + if ($item instanceof Tool) $item->setDamage($random->nextRange($function["damage"]["min"] * $item->getMaxDurability(), $function["damage"]["max"] * $item->getMaxDurability())); + else $item->setDamage($random->nextRange($function["damage"]["min"], $function["damage"]["max"])); + } + break; + case "set_data": { + //fish fix, blame mojang + if ($item->getId() == Item::RAW_FISH) { + switch ($function["data"]) { + case 1: + $item = Item::get(Item::RAW_SALMON, $item->getDamage(), $item->getCount(), $item->getCompoundTag()); + break; + case 2: + $item = Item::get(Item::CLOWN_FISH, $item->getDamage(), $item->getCount(), $item->getCompoundTag()); + break; + case 3: + $item = Item::get(Item::PUFFER_FISH, $item->getDamage(), $item->getCount(), $item->getCompoundTag()); + break; + default: + break; + } + } else $item->setDamage($function["data"]); + } + break; + case "set_count": { + $item->setCount($random->nextRange($function["count"]["min"], $function["count"]["max"])); + } + break; + case "furnace_smelt": { + /* TODO + Mostly bound to conditions (burning) + "conditions": [ + { + "condition": "entity_properties", + "entity": "this", + "properties": { + "on_fire": true + } } - } else $item->setDamage($function["data"]); + ] + */ + } + break; + case "enchant_randomly": { + //TODO + } + break; + case "enchant_with_levels": { + //TODO + } + break; + case "looting_enchant": { + //TODO + } + break; + default: + assert("Unknown looting table function $functionname, skipping"); } - break; - case "set_count": { - $item->setCount($random->nextRange($function["count"]["min"], $function["count"]["max"])); - } - break; - case "furnace_smelt": { - /* TODO - Mostly bound to conditions (burning) - "conditions": [ - { - "condition": "entity_properties", - "entity": "this", - "properties": { - "on_fire": true - } - } - ] - */ - } - break; - case "enchant_randomly": { - //TODO - } - break; - case "enchant_with_levels": { - //TODO - } - break; - case "looting_enchant": { - //TODO - } - break; - default: - assert("Unknown looting table function $functionname, skipping"); } } + $items[] = $item; } - $items[] = $item; } } return $items; } /** - * TODO: Make random actually useful here. + * TODO: Make Random::class actually useful here. * @param array $weightedValues * @return mixed */ @@ -161,7 +152,19 @@ class LootTable { * @return mixed */ private static function fixItemName($name) { - //TODO add a switch-case here + switch ($name) { + case 'minecraft:horsearmoriron': + $name = 'minecraft:iron_horse_armor'; + break; + case 'minecraft:horsearmorgold': + $name = 'minecraft:gold_horse_armor'; + break; + case 'minecraft:horsearmordiamond': + $name = 'minecraft:diamond_horse_armor'; + break; + default: { + } + } return $name; } } \ No newline at end of file diff --git a/src/Ad5001/BetterGen/structure/Igloo.php b/src/Ad5001/BetterGen/structure/Igloo.php index dd00abf..268cbde 100644 --- a/src/Ad5001/BetterGen/structure/Igloo.php +++ b/src/Ad5001/BetterGen/structure/Igloo.php @@ -35,11 +35,11 @@ class Igloo extends Object { /** * Places an igloo - * @param $level pocketmine\level\ChunkManager - * @param $x int - * @param $y int - * @param $z int - * @param $random pocketmine\utils\Random + * @param ChunkManager $level + * @param $x + * @param $y + * @param $z + * @param Random $random * @return bool placed */ public function placeObject(ChunkManager $level, $x, $y, $z, Random $random) { @@ -347,11 +347,11 @@ class Igloo extends Object { /** * Checks if an igloo is placeable - * @param $level pocketmine\level\ChunkManager - * @param $x int - * @param $y int - * @param $z int - * @param $random pocketmine\utils\Random + * @param ChunkManager $level + * @param $x + * @param $y + * @param $z + * @param Random $random * @return bool */ public function canPlaceObject(ChunkManager $level, $x, $y, $z, Random $random) { diff --git a/src/Ad5001/BetterGen/structure/Temple.php b/src/Ad5001/BetterGen/structure/Temple.php index 18859bc..79ea60f 100644 --- a/src/Ad5001/BetterGen/structure/Temple.php +++ b/src/Ad5001/BetterGen/structure/Temple.php @@ -14,10 +14,12 @@ namespace Ad5001\BetterGen\structure; +use Ad5001\BetterGen\Main; use Ad5001\BetterGen\utils\BuildingUtils; use pocketmine\block\Block; use pocketmine\level\ChunkManager; use pocketmine\level\generator\object\Object; +use pocketmine\level\Position; use pocketmine\math\Vector3; use pocketmine\utils\Random; @@ -113,14 +115,13 @@ class Temple extends Object { /** * Checks if a temple is placeable - * @param $level pocketmine\level\ChunkManager - * @param $x int - * @param $y int - * @param $z int - * @param $random pocketmine\utils\Random + * @param ChunkManager $level + * @param $x + * @param $y + * @param $z + * @param Random $random * @return bool */ - public function canPlaceObject(ChunkManager $level, $x, $y, $z, Random $random) { $this->level = $level; $this->direction = $random->nextBoundedInt(4); @@ -134,11 +135,11 @@ class Temple extends Object { /** * Places a temple - * @param $level pocketmine\level\ChunkManager - * @param $x int - * @param $y int - * @param $z int - * @param $random pocketmine\utils\Random + * @param ChunkManager $level + * @param $x + * @param $y + * @param $z + * @param Random $random */ public function placeObject(ChunkManager $level, $x, $y, $z, Random $random) { // Clearing space... @@ -216,20 +217,19 @@ class Temple extends Object { $this->placeBlock($xx, $y - 13, $zz, Block::TNT); $this->placeBlock($x, $y - 11, $z, Block::STONE_PRESSURE_PLATE); - //TODO TILES - $this->placeBlock($x, $y - 11, $z + 2, Block::CHEST, 4); - $this->placeBlock($x, $y - 11, $z - 2, Block::CHEST, 2); - $this->placeBlock($x + 2, $y - 11, $z, Block::CHEST, 5); - $this->placeBlock($x - 2, $y - 11, $z, Block::CHEST, 3); $this->placeBlock($x, $y - 10, $z + 2, Block::AIR); $this->placeBlock($x, $y - 10, $z - 2, Block::AIR); $this->placeBlock($x + 2, $y - 10, $z, Block::AIR); $this->placeBlock($x - 2, $y - 10, $z, Block::AIR); // Chests - /*LootTable::buildLootTable(new Vector3($x, $y - 11, $z + 2), LootTable::LOOT_DESERT_TEMPLE, $random);//TODO: Improve using addon - LootTable::buildLootTable(new Vector3($x, $y - 11, $z - 2), LootTable::LOOT_DESERT_TEMPLE, $random); - LootTable::buildLootTable(new Vector3($x + 2, $y - 11, $z), LootTable::LOOT_DESERT_TEMPLE, $random); - LootTable::buildLootTable(new Vector3($x - 2, $y - 11, $z), LootTable::LOOT_DESERT_TEMPLE, $random);*/ + #$this->placeBlock($x, $y - 11, $z + 2, Block::CHEST, 4); + #$this->placeBlock($x, $y - 11, $z - 2, Block::CHEST, 2); + #$this->placeBlock($x + 2, $y - 11, $z, Block::CHEST, 5); + #$this->placeBlock($x - 2, $y - 11, $z, Block::CHEST, 3); + Main::placeLootChest(Block::get(Block::CHEST, 2, new Position($x, $y - 11, $z + 2, $this->level)), 'loot_tables\\chests\\desert_pyramid'); + Main::placeLootChest(Block::get(Block::CHEST, 3, new Position($x, $y - 11, $z - 2, $this->level)), 'loot_tables\\chests\\desert_pyramid'); + Main::placeLootChest(Block::get(Block::CHEST, 4, new Position($x + 2, $y - 11, $z, $this->level)), 'loot_tables\\chests\\desert_pyramid'); + Main::placeLootChest(Block::get(Block::CHEST, 5, new Position($x - 2, $y - 11, $z, $this->level)), 'loot_tables\\chests\\desert_pyramid'); // Entrance is a rectangular parallelepiped switch ($this->direction) { @@ -896,6 +896,7 @@ class Temple extends Object { * @param $z int * @param $id int * @param $meta int + * @param bool $top * @return void */ protected function placeSlab($x, $y, $z, $id = 44, $meta = 1, $top = false) {