PocketMine's Tomorrow's World Generator
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Main.php 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. <?php
  2. /*
  3. * Main from BetterGen
  4. * Copyright(C) Ad5001 2017
  5. * Licensed under the BoxOfDevs Public General LICENSE which can be found in the file LICENSE in the root directory
  6. * @author ad5001
  7. */
  8. namespace Ad5001\BetterGen;
  9. use pocketmine\plugin\PluginBase;
  10. use pocketmine\level\generator\biome\Biome;
  11. use pocketmine\level\generator\Generator;
  12. use pocketmine\level\generator\normal\Normal;
  13. use pocketmine\event\level\ChunkPopulateEvent;
  14. use Ad5001\BetterGen\generator\BetterNormal;
  15. use Ad5001\BetterGen\biome\BetterForest;
  16. use Ad5001\BetterGen\loot\LootTable;
  17. use pocketmine\utils\Config;
  18. use pocketmine\block\Block;
  19. use pocketmine\tile\Chest;
  20. use pocketmine\nbt\NBT;
  21. use pocketmine\nbt\tag\CompoundTag;
  22. use pocketmine\nbt\tag\ListTag;
  23. use pocketmine\nbt\tag\StringTag;
  24. use pocketmine\nbt\tag\IntTag;
  25. use pocketmine\tile\Tile;
  26. use pocketmine\item\Item;
  27. use pocketmine\event\player\PlayerInteractEvent;
  28. use pocketmine\event\block\BlockBreakEvent;
  29. class Main extends PluginBase implements \pocketmine\event\Listener {
  30. const PREFIX = "§l§o§b[§r§l§2Better§aGen§o§b]§r§f ";
  31. const SAKURA_FOREST = 100; // Letting some place for future biomes.
  32. /*
  33. * Called when the plugin enables
  34. */
  35. public function onEnable() {
  36. $this->getServer()->getPluginManager()->registerEvents($this, $this);
  37. Generator::addGenerator(BetterNormal::class, "betternormal");
  38. if($this->isOtherNS()) $this->getLogger()->warning("Tesseract detected. Note that some parts of the generator could not work properly");
  39. @mkdir($this->getDataFolder());
  40. if(! file_exists(LootTable::getPluginFolder(). "processingLoots.json"))
  41. file_put_contents(LootTable::getPluginFolder(). "processingLoots.json", "{}");
  42. }
  43. /*
  44. * Called when the plugin disables
  45. */
  46. public function onDisable() {
  47. }
  48. /*
  49. * Called when one of the defined commands of the plugin has been called
  50. * @param $sender \pocketmine\command\CommandSender
  51. * @param $cmd \pocketmine\command\Command
  52. * @param $label mixed
  53. * @param $args array
  54. * return bool
  55. */
  56. public function onCommand(\pocketmine\command\CommandSender $sender, \pocketmine\command\Command $cmd, $label, array $args): bool {
  57. switch($cmd->getName()) {
  58. case "createworld" : // /createworld <name> [generator = betternormal] [seed = rand()] [options(json)]
  59. switch(count($args)) {
  60. case 0 :
  61. return false;
  62. break;
  63. case 1 : // /createworld <name>
  64. $name = $args [0];
  65. $generator = Generator::getGenerator("betternormal");
  66. $generatorName = "betternormal";
  67. $seed = $this->generateRandomSeed();
  68. $options = [ ];
  69. break;
  70. case 2 : // /createworld <name> [generator = betternormal]
  71. $name = $args [0];
  72. $generator = Generator::getGenerator($args [1]);
  73. if(Generator::getGeneratorName($generator) !== strtolower($args [1])) {
  74. $sender->sendMessage(self::PREFIX . "§4Could not find generator {$args[1]}. Are you sure it is registered?");
  75. return true;
  76. }
  77. $generatorName = strtolower($args [1]);
  78. $seed = $this->generateRandomSeed();
  79. $options = [ ];
  80. break;
  81. case 3 : // /createworld <name> [generator = betternormal] [seed = rand()]
  82. $name = $args [0];
  83. $generator = Generator::getGenerator($args [1]);
  84. if(Generator::getGeneratorName($generator) !== strtolower($args [1])) {
  85. $sender->sendMessage(self::PREFIX . "§4Could not find generator {$args[1]}. Are you sure it is registered?");
  86. return true;
  87. }
  88. $generatorName = strtolower($args [1]);
  89. if(preg_match("[^\d]", $args [2]) !== false) {
  90. $parts = str_split($args [2]);
  91. foreach($parts as $key => $str) {
  92. $parts [$key] = ord($str);
  93. }
  94. $seed = implode("", $parts);
  95. } else {
  96. $seed = $args [2];
  97. }
  98. $options = [ ];
  99. break;
  100. default : // /createworld <name> [generator = betternormal] [seed = rand()] [options(json)]
  101. $name = $args [0];
  102. $generator = Generator::getGenerator($args [1]);
  103. if(Generator::getGeneratorName($generator) !== strtolower($args [1])) {
  104. $sender->sendMessage(self::PREFIX . "§4Could not find generator {$args[1]}. Are you sure it is registered?");
  105. return true;
  106. }
  107. $generatorName = strtolower($args [1]);
  108. if(preg_match("[^\d]", $args [2]) !== false) {
  109. $parts = str_split($args [2]);
  110. foreach($parts as $key => $str) {
  111. $parts [$key] = ord($str);
  112. }
  113. $seed = implode("", $parts);
  114. } else {
  115. $seed = $args [2];
  116. }
  117. unset($args [0], $args [1], $args [2]);
  118. $options = json_decode($args [3], true);
  119. if(! is_array($json)) {
  120. $sender->sendMessage(Main::PREFIX . "§4Invalid JSON for options.");
  121. return true;
  122. }
  123. break;
  124. }
  125. $this->getServer()->broadcastMessage(Main::PREFIX . "§aGenerating level $name with generator $generatorName and seed $seed..");
  126. $this->getServer()->generateLevel($name, $seed, $generator, $options);
  127. $this->getServer()->loadLevel($name);
  128. return true;
  129. break;
  130. }
  131. }
  132. /*
  133. * Registers a forest type.
  134. * @param $name string
  135. * @param $treeClass string
  136. * @params $infos Array(temperature, rainfall)
  137. * @return bool
  138. */
  139. public function registerForest(string $name, string $treeClass, array $infos): bool {
  140. if(! @class_exists($treeClass))
  141. return false;
  142. if(! @is_subclass_of($treeClass, "pocketmine\\level\\generator\\normal\\object\\Tree"))
  143. return false;
  144. if(count($infos) < 2 or ! is_float($infos [0]) or ! is_float($infos [1]))
  145. return false;
  146. return BetterForest::registerForest($name, $treeClass, $infos);
  147. }
  148. /*
  149. * Registers a biome for the normal generator. Normal means(Biome::register) doesn't allow biome to be generated
  150. * @param $id int
  151. * @param $biome Biome
  152. * @return void
  153. */
  154. public static function registerBiome(int $id, Biome $biome) {
  155. $reflection = new \ReflectionClass('pocketmine\\level\\generator\\biome\\Biome');
  156. $register = $reflection->getMethod('register');
  157. $register->setAccessible(true);
  158. $register->invoke(null, $id, $biome);
  159. BetterNormal::registerBiome($biome);
  160. }
  161. /*
  162. * Generates a(semi) random seed.
  163. * @return int
  164. */
  165. public function generateRandomSeed(): int {
  166. return(int) round(time() * rand(0, time()) / memory_get_usage());
  167. }
  168. // Listener
  169. /*
  170. * Checks after a chunk populates so we an add tiles and loot tables
  171. * @param $event pocketmine\event\level\ChunkPopulateEvent
  172. * @return int
  173. */
  174. public function onChunkPopulate(ChunkPopulateEvent $event) {
  175. $cfg = new Config(LootTable::getPluginFolder() . "processingLoots.json", Config::JSON);
  176. foreach($cfg->getAll() as $key => $value) {
  177. list($x, $y, $z) = explode(";", $key);
  178. if($value["saveAs"] == "chest" && $event->getLevel()->getBlockIdAt($x, $y, $z) == Block::AIR ){
  179. $event->getLevel()->setBlockIdAt($x, $y, $z, Block::CHEST);
  180. } else {
  181. $cfg->remove($key);
  182. $cfg->save();
  183. }
  184. }
  185. }
  186. /*
  187. * Checks when a player interacts with a loot chest to create it.
  188. */
  189. public function onInteract(PlayerInteractEvent $event) {
  190. $cfg = new Config(LootTable::getPluginFolder() . "processingLoots.json", Config::JSON);
  191. if($event->getBlock()->getId() !== Block::CHEST) return;
  192. if(!$cfg->exists($event->getBlock()->getX() . ";" . $event->getBlock()->getY() . ";" . $event->getBlock()->getZ())) return;
  193. echo "Doing {$event->getBlock()}";
  194. $chest = new \pocketmine\block\Chest(0);
  195. $nbt = new CompoundTag("", [
  196. new ListTag("Items", []),
  197. new StringTag("id", Tile::CHEST),
  198. new IntTag("x", $event->getBlock()->x),
  199. new IntTag("y", $event->getBlock()->y),
  200. new IntTag("z", $event->getBlock()->z)
  201. ]);
  202. $chest->setLevel($event->getBlock()->getLevel());
  203. $cItem = Item::get(Item::CHEST, 0);
  204. $cItem->setCustomName("§k(Fake)§r Minecart chest");
  205. $chest->place($cItem, $event->getBlock()->getLevel()->getBlock($event->getBlock()), $chest, 0, 0, 0, 0);
  206. $inv = $event->getBlock()->getLevel()->getTile($event->getBlock());
  207. LootTable::fillChest($inv->getInventory(), $event->getBlock());
  208. }
  209. /*
  210. * Checks when a player breaks a loot chest which is not created to create it
  211. */
  212. public function onBlockBreak(BlockBreakEvent $event) {
  213. $cfg = new Config(LootTable::getPluginFolder() . "processingLoots.json", Config::JSON);
  214. if($event->getBlock()->getId() !== Block::CHEST) return;
  215. if(!$cfg->exists($event->getBlock()->getX() . ";" . $event->getBlock()->getY() . ";" . $event->getBlock()->getZ())) return;
  216. echo "Doing {$event->getBlock()}";
  217. $chest = new \pocketmine\block\Chest(0);
  218. $nbt = new CompoundTag("", [
  219. new ListTag("Items", []),
  220. new StringTag("id", Tile::CHEST),
  221. new IntTag("x", $event->getBlock()->x),
  222. new IntTag("y", $event->getBlock()->y),
  223. new IntTag("z", $event->getBlock()->z)
  224. ]);
  225. $chest->setLevel($event->getBlock()->getLevel());
  226. $cItem = Item::get(Item::CHEST, 0);
  227. $cItem->setCustomName("§k(Fake)§r Minecart chest");
  228. $chest->place($cItem, $event->getBlock()->getLevel()->getBlock($event->getBlock()), $chest, 0, 0, 0, 0);
  229. $inv = $event->getBlock()->getLevel()->getTile($event->getBlock());
  230. LootTable::fillChest($inv->getInventory(), $event->getBlock());
  231. $event->setCancelled();
  232. }
  233. /*
  234. * Check if it's a Tesseract like namespace
  235. * @return bool
  236. */
  237. public static function isOtherNS() {
  238. try {
  239. return @class_exists("pocketmine\\level\\generator\\normal\\object\\OakTree");
  240. } catch(\Exception $e) {
  241. return false;
  242. }
  243. }
  244. }