Finish loottable generation & chest generation
This commit is contained in:
parent
58b4870fee
commit
1f10807c7b
4 changed files with 188 additions and 140 deletions
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue