From 44401c8a2b27abb9150588ecbec4b18bff5f381c Mon Sep 17 00:00:00 2001 From: Falkirks Date: Sat, 15 Apr 2017 08:58:19 -0700 Subject: [PATCH 1/4] Start rewrite --- .gitignore | 1 + LICENSE | 2 +- plugin.yml | 4 +- src/falkirks/minereset/MineManager.php | 251 ++++++++++++++++ src/falkirks/minereset/MineReset.php | 13 + src/falkirks/minereset/mine/Mine.php | 82 ++++++ .../minereset/store/AbstractStore.php | 25 ++ src/falkirks/minereset/store/DataStore.php | 39 +++ src/falkirks/minereset/store/Reloadable.php | 7 + src/falkirks/minereset/store/Saveable.php | 14 + src/falkirks/minereset/store/YAMLStore.php | 85 ++++++ src/minereset/Mine.php | 79 ----- src/minereset/MineReset.php | 269 ------------------ src/minereset/MineResetTask.php | 95 ------- src/minereset/RegionBlocker.php | 84 ------ 15 files changed, 520 insertions(+), 530 deletions(-) create mode 100644 src/falkirks/minereset/MineManager.php create mode 100644 src/falkirks/minereset/MineReset.php create mode 100644 src/falkirks/minereset/mine/Mine.php create mode 100644 src/falkirks/minereset/store/AbstractStore.php create mode 100644 src/falkirks/minereset/store/DataStore.php create mode 100644 src/falkirks/minereset/store/Reloadable.php create mode 100644 src/falkirks/minereset/store/Saveable.php create mode 100644 src/falkirks/minereset/store/YAMLStore.php delete mode 100644 src/minereset/Mine.php delete mode 100644 src/minereset/MineReset.php delete mode 100644 src/minereset/MineResetTask.php delete mode 100644 src/minereset/RegionBlocker.php diff --git a/.gitignore b/.gitignore index b31f955..8914ed0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea out +old mines.yml .DS_Store diff --git a/LICENSE b/LICENSE index b9d2a38..f568708 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014 Falkirks +Copyright (c) 2017 Falkirks Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/plugin.yml b/plugin.yml index 08bdeda..674edee 100644 --- a/plugin.yml +++ b/plugin.yml @@ -1,6 +1,6 @@ name: MineReset -main: minereset\MineReset -version: 2.3 +main: falkirks\minereset\MineReset +version: 3.0 author: Falk api: [1.0.0, 2.0.0, 3.0.0-ALPHA1, 3.0.0-ALPHA2, 3.0.0-ALPHA3, 3.0.0-ALPHA4, 3.0.0-ALPHA5] load: POSTWORLD diff --git a/src/falkirks/minereset/MineManager.php b/src/falkirks/minereset/MineManager.php new file mode 100644 index 0000000..033d0c9 --- /dev/null +++ b/src/falkirks/minereset/MineManager.php @@ -0,0 +1,251 @@ +api = $api; + $this->store = $store; + $this->flag = $flag; + $this->warps = []; + if($this->flag < 2){ + $this->warps = $this->loadWarps(); + } + } + protected function reloadStore(){ + if($this->flag >= 2 && $this->store instanceof Reloadable){ + $this->store->reload(); + } + } + protected function saveStore($force = false){ + if(($this->flag > 0 || $force) && $this->store instanceof Saveable){ + $this->store->save(); + } + } + protected function loadWarps(): array{ + $out = []; + foreach($this->store->getIterator() as $name => $data){ + $out[$name] = $this->warpFromData($name, $data); + } + return $out; + } + /** + * WARNING + * This function is for internal use only. + */ + public function saveAll(){ + if($this->flag === 0){ + $this->store->clear(); + foreach($this->warps as $warp){ + $this->store->add($warp->getName(), $this->warpToData($warp)); + } + $this->saveStore(true); + } + } + /** + * (PHP 5 >= 5.0.0)
+ * Whether a offset exists + * @link http://php.net/manual/en/arrayaccess.offsetexists.php + * @param mixed $offset

+ * An offset to check for. + *

+ * @return boolean true on success or false on failure. + *

+ *

+ * The return value will be casted to boolean if non-boolean was returned. + */ + public function offsetExists($offset){ + $this->reloadStore(); + if(isset($this->warps[$offset]) || ($this->flag >= 2 && $this->store->exists($offset))){ + return true; + } + return false; + } + /** + * (PHP 5 >= 5.0.0)
+ * Offset to retrieve + * @link http://php.net/manual/en/arrayaccess.offsetget.php + * @param mixed $offset

+ * The offset to retrieve. + *

+ * @return mixed Can return all value types. + */ + public function offsetGet($offset){ + if($this->flag >= 2){ + $this->reloadStore(); + return $this->warpFromData($offset, $this->store->get($offset)); + } + return isset($this->warps[$offset]) ? $this->warps[$offset] : null; + } + /** + * (PHP 5 >= 5.0.0)
+ * Offset to set + * @link http://php.net/manual/en/arrayaccess.offsetset.php + * @param mixed $offset

+ * The offset to assign the value to. + *

+ * @param mixed $value

+ * The value to set. + *

+ * @return void + */ + public function offsetSet($offset, $value){ + if($value instanceof Mine && $value->getName() === $offset) { + if($this->flag < 2) { + $this->warps[$offset] = $value; + } + if ($this->flag >= 1) { + $this->store->add($offset, $this->warpToData($value)); + $this->saveStore(); + } + } + else{ + //TODO report failure + } + } + /** + * (PHP 5 >= 5.0.0)
+ * Offset to unset + * @link http://php.net/manual/en/arrayaccess.offsetunset.php + * @param mixed $offset

+ * The offset to unset. + *

+ * @return void + */ + public function offsetUnset($offset){ + if($this->flag < 2){ + unset($this->warps[$offset]); + } + if($this->flag >= 1){ + $this->store->remove($offset); + $this->saveStore(); + } + } + /** + * This method requires the key of the warp in order + * to construct a warp object + * @param $name + * @param array $array + * @return Mine + * @throws \Exception + */ + protected function warpFromData($name, array $array){ + if(isset($array["level"]) && isset($array["x"]) && isset($array["y"]) && isset($array["z"]) && isset($array["public"])){ // This is an internal warp + return new Warp($this, $name, new Destination(new WeakPosition($array["x"], $array["y"], $array["z"], $array["level"])), $array["public"], $array["metadata"] ?? []); + } + elseif(isset($array["address"]) && isset($array["port"]) && isset($array["public"])) { + return new Warp($this, $name, new Destination($array["address"], $array["port"]), $array["public"], $array["metadata"] ?? []); + } + $this->api->getLogger()->critical("A mine with the name " . TextFormat::AQUA . $name . TextFormat::RESET . " is incomplete. It will be removed automatically when your server stops."); + return null; + } + /** + * In order to pass data to a DataStore + * a key is needed. Typically one should + * use $warp->getName() + * @param Warp $warp + * @return array + */ + protected function warpToData(Warp $warp){ + $ret = []; + if($warp->getDestination()->isInternal()) { + //TODO implement yaw and pitch + $pos = $warp->getDestination()->getPosition(); + $ret = [ + "x" => $pos->getX(), + "y" => $pos->getY(), + "z" => $pos->getZ(), + "level" => ($pos instanceof WeakPosition ? $pos->getLevelName() : $pos->getLevel()->getName()), + "public" => $warp->isPublic(), + ]; + } + else{ + $ret = [ + "address" => $warp->getDestination()->getAddress(), + "port" => $warp->getDestination()->getPort(), + "public" => $warp->isPublic() + ]; + } + $ret["metadata"] = $warp->getAllMetadata(); + return $ret; + } + /** + * (PHP 5 >= 5.0.0)
+ * Retrieve an external iterator + * @link http://php.net/manual/en/iteratoraggregate.getiterator.php + * @return Traversable An instance of an object implementing Iterator or + * Traversable + */ + public function getIterator(){ + if($this->flag >= 2){ + return $this->loadWarps(); + } + return $this->warps; + } + /** + * Returns the current storage-mode + * ##### + * MEMORY_TILL_CLOSE = 0 + * Warps are loaded into memory when the server starts and are + * held there until the server closes. When the server closes + * they are converted back into YAML. This new YAML will + * replace warps.yml, this means that changes are lost and + * warps which fail to load are discarded. + * + * + * FLUSH_ON_CHANGE = 1 + * Warps are loaded into memory when the server starts. Whenever a + * warp is updated, it will be updated in the warps.yml. When the + * server closes, the warps file is NOT overwritten. + * + * NO_MEMORY_STORE = 2 + * Warps are never "stored" in memory. They are converted on demand + * between YAML and object format. Any changes made to the config + * will be available right away in the server and vice versa. + * #### + * @return int + */ + public function getFlag(): int{ + return $this->flag; + } + /** + * returns the current data store + * @return DataStore + */ + public function getStore(): DataStore{ + return $this->store; + } + /** + * Injects a new DataStore for warps + * ! This will inject your code into SimpleWarp, potentially breaking! + * @param DataStore $store + */ + public function setStore(DataStore $store){ + $this->saveAll(); + $this->store = $store; + if($this->flag < 2){ + $this->warps = $this->loadWarps(); + } + } + +} \ No newline at end of file diff --git a/src/falkirks/minereset/MineReset.php b/src/falkirks/minereset/MineReset.php new file mode 100644 index 0000000..1fe29fb --- /dev/null +++ b/src/falkirks/minereset/MineReset.php @@ -0,0 +1,13 @@ +getDataFolder()); + } + +} \ No newline at end of file diff --git a/src/falkirks/minereset/mine/Mine.php b/src/falkirks/minereset/mine/Mine.php new file mode 100644 index 0000000..da33c8a --- /dev/null +++ b/src/falkirks/minereset/mine/Mine.php @@ -0,0 +1,82 @@ +pointA = $pointA; + $this->pointB = $pointB; + $this->level = $level; + $this->data = $data; + $this->name = $name; + $this->api = $api; + } + + /** + * @return Vector3 + */ + public function getPointA(): Vector3{ + return $this->pointA; + } + + /** + * @return Vector3 + */ + public function getPointB(): Vector3{ + return $this->pointB; + } + + /** + * @return Level + */ + public function getLevel(): Level{ + return $this->level; + } + + /** + * @return array + */ + public function getData(): array{ + return $this->data; + } + + /** + * @return string + */ + public function getName(): string{ + return $this->name; + } + + /** + * @return MineReset + */ + public function getApi(): MineReset{ + return $this->api; + } + +} \ No newline at end of file diff --git a/src/falkirks/minereset/store/AbstractStore.php b/src/falkirks/minereset/store/AbstractStore.php new file mode 100644 index 0000000..4ff287f --- /dev/null +++ b/src/falkirks/minereset/store/AbstractStore.php @@ -0,0 +1,25 @@ + $mine){ + $this->add($name, $mine); + } + } + public function removeAll($mines){ + foreach($mines as $mine){ + $this->remove($mine); + } + } + public function exists($name): bool{ + return $this->get($name) !== null; + } +} \ No newline at end of file diff --git a/src/falkirks/minereset/store/DataStore.php b/src/falkirks/minereset/store/DataStore.php new file mode 100644 index 0000000..af69506 --- /dev/null +++ b/src/falkirks/minereset/store/DataStore.php @@ -0,0 +1,39 @@ +config = $config; + } + + /** + * Adds a new mine and returns the old one + * @param $name + * @param $warp + * @return bool|mixed + */ + public function add($name, $mine){ + $past = $this->config->get($name, null); + $this->config->set($name, $mine); + $this->config->save(); + return $past; + } + + /** + * Gets mine with $name + * @param $name + * @return bool|mixed + */ + public function get($name){ + return $this->config->get($name, null); + } + + /** + * Removes a mine with $name and returns it + * @param $name + * @return bool|mixed + */ + public function remove($name){ + $past = $this->config->get($name, null); + $this->config->remove($name); + $this->config->save(); + return $past; + } + + /** + * Clears all mines + */ + public function clear(){ + $this->config->setAll([]); + $this->config->save(); + } + + /** + * Reloads the mines from YAML + */ + public function reload(){ + $this->config->reload(); + } + /** + * Returns something which can be used to iterate + * over the store. + * @return mixed + */ + public function getIterator(){ + return $this->config->getAll(); + } + + /** + * Saves mines to file + */ + public function save(){ + $this->config->save(); + } +} \ No newline at end of file diff --git a/src/minereset/Mine.php b/src/minereset/Mine.php deleted file mode 100644 index 90a308a..0000000 --- a/src/minereset/Mine.php +++ /dev/null @@ -1,79 +0,0 @@ -a = $a; - $this->b = $b; - $this->base = $base; - $this->name = $name; - $this->data = $data; - $this->level = $level; - } - /** - * @return bool - */ - public function isMineSet(){ - return (count($this->data) != 0); - } - /** - * @param array $arr - */ - public function setData(array $arr){ - $this->data = $arr; - } - /** - * @return Vector3 - */ - public function getA(){ - return $this->a; - } - /** - * @return Vector3 - */ - public function getB(){ - return $this->b; - } - /** - * @return Level|null - */ - public function getLevel(){ - return $this->base->getServer()->getLevel($this->level); - } - public function getName() { - return $this->name; - } - /** - * @return array - */ - public function getData(){ - return $this->data; - } - public function resetMine(){ - $chunks = []; - $chunkClass = Chunk::class; - for ($x = $this->getA()->getX(); $x-16 <= $this->getB()->getX(); $x += 16){ - for ($z = $this->getA()->getZ(); $z-16 <= $this->getB()->getZ(); $z += 16) { - $chunk = $this->getLevel()->getChunk($x >> 4, $z >> 4, true); - $chunkClass = get_class($chunk); - $chunks[Level::chunkHash($x >> 4, $z >> 4)] = $chunk->fastSerialize(); - } - } - $resetTask = new MineResetTask($chunks, $this->a, $this->b, $this->data, $this->level, $this->base->getRegionBlocker()->blockZone($this->a, $this->b, $this->getLevel()), $chunkClass); - $this->base->getServer()->getScheduler()->scheduleAsyncTask($mineResetTask); - } - public function __toString(){ - return $this->getName(); - } -} \ No newline at end of file diff --git a/src/minereset/MineReset.php b/src/minereset/MineReset.php deleted file mode 100644 index 5806747..0000000 --- a/src/minereset/MineReset.php +++ /dev/null @@ -1,269 +0,0 @@ -getDataFolder()); - $this->mineData = new Config($this->getDataFolder() . "mines.yml", Config::YAML, []); - $this->parseMines(); - $this->getServer()->getPluginManager()->registerEvents($this, $this); - $this->regionBlocker = new RegionBlocker($this); - } - - /** - * @param CommandSender $sender - * @param Command $cmd - * @param string $label - * @param array $args - * @return bool - */ - public function onCommand(CommandSender $sender, Command $cmd, $label, array $args){ - if(isset($args[0])){ - if(!$sender->hasPermission("minereset.commmand." . strtolower($args[0]))){ - $sender->sendMessage(TextFormat::RED . "You do not have permission." . TextFormat::RESET); - return true; - }else{ - switch($args[0]){ - case "create": - case "c": - if($sender instanceof Player){ - if(isset($args[1])){ - if(!isset($this->mines[$args[1]])){ - $this->sessions[$sender->getName()] = [$args[1]]; - $sender->sendMessage("Tap a block to set as first position..."); - return true; - } - else{ - $sender->sendMessage(TextFormat::RED . "That mine already exists." . TextFormat::RESET); - return true; - } - } - else{ - $sender->sendMessage("Usage: /mine create "); - return true; - } - } - else{ - $sender->sendMessage("You must use this command in-game"); - return true; - } - break; - case "destroy": - case "d": - if(isset($args[1])){ - if(isset($this->mines[$args[1]])){ - unset($this->mines[$args[1]]); - $this->saveConfig(); - $sender->sendMessage("Mine " . $args[1] . " has been destroyed."); - return true; - } - else{ - $sender->sendMessage(TextFormat::RED . "That mine doesn't exist." . TextFormat::RESET); - return true; - } - } - else{ - $sender->sendMessage("Usage: /mine destroy "); - return true; - } - break; - case "set": - case "s": - if(isset($args[1])){ - if(isset($args[3])){ - if (isset($this->mines[$args[1]])) { - $sets = array_slice($args, 2); - $save = []; - if(count($sets) % 2 === 0) { - foreach ($sets as $key => $item) { - if(strpos($item, "%")) { - $sender->sendMessage(TextFormat::RED . "Your format string looks incorrect." . TextFormat::RESET); - return true; - } - if ($key & 1) { - if (isset($save[$sets[$key - 1]])) { - $save[$sets[$key - 1]] += $item; - } else { - $save[$sets[$key - 1]] = $item; - } - } - } - $this->mines[$args[1]]->setData($save); - $sender->sendMessage("Mine blocks have been saved"); - $this->saveConfig(); - return true; - } - else{ - $sender->sendMessage(TextFormat::RED . "Your format string looks incorrect." . TextFormat::RESET); - return true; - } - } - else{ - $sender->sendMessage(TextFormat::RED . "Mine doesn't exist." . TextFormat::RESET); - return true; - } - } - else{ - $sender->sendMessage(TextFormat::RED . "You must provide at least one block with a chance value." . TextFormat::RESET); - return true; - } - } - else{ - $sender->sendMessage("Usage: /mine set "); - return true; - } - break; - case "reset": - case "r": - if(isset($args[1])){ - if(isset($this->mines[$args[1]])){ - if($this->mines[$args[1]]->isMineSet()){ - $this->mines[$args[1]]->resetMine(); - $sender->sendMessage("Mine is now resetting."); - return true; - } - else{ - $sender->sendMessage(TextFormat::RED . "Mine has not been set." . TextFormat::RESET); - return true; - } - } - else{ - $sender->sendMessage(TextFormat::RED . "Mine doesn't exist." . TextFormat::RESET); - return true; - } - } - else{ - $sender->sendMessage(TextFormat::RED . "You need to specify a name." . TextFormat::RESET); - return true; - } - break; - case "list": - case "l": - if(count($this->mines) == 0) - $sender->sendMessage("You have no mines."); - else - $sender->sendMessage("Mines: " . implode(",", array_keys($this->mines))); - break; - case "reset-all": - $i = 0; - foreach($this->mines as $mine) { - if($mine->isMineSet()) { - $mine->resetMine(); - $i++; - } - } - $sender->sendMessage("Resetting {$i} mines."); - return true; - break; - } - } - } - else{ - return false; - } - return true; - } - - /** - * @priority LOW - * @ignoreCancelled true - * - * @param PlayerInteractEvent $event - */ - public function onBlockTap(PlayerInteractEvent $event){ - if(isset($this->sessions[$event->getPlayer()->getName()])){ - if(isset($this->sessions[$event->getPlayer()->getName()][1])){ - /** @var Vector3 $a */ - $a = $this->sessions[$event->getPlayer()->getName()][1]; - $b = $event->getBlock(); - $this->mines[$this->sessions[$event->getPlayer()->getName()][0]] = new Mine($this, - $this->sessions[$event->getPlayer()->getName()][0], - new Vector3(min($a->getX(), $b->getX()), min($a->getY(), $b->getY()), min($a->getZ(), $b->getZ())), - new Vector3(max($a->getX(), $b->getX()), max($a->getY(), $b->getY()), max($a->getZ(), $b->getZ())), - $b->getLevel()->getId()); - $event->getPlayer()->sendMessage("Mine created."); - unset($this->sessions[$event->getPlayer()->getName()]); - $this->saveConfig(); - } - else{ - $this->sessions[$event->getPlayer()->getName()][1] = new Vector3($event->getBlock()->getX(), $event->getBlock()->getY(), $event->getBlock()->getZ()); - $event->getPlayer()->sendMessage("Tap another block to create mine"); - } - $event->setCancelled(); - } - } - - public function saveConfig(){ - $this->mineData->setAll([]); - foreach($this->mines as $n => $mine){ - $this->mineData->set($n, [ - $mine->getA()->getX(), - $mine->getB()->getX(), - $mine->getA()->getY(), - $mine->getB()->getY(), - $mine->getA()->getZ(), - $mine->getB()->getZ(), - (count($mine->getData()) > 0 ? $mine->getData() : false), - $mine->getLevel()->getName() - ]); - } - $this->mineData->save(); - } - - public function parseMines(){ - foreach($this->mineData->getAll() as $n => $m){ - if(!$this->getServer()->getLevelByName($m[7]) instanceof Level) { - if(!$this->getServer()->loadLevel($m[7])) { - $this->getLogger()->error("The world '{$m[7]}' of mine '{$n}' is invalid"); - continue; - } - $this->getLogger()->info("Loaded level '{$m[7]}' for mine '{$n}'"); - } - if(!is_array($m[6])) { - $this->getLogger()->error("The block settings for mine '{$n}' are incorrect"); - continue; - } - $this->mines[$n] = new Mine($this, - $n, - new Vector3(min($m[0], $m[1]), min($m[2], $m[3]), min($m[4], $m[5])), - new Vector3(max($m[0], $m[1]), max($m[2], $m[3]), max($m[4], $m[5])), - $this->getServer()->getLevelByName($m[7])->getId(), - $m[6]); - } - } - - /** - * @param MineResetTask $mineResetTask - */ - public function scheduleReset(MineResetTask $mineResetTask){ - $this->getServer()->getScheduler()->scheduleAsyncTask($mineResetTask); - } - - /** - * @return RegionBlocker - */ - public function getRegionBlocker(){ - return $this->regionBlocker; - } -} diff --git a/src/minereset/MineResetTask.php b/src/minereset/MineResetTask.php deleted file mode 100644 index f76f127..0000000 --- a/src/minereset/MineResetTask.php +++ /dev/null @@ -1,95 +0,0 @@ -chunks = serialize($chunks); - $this->a = $a; - $this->b = $b; - $this->ratioData = serialize($data); - $this->levelId = $levelId; - $this->regionId = $regionId; - $this->chunkClass = $chunkClass; - } - /** - * Actions to execute when run - * - * @return void - */ - public function onRun(){ - $chunkClass = $this->chunkClass; - /** @var Chunk[] $chunks */ - $chunks = unserialize($this->chunks); - foreach($chunks as $hash => $binary){ - $chunks[$hash] = $chunkClass::fastDeserialize($binary); - } - $sum = []; - $id = array_keys(unserialize($this->ratioData)); - for($i = 0; $i < count($id); $i++){ - $blockId = explode(":", $id[$i]); - if(!isset($blockId[1])){ - $blockId[1] = 0; - } - $id[$i] = $blockId; - } - $m = array_values(unserialize($this->ratioData)); - $sum[0] = $m[0]; - for ($l = 1; $l < count($m); $l++) - $sum[$l] = $sum[$l - 1] + $m[$l]; - for ($x = $this->a->getX(); $x <= $this->b->getX(); $x++) { - for ($y = $this->a->getY(); $y <= $this->b->getY(); $y++) { - for ($z = $this->a->getZ(); $z <= $this->b->getZ(); $z++) { - $a = rand(0, end($sum)); - for ($l = 0; $l < count($sum); $l++) { - if ($a <= $sum[$l]) { - $hash = Level::chunkHash($x >> 4, $z >> 4); - if(isset($chunks[$hash])){ - $chunks[$hash]->setBlock($x & 0x0f, $y & 0x7f, $z & 0x0f, $id[$l][0] & 0xff, $id[$l][1] & 0xff); - } - $l = count($sum); - } - } - } - } - } - $this->setResult($chunks); - } - /** - * @param Server $server - */ - public function onCompletion(Server $server){ - $chunks = $this->getResult(); - $plugin = $server->getPluginManager()->getPlugin("MineReset"); - if($plugin instanceof MineReset and $plugin->isEnabled()) { - $level = $server->getLevel($this->levelId); - if ($level instanceof Level) { - foreach ($chunks as $hash => $chunk) { - Level::getXZ($hash, $x, $z); - $level->setChunk($x, $z, $chunk); - } - } - $plugin->getRegionBlocker()->freeZone($this->regionId, $this->levelId); - } - } -} diff --git a/src/minereset/RegionBlocker.php b/src/minereset/RegionBlocker.php deleted file mode 100644 index 01e8298..0000000 --- a/src/minereset/RegionBlocker.php +++ /dev/null @@ -1,84 +0,0 @@ -plugin = $mineReset; - $this->activeZones = []; - $this->plugin->getServer()->getPluginManager()->registerEvents($this, $this->plugin); - } - /** - * @priority HIGH - * - * @param PlayerMoveEvent $event - */ - public function onPlayerMove(PlayerMoveEvent $event){ - if(isset($this->activeZones[$event->getPlayer()->getLevel()->getId()])){ - foreach($this->activeZones[$event->getPlayer()->getLevel()->getId()] as $zone){ - if($this->isInsideZone($event->getTo(), $zone[0], $zone[1])){ - $event->setCancelled(); - $event->getPlayer()->sendMessage(TextFormat::RED . "You can't go in there, a mine is resetting." . TextFormat::RESET); - return; - } - } - } - } - /** - * @param Vector3 $a - * @param Vector3 $b - * @param Level $level - * @return int - */ - public function blockZone(Vector3 $a, Vector3 $b, Level $level){ - if(!isset($this->activeZones[$level->getId()])) $this->activeZones[$level->getId()] = []; - $id = count($this->activeZones[$level->getId()]); - $this->activeZones[$level->getId()][$id] = [$a, $b]; - $this->clearZone($level, $id); - return $id; - } - /** - * @param int $id - * @param int $level - */ - public function freeZone(int $id, int $level){ - if(isset($this->activeZones[$level]) && isset($this->activeZones[$level][$id])){ - unset($this->activeZones[$level][$id]); - } - } - /** - * @param Vector3 $test - * @param Vector3 $a - * @param Vector3 $b - * @return bool - */ - protected function isInsideZone(Vector3 $test, Vector3 $a, Vector3 $b){ - return ($test->getX() >= $a->getX() && $test->getX() <= $b->getX() - && $test->getY() >= $a->getY() && $test->getY() <= $b->getY() - && $test->getZ() >= $a->getZ() && $test->getZ() <= $b->getZ()); - } - /** - * @param Level $level - * @param int $id - */ - protected function clearZone(Level $level, int $id){ - $level = $level->getId(); - if(isset($this->activeZones[$level]) && isset($this->activeZones[$level][$id])){ - foreach($this->plugin->getServer()->getOnlinePlayers() as $player){ - if($player->getLevel()->getId() === $level && $this->isInsideZone($player->getPosition(), $this->activeZones[$level][$id][0], $this->activeZones[$level][$id][1])){ - $player->teleport($player->getSpawn()); - $player->sendMessage("You have been teleported because you were inside a mine while it was resetting."); - } - } - } - } -} From e6e4d4600a75ef9f2dc80fcaa9ab377064137cb7 Mon Sep 17 00:00:00 2001 From: Falkirks Date: Mon, 17 Apr 2017 13:55:45 -0700 Subject: [PATCH 2/4] Working version --- plugin.yml | 5 - src/falkirks/minereset/Mine.php | 133 ++++++++++++++++++ src/falkirks/minereset/MineManager.php | 125 +++++++++------- src/falkirks/minereset/MineReset.php | 78 ++++++++++ .../minereset/ResetProgressManager.php | 59 ++++++++ .../minereset/command/CreateCommand.php | 38 +++++ .../minereset/command/DestroyCommand.php | 64 +++++++++ .../minereset/command/ListCommand.php | 16 +++ .../minereset/command/MineCommand.php | 49 +++++++ .../minereset/command/ResetAllCommand.php | 22 +++ .../minereset/command/ResetCommand.php | 28 ++++ src/falkirks/minereset/command/SetCommand.php | 49 +++++++ src/falkirks/minereset/command/SubCommand.php | 29 ++++ .../minereset/listener/CreationListener.php | 94 +++++++++++++ .../listener/MineCreationSession.php | 128 +++++++++++++++++ .../listener/RegionBlockerListener.php | 9 ++ src/falkirks/minereset/mine/Mine.php | 82 ----------- src/falkirks/minereset/task/ResetTask.php | 120 ++++++++++++++++ 18 files changed, 990 insertions(+), 138 deletions(-) create mode 100644 src/falkirks/minereset/Mine.php create mode 100644 src/falkirks/minereset/ResetProgressManager.php create mode 100644 src/falkirks/minereset/command/CreateCommand.php create mode 100644 src/falkirks/minereset/command/DestroyCommand.php create mode 100644 src/falkirks/minereset/command/ListCommand.php create mode 100644 src/falkirks/minereset/command/MineCommand.php create mode 100644 src/falkirks/minereset/command/ResetAllCommand.php create mode 100644 src/falkirks/minereset/command/ResetCommand.php create mode 100644 src/falkirks/minereset/command/SetCommand.php create mode 100644 src/falkirks/minereset/command/SubCommand.php create mode 100644 src/falkirks/minereset/listener/CreationListener.php create mode 100644 src/falkirks/minereset/listener/MineCreationSession.php create mode 100644 src/falkirks/minereset/listener/RegionBlockerListener.php delete mode 100644 src/falkirks/minereset/mine/Mine.php create mode 100644 src/falkirks/minereset/task/ResetTask.php diff --git a/plugin.yml b/plugin.yml index 674edee..622aa87 100644 --- a/plugin.yml +++ b/plugin.yml @@ -4,11 +4,6 @@ version: 3.0 author: Falk api: [1.0.0, 2.0.0, 3.0.0-ALPHA1, 3.0.0-ALPHA2, 3.0.0-ALPHA3, 3.0.0-ALPHA4, 3.0.0-ALPHA5] load: POSTWORLD -commands: - mine: - description: "MineReset command" - usage: "/mine [parameters]" - permission: minereset.command permissions: minereset: default: op diff --git a/src/falkirks/minereset/Mine.php b/src/falkirks/minereset/Mine.php new file mode 100644 index 0000000..1a33dc8 --- /dev/null +++ b/src/falkirks/minereset/Mine.php @@ -0,0 +1,133 @@ +pointA = $pointA; + $this->pointB = $pointB; + $this->level = $level; + $this->data = $data; + $this->name = $name; + $this->api = $api; + + $this->isResetting = false; + } + + /** + * @return Vector3 + */ + public function getPointA(): Vector3{ + return $this->pointA; + } + + /** + * @return Vector3 + */ + public function getPointB(): Vector3{ + return $this->pointB; + } + + /** + * @return Level + */ + public function getLevel(): Level{ + return $this->api->getApi()->getServer()->getLevelByName($this->level); + } + + /** + * @return string + */ + public function getLevelName(): string { + return $this->level; + } + + /** + * @return array + */ + public function getData(): array{ + return $this->data; + } + + /** + * @param array $data + */ + public function setData(array $data){ + $this->data = $data; + $this->getApi()->offsetSet($this->getName(), $this); + } + + /** + * @return string + */ + public function getName(): string{ + return $this->name; + } + + /** + * @return MineManager + */ + public function getApi(): MineManager{ + return $this->api; + } + + /** + * @return bool + */ + public function isResetting(){ + return $this->isResetting; + } + + public function reset(){ + if(!$this->isResetting()){ + //TODO make AsyncTask + $this->isResetting = true; + + $chunks = []; + $chunkClass = Chunk::class; + for ($x = $this->getPointA()->getX(); $x-16 <= $this->getPointB()->getX(); $x += 16){ + for ($z = $this->getPointA()->getZ(); $z-16 <= $this->getPointB()->getZ(); $z += 16) { + $chunk = $this->getLevel()->getChunk($x >> 4, $z >> 4, true); + $chunkClass = get_class($chunk); + $chunks[Level::chunkHash($x >> 4, $z >> 4)] = $chunk->fastSerialize(); + } + } + + $resetTask = new ResetTask($this->getName(), $chunks, $this->getPointA(), $this->getPointB(), $this->data, $this->getLevel()->getId(), $chunkClass); + $this->getApi()->getApi()->getServer()->getScheduler()->scheduleAsyncTask($resetTask); + return true; + } + return false; + } + + public function doneReset(){ + $this->isResetting = false; + } + +} \ No newline at end of file diff --git a/src/falkirks/minereset/MineManager.php b/src/falkirks/minereset/MineManager.php index 033d0c9..02eb3a2 100644 --- a/src/falkirks/minereset/MineManager.php +++ b/src/falkirks/minereset/MineManager.php @@ -2,13 +2,13 @@ namespace falkirks\minereset; -use falkirks\minereset\mine\Mine; use falkirks\minereset\store\DataStore; use falkirks\minereset\store\Reloadable; use falkirks\minereset\store\Saveable; +use pocketmine\math\Vector3; use pocketmine\utils\TextFormat; -class MineManager implements \ArrayAccess, \IteratorAggregate{ +class MineManager implements \ArrayAccess, \IteratorAggregate, \Countable { const MEMORY_TILL_CLOSE = 0; const FLUSH_ON_CHANGE = 1; /** @@ -20,16 +20,16 @@ class MineManager implements \ArrayAccess, \IteratorAggregate{ /** @var DataStore */ private $store; /** @var Mine[] */ - private $warps; + private $mines; private $flag; - public function __construct(MineReset $api, DataStore $store, $flag = MineManager::MEMORY_TILL_CLOSE){ + public function __construct(MineReset $api, DataStore $store, $flag = MineManager::FLUSH_ON_CHANGE){ $this->api = $api; $this->store = $store; $this->flag = $flag; - $this->warps = []; + $this->mines = []; if($this->flag < 2){ - $this->warps = $this->loadWarps(); + $this->mines = $this->loadMines(); } } protected function reloadStore(){ @@ -42,10 +42,10 @@ protected function saveStore($force = false){ $this->store->save(); } } - protected function loadWarps(): array{ + protected function loadMines(): array{ $out = []; foreach($this->store->getIterator() as $name => $data){ - $out[$name] = $this->warpFromData($name, $data); + $out[$name] = $this->mineFromData($name, $data); } return $out; } @@ -56,8 +56,8 @@ protected function loadWarps(): array{ public function saveAll(){ if($this->flag === 0){ $this->store->clear(); - foreach($this->warps as $warp){ - $this->store->add($warp->getName(), $this->warpToData($warp)); + foreach($this->mines as $mine){ + $this->store->add($mine->getName(), $this->mineToData($mine)); } $this->saveStore(true); } @@ -76,7 +76,7 @@ public function saveAll(){ */ public function offsetExists($offset){ $this->reloadStore(); - if(isset($this->warps[$offset]) || ($this->flag >= 2 && $this->store->exists($offset))){ + if(isset($this->mines[$offset]) || ($this->flag >= 2 && $this->store->exists($offset))){ return true; } return false; @@ -93,9 +93,9 @@ public function offsetExists($offset){ public function offsetGet($offset){ if($this->flag >= 2){ $this->reloadStore(); - return $this->warpFromData($offset, $this->store->get($offset)); + return $this->mineFromData($offset, $this->store->get($offset)); } - return isset($this->warps[$offset]) ? $this->warps[$offset] : null; + return isset($this->mines[$offset]) ? $this->mines[$offset] : null; } /** * (PHP 5 >= 5.0.0)
@@ -112,15 +112,15 @@ public function offsetGet($offset){ public function offsetSet($offset, $value){ if($value instanceof Mine && $value->getName() === $offset) { if($this->flag < 2) { - $this->warps[$offset] = $value; + $this->mines[$offset] = $value; } if ($this->flag >= 1) { - $this->store->add($offset, $this->warpToData($value)); + $this->store->add($offset, $this->mineToData($value)); $this->saveStore(); } } else{ - //TODO report failure + throw new \RuntimeException("Invalid \$offset for mine data."); } } /** @@ -134,7 +134,7 @@ public function offsetSet($offset, $value){ */ public function offsetUnset($offset){ if($this->flag < 2){ - unset($this->warps[$offset]); + unset($this->mines[$offset]); } if($this->flag >= 1){ $this->store->remove($offset); @@ -149,12 +149,27 @@ public function offsetUnset($offset){ * @return Mine * @throws \Exception */ - protected function warpFromData($name, array $array){ - if(isset($array["level"]) && isset($array["x"]) && isset($array["y"]) && isset($array["z"]) && isset($array["public"])){ // This is an internal warp - return new Warp($this, $name, new Destination(new WeakPosition($array["x"], $array["y"], $array["z"], $array["level"])), $array["public"], $array["metadata"] ?? []); - } - elseif(isset($array["address"]) && isset($array["port"]) && isset($array["public"])) { - return new Warp($this, $name, new Destination($array["address"], $array["port"]), $array["public"], $array["metadata"] ?? []); + protected function mineFromData($name, array $array){ + if(count($array) === 8) { + if(!$this->getApi()->getServer()->isLevelLoaded($array[7])){ + $this->api->getLogger()->warning("A mine with the name " . TextFormat::AQUA . $name . TextFormat::RESET . " is connected to a level which is not loaded. You won't be able to use it until you load the level correctly."); + } + + if(is_array($array[6])) { + return new Mine($this, + new Vector3(min($array[0], $array[1]), min($array[2], $array[3]), min($array[4], $array[5])), + new Vector3(max($array[0], $array[1]), max($array[2], $array[3]), max($array[4], $array[5])), + $array[7], + $name, + $array[6]); + } + else{ + return new Mine($this, + new Vector3(min($array[0], $array[1]), min($array[2], $array[3]), min($array[4], $array[5])), + new Vector3(max($array[0], $array[1]), max($array[2], $array[3]), max($array[4], $array[5])), + $array[7], + $name); + } } $this->api->getLogger()->critical("A mine with the name " . TextFormat::AQUA . $name . TextFormat::RESET . " is incomplete. It will be removed automatically when your server stops."); return null; @@ -163,45 +178,40 @@ protected function warpFromData($name, array $array){ * In order to pass data to a DataStore * a key is needed. Typically one should * use $warp->getName() - * @param Warp $warp + * @param Mine $mine * @return array */ - protected function warpToData(Warp $warp){ - $ret = []; - if($warp->getDestination()->isInternal()) { - //TODO implement yaw and pitch - $pos = $warp->getDestination()->getPosition(); - $ret = [ - "x" => $pos->getX(), - "y" => $pos->getY(), - "z" => $pos->getZ(), - "level" => ($pos instanceof WeakPosition ? $pos->getLevelName() : $pos->getLevel()->getName()), - "public" => $warp->isPublic(), - ]; - } - else{ - $ret = [ - "address" => $warp->getDestination()->getAddress(), - "port" => $warp->getDestination()->getPort(), - "public" => $warp->isPublic() - ]; - } - $ret["metadata"] = $warp->getAllMetadata(); - return $ret; + protected function mineToData(Mine $mine){ + return [ + $mine->getPointA()->getX(), + $mine->getPointB()->getX(), + $mine->getPointA()->getY(), + $mine->getPointB()->getY(), + $mine->getPointA()->getZ(), + $mine->getPointB()->getZ(), + (count($mine->getData()) > 0 ? $mine->getData() : false), + $mine->getLevelName() + ]; } /** * (PHP 5 >= 5.0.0)
* Retrieve an external iterator * @link http://php.net/manual/en/iteratoraggregate.getiterator.php - * @return Traversable An instance of an object implementing Iterator or + * @return \Traversable An instance of an object implementing Iterator or * Traversable */ public function getIterator(){ if($this->flag >= 2){ - return $this->loadWarps(); + return new \ArrayIterator($this->loadMines()); } - return $this->warps; + return new \ArrayIterator($this->mines); + } + + public function count(){ + return count($this->mines); } + + /** * Returns the current storage-mode * ##### @@ -237,15 +247,28 @@ public function getStore(): DataStore{ } /** * Injects a new DataStore for warps - * ! This will inject your code into SimpleWarp, potentially breaking! + * ! This will inject your code into MineReset, potentially breaking! * @param DataStore $store */ public function setStore(DataStore $store){ $this->saveAll(); $this->store = $store; if($this->flag < 2){ - $this->warps = $this->loadWarps(); + $this->mines = $this->loadMines(); } } + /** + * @return MineReset + */ + public function getApi(): MineReset{ + return $this->api; + } + + /** + * @return Mine[] + */ + public function getMines(): array{ + return $this->mines; + } } \ No newline at end of file diff --git a/src/falkirks/minereset/MineReset.php b/src/falkirks/minereset/MineReset.php index 1fe29fb..3e6399e 100644 --- a/src/falkirks/minereset/MineReset.php +++ b/src/falkirks/minereset/MineReset.php @@ -2,12 +2,90 @@ namespace falkirks\minereset; +use falkirks\minereset\command\CreateCommand; +use falkirks\minereset\command\DestroyCommand; +use falkirks\minereset\command\ListCommand; +use falkirks\minereset\command\MineCommand; +use falkirks\minereset\command\ResetAllCommand; +use falkirks\minereset\command\ResetCommand; +use falkirks\minereset\command\SetCommand; +use falkirks\minereset\listener\CreationListener; +use falkirks\minereset\store\YAMLStore; use pocketmine\plugin\PluginBase; +use pocketmine\utils\Config; + +/** + * MineReset is a powerful mine resetting tool for PocketMine + * + * Class MineReset + * @package falkirks\minereset + */ class MineReset extends PluginBase{ + /** @var MineManager */ + private $mineManager; + /** @var ResetProgressManager */ + private $resetProgressManager; + /** @var MineCommand */ + private $mainCommand; + + /** @var CreationListener */ + private $creationListener; + public function onEnable(){ @mkdir($this->getDataFolder()); + + $this->mineManager = new MineManager($this, new YAMLStore(new Config($this->getDataFolder() . "mines.yml", Config::YAML, []))); + + $this->resetProgressManager = new ResetProgressManager($this); + + $this->creationListener = new CreationListener($this); + $this->getServer()->getPluginManager()->registerEvents($this->creationListener, $this); + + $this->mainCommand = new MineCommand($this); + $this->getServer()->getCommandMap()->register("minereset", $this->mainCommand); + + $this->mainCommand->registerSubCommand("list", new ListCommand($this)); + $this->mainCommand->registerSubCommand("create", new CreateCommand($this)); + $this->mainCommand->registerSubCommand("set", new SetCommand($this)); + $this->mainCommand->registerSubCommand("destroy", new DestroyCommand($this)); + $this->mainCommand->registerSubCommand("create", new CreateCommand($this)); + $this->mainCommand->registerSubCommand("reset", new ResetCommand($this)); + $this->mainCommand->registerSubCommand("reset-all", new ResetAllCommand($this)); + } + + public function onDisable(){ + $this->mineManager->saveAll(); } + /** + * @return MineManager + */ + public function getMineManager(): MineManager{ + return $this->mineManager; + } + + /** + * @return ResetProgressManager + */ + public function getResetProgressManager(): ResetProgressManager{ + return $this->resetProgressManager; + } + + /** + * @return MineCommand + */ + public function getMainCommand(): MineCommand{ + return $this->mainCommand; + } + + /** + * @return CreationListener + */ + public function getCreationListener(): CreationListener{ + return $this->creationListener; + } + + } \ No newline at end of file diff --git a/src/falkirks/minereset/ResetProgressManager.php b/src/falkirks/minereset/ResetProgressManager.php new file mode 100644 index 0000000..7788620 --- /dev/null +++ b/src/falkirks/minereset/ResetProgressManager.php @@ -0,0 +1,59 @@ +api = $api; + $this->subscriptions = []; + } + + + public function notifyProgress(string $progress, string $mineName){ + if(isset($this->subscriptions[$mineName])){ + foreach ($this->subscriptions[$mineName] as $sender){ + $sender->sendMessage("RESET {$mineName}: {$progress}"); + } + } + } + + public function notifyComplete(string $mineName){ + if(isset($this->getApi()->getMineManager()[$mineName])){ + $this->getApi()->getMineManager()[$mineName]->doneReset(); + } + if(isset($this->subscriptions[$mineName])){ + foreach ($this->subscriptions[$mineName] as $sender){ + $sender->sendMessage("Reset of {$mineName} has completed."); + } + unset($this->subscriptions[$mineName]); + } + } + + public function addObserver(string $mineName, CommandSender $sender){ + if(!isset($this->subscriptions[$mineName])){ + $this->subscriptions[$mineName] = []; + } + $this->subscriptions[$mineName][] = $sender; + } + + /** + * @return MineReset + */ + public function getApi(): MineReset{ + return $this->api; + } + + +} \ No newline at end of file diff --git a/src/falkirks/minereset/command/CreateCommand.php b/src/falkirks/minereset/command/CreateCommand.php new file mode 100644 index 0000000..d9de537 --- /dev/null +++ b/src/falkirks/minereset/command/CreateCommand.php @@ -0,0 +1,38 @@ +getApi()->getCreationListener()->playerHasSession($sender)) { + if (!isset($this->getApi()->getMineManager()[$args[0]])) { + $this->getApi()->getCreationListener()->addSession(new MineCreationSession($args[0], $sender)); + $sender->sendMessage("Tap a block to set position A."); + } else { + $sender->sendMessage("That mine already exists. You must run \"/mine destroy {$args[0]}\" before creating a new one."); + } + } + else{ + $sender->sendMessage("Hold up! You are already in the process of creating a mine. You need to finish that first."); + } + + } + else { + $sender->sendMessage("Usage: /mine create "); + } + } + else{ + $sender->sendMessage(TextFormat::RED . "This command can only be run in-game." . TextFormat::RESET); + } + } +} \ No newline at end of file diff --git a/src/falkirks/minereset/command/DestroyCommand.php b/src/falkirks/minereset/command/DestroyCommand.php new file mode 100644 index 0000000..5cb72ea --- /dev/null +++ b/src/falkirks/minereset/command/DestroyCommand.php @@ -0,0 +1,64 @@ +offset = 0; + $this->senders = []; + } + + + public function execute(CommandSender $sender, $commandLabel, array $args){ + if(isset($args[0])){ + if(isset($this->getApi()->getMineManager()[$args[0]])){ + if(isset($args[1]) && isset($this->senders[$sender->getName()]) && $this->senders[$sender->getName()] === $args[1]){ + unset($this->getApi()->getMineManager()[$args[0]]); + unset($this->senders[$sender->getName()]); + $sender->sendMessage("{$args[0]} has been destroyed."); + } + else{ + $str = DestroyCommand::DESTROY_STRINGS[$this->offset]; + $sender->sendMessage("Run: " . TextFormat::AQUA . "/mine destroy {$args[0]} $str" . TextFormat::RESET); + $sender->sendMessage("To destroy mines faster, you can edit the config file directly."); + $this->senders[$sender->getName()] = $str; + + if($this->offset === count(DestroyCommand::DESTROY_STRINGS)-1){ + $this->offset = -1; + } + + $this->offset++; + } + } + else{ + $sender->sendMessage("{$args[0]} is not a valid mine."); + } + } + else{ + $sender->sendMessage("Usage: /mine destroy "); + } + } +} \ No newline at end of file diff --git a/src/falkirks/minereset/command/ListCommand.php b/src/falkirks/minereset/command/ListCommand.php new file mode 100644 index 0000000..532f712 --- /dev/null +++ b/src/falkirks/minereset/command/ListCommand.php @@ -0,0 +1,16 @@ +getApi()->getMineManager() as $mine){ + if($mine instanceof Mine) { + $sender->sendMessage($mine->getName()); + } + } + } +} \ No newline at end of file diff --git a/src/falkirks/minereset/command/MineCommand.php b/src/falkirks/minereset/command/MineCommand.php new file mode 100644 index 0000000..56068f0 --- /dev/null +++ b/src/falkirks/minereset/command/MineCommand.php @@ -0,0 +1,49 @@ + [parameters]"); + $this->api = $api; + $this->subCommands = []; + } + /** + * @param CommandSender $sender + * @param string $commandLabel + * @param string[] $args + * + * @return mixed + */ + public function execute(CommandSender $sender, $commandLabel, array $args){ + if(count($args) > 0 && array_key_exists($args[0], $this->subCommands)){ + return $this->subCommands[array_shift($args)]->execute($sender, $commandLabel, $args); + } + else{ + $sender->sendMessage($this->getUsage()); + return null; + } + } + + /** + * @return \pocketmine\plugin\Plugin + */ + public function getPlugin(): Plugin{ + return $this->api; + } + + public function registerSubCommand(string $name, SubCommand $command){ + $this->subCommands[$name] = $command; + } +} \ No newline at end of file diff --git a/src/falkirks/minereset/command/ResetAllCommand.php b/src/falkirks/minereset/command/ResetAllCommand.php new file mode 100644 index 0000000..9498459 --- /dev/null +++ b/src/falkirks/minereset/command/ResetAllCommand.php @@ -0,0 +1,22 @@ +getApi()->getMineManager() as $mine){ + if($mine instanceof Mine) { + if($mine->reset()){ + $success++; + $this->getApi()->getResetProgressManager()->addObserver($mine->getName(), $sender); + } + } + } + $count = count($this->getApi()->getMineManager()); + $sender->sendMessage("Queued reset for {$success}/{$count} mines."); + } +} \ No newline at end of file diff --git a/src/falkirks/minereset/command/ResetCommand.php b/src/falkirks/minereset/command/ResetCommand.php new file mode 100644 index 0000000..a28b29e --- /dev/null +++ b/src/falkirks/minereset/command/ResetCommand.php @@ -0,0 +1,28 @@ +getApi()->getMineManager()[$args[0]])){ + if($this->getApi()->getMineManager()[$args[0]]->reset()){ + $sender->sendMessage("Queued reset for {$args[0]}."); + $this->getApi()->getResetProgressManager()->addObserver($args[0], $sender); + } + else{ + $sender->sendMessage("Could not queue reset for {$args[0]}."); + } + } + else{ + $sender->sendMessage("{$args[0]} is not a valid mine."); + } + } + else{ + $sender->sendMessage("Usage: /mine reset "); + } + } +} \ No newline at end of file diff --git a/src/falkirks/minereset/command/SetCommand.php b/src/falkirks/minereset/command/SetCommand.php new file mode 100644 index 0000000..3fa55c7 --- /dev/null +++ b/src/falkirks/minereset/command/SetCommand.php @@ -0,0 +1,49 @@ +getApi()->getMineManager()[$args[0]])){ + if(isset($args[2])){ + $sets = array_slice($args, 1); + $save = []; + if(count($sets) % 2 === 0) { + foreach ($sets as $key => $item) { + if(strpos($item, "%")) { + $sender->sendMessage(TextFormat::RED . "Your format string looks incorrect." . TextFormat::RESET); + return; + } + if ($key & 1) { + if (isset($save[$sets[$key - 1]])) { + $save[$sets[$key - 1]] += $item; + } else { + $save[$sets[$key - 1]] = $item; + } + } + } + $this->getApi()->getMineManager()[$args[0]]->setData($save); + $sender->sendMessage(TextFormat::GREEN . "Mine has been setted. Use /mine reset {$args[0]} to see your changes."); + } + else{ + $sender->sendMessage(TextFormat::RED . "Your format string looks incorrect." . TextFormat::RESET); + } + } + else{ + $sender->sendMessage("You must provide at least one block with a chance value."); + } + } + else{ + $sender->sendMessage("{$args[0]} is not a valid mine."); + } + } + else{ + $sender->sendMessage("Usage: /mine set "); + } + } +} \ No newline at end of file diff --git a/src/falkirks/minereset/command/SubCommand.php b/src/falkirks/minereset/command/SubCommand.php new file mode 100644 index 0000000..9225189 --- /dev/null +++ b/src/falkirks/minereset/command/SubCommand.php @@ -0,0 +1,29 @@ +api = $api; + } + + + abstract public function execute(CommandSender $sender, $commandLabel, array $args); + + /** + * @return MineReset + */ + public function getApi(): MineReset{ + return $this->api; + } +} \ No newline at end of file diff --git a/src/falkirks/minereset/listener/CreationListener.php b/src/falkirks/minereset/listener/CreationListener.php new file mode 100644 index 0000000..460baef --- /dev/null +++ b/src/falkirks/minereset/listener/CreationListener.php @@ -0,0 +1,94 @@ +api = $api; + $this->sessions = []; + } + + /** + * @priority LOW + * @ignoreCancelled true + * + * @param PlayerInteractEvent $event + */ + public function onBlockTap(PlayerInteractEvent $event){ + $session = $this->getPlayerSession($event->getPlayer()); + + if($session !== null){ + if($session->getLevel() === null || $session->getLevel()->getId() === $event->getPlayer()->getId()) { + $session->setNextPoint($event->getBlock()); + $session->setLevel($event->getPlayer()->getPosition()->getLevel()); + + if($session->canGenerate()){ + $mine = $session->generate($this->getApi()->getMineManager()); + $event->getPlayer()->sendMessage("You have created a mine called " . $mine->getName() . "."); + $event->getPlayer()->sendMessage("You can set it using /mine set " . $mine->getName() . " "); + unset($this->sessions[array_search($session, $this->sessions)]); + } + else{ + $event->getPlayer()->sendMessage("You have set position A. Tap another block to set position B."); + } + } + else{ + $event->getPlayer()->sendMessage(TextFormat::RED . "Failed to create mine due to level switch". TextFormat::RESET); + unset($this->sessions[array_search($session, $this->sessions)]); + } + } + } + + /** + * @return MineReset + */ + public function getApi(): MineReset{ + return $this->api; + } + + public function playerHasSession(Player $player): bool { + foreach ($this->sessions as $session){ + if($session->getPlayer()->getName() === $player->getName()){ + return true; + } + } + return false; + } + + public function getPlayerSession(Player $player){ + foreach ($this->sessions as $session){ + if($session->getPlayer()->getName() === $player->getName()){ + return $session; + } + } + return null; + } + + + public function addSession(MineCreationSession $session): bool { + if(!$this->playerHasSession($session->getPlayer())) { + $this->sessions[] = $session; + return true; + } + return false; + } + + +} \ No newline at end of file diff --git a/src/falkirks/minereset/listener/MineCreationSession.php b/src/falkirks/minereset/listener/MineCreationSession.php new file mode 100644 index 0000000..7dd7a41 --- /dev/null +++ b/src/falkirks/minereset/listener/MineCreationSession.php @@ -0,0 +1,128 @@ +name = $name; + $this->player = $player; + $this->pointA = null; + $this->pointB = null; + $this->level = null; + } + + /** + * @return string + */ + public function getName(): string{ + return $this->name; + } + + /** + * @return Player + */ + public function getPlayer(): Player{ + return $this->player; + } + + /** + * @param Player $player + */ + public function setPlayer(Player $player){ + $this->player = $player; + } + + /** + * @return Vector3 | null + */ + public function getPointA(){ + return $this->pointA; + } + + /** + * @param Vector3 $pointA + */ + public function setPointA(Vector3 $pointA){ + $this->pointA = $pointA; + } + + /** + * @return Vector3 | null + */ + public function getPointB(){ + return $this->pointB; + } + + /** + * @param Vector3 $pointB + */ + public function setPointB(Vector3 $pointB){ + $this->pointB = $pointB; + } + + /** + * @return Level | null + */ + public function getLevel(){ + return $this->level; + } + + /** + * @param Level $level + */ + public function setLevel(Level $level){ + $this->level = $level; + } + + public function setNextPoint(Vector3 $point){ + if($this->pointA === null){ + $this->setPointA($point); + } + else if($this->pointB === null){ + $this->setPointB($point); + } + } + + public function canGenerate() : bool { + return $this->pointA !== null && $this->pointB !== null && $this->level !== null; + } + + public function generate(MineManager $owner): Mine{ + if($this->canGenerate()){ + $mine = new Mine($owner, + new Vector3(min($this->pointA->getFloorX(), $this->pointB->getFloorX()), min($this->pointA->getFloorY(), $this->pointB->getFloorY()), min($this->pointA->getFloorZ(), $this->pointB->getFloorZ())), + new Vector3(max($this->pointA->getFloorX(), $this->pointB->getFloorX()), max($this->pointA->getFloorY(), $this->pointB->getFloorY()), max($this->pointA->getFloorZ(), $this->pointB->getFloorZ())), + $this->level->getName(), + $this->name); + $owner[$this->name] = $mine; + return $mine; + } + else{ + throw new \InvalidStateException(); + } + } + +} \ No newline at end of file diff --git a/src/falkirks/minereset/listener/RegionBlockerListener.php b/src/falkirks/minereset/listener/RegionBlockerListener.php new file mode 100644 index 0000000..67ee87a --- /dev/null +++ b/src/falkirks/minereset/listener/RegionBlockerListener.php @@ -0,0 +1,9 @@ +pointA = $pointA; - $this->pointB = $pointB; - $this->level = $level; - $this->data = $data; - $this->name = $name; - $this->api = $api; - } - - /** - * @return Vector3 - */ - public function getPointA(): Vector3{ - return $this->pointA; - } - - /** - * @return Vector3 - */ - public function getPointB(): Vector3{ - return $this->pointB; - } - - /** - * @return Level - */ - public function getLevel(): Level{ - return $this->level; - } - - /** - * @return array - */ - public function getData(): array{ - return $this->data; - } - - /** - * @return string - */ - public function getName(): string{ - return $this->name; - } - - /** - * @return MineReset - */ - public function getApi(): MineReset{ - return $this->api; - } - -} \ No newline at end of file diff --git a/src/falkirks/minereset/task/ResetTask.php b/src/falkirks/minereset/task/ResetTask.php new file mode 100644 index 0000000..0c06626 --- /dev/null +++ b/src/falkirks/minereset/task/ResetTask.php @@ -0,0 +1,120 @@ +name = $name; + $this->chunks = serialize($chunks); + $this->a = $a; + $this->b = $b; + $this->ratioData = serialize($data); + $this->levelId = $levelId; + $this->chunkClass = $chunkClass; + } + /** + * Actions to execute when run + * + * @return void + */ + public function onRun(){ + $chunkClass = $this->chunkClass; + /** @var Chunk[] $chunks */ + $chunks = unserialize($this->chunks); + foreach($chunks as $hash => $binary){ + $chunks[$hash] = $chunkClass::fastDeserialize($binary); + } + $sum = []; + $id = array_keys(unserialize($this->ratioData)); + for($i = 0; $i < count($id); $i++){ + $blockId = explode(":", $id[$i]); + if(!isset($blockId[1])){ + $blockId[1] = 0; + } + $id[$i] = $blockId; + } + $m = array_values(unserialize($this->ratioData)); + $sum[0] = $m[0]; + for ($l = 1; $l < count($m); $l++) + $sum[$l] = $sum[$l - 1] + $m[$l]; + + $totalBlocks = ($this->b->x - $this->a->x + 1)*($this->b->y - $this->a->y + 1)*($this->b->z - $this->a->z + 1); + $interval = $totalBlocks / 8; //TODO determine the interval programmatically + $lastUpdate = 0; + $currentBlocks = 0; + + for ($x = $this->a->getX(); $x <= $this->b->getX(); $x++) { + for ($y = $this->a->getY(); $y <= $this->b->getY(); $y++) { + for ($z = $this->a->getZ(); $z <= $this->b->getZ(); $z++) { + $a = rand(0, end($sum)); + for ($l = 0; $l < count($sum); $l++) { + if ($a <= $sum[$l]) { + $hash = Level::chunkHash($x >> 4, $z >> 4); + if(isset($chunks[$hash])){ + $chunks[$hash]->setBlock($x & 0x0f, $y & 0x7f, $z & 0x0f, $id[$l][0] & 0xff, $id[$l][1] & 0xff); + $currentBlocks++; + if($lastUpdate + $interval <= $currentBlocks){ + $this->publishProgress(round(($currentBlocks / $totalBlocks)*100) . "%"); + $lastUpdate = $currentBlocks; + } + + } + $l = count($sum); + } + } + } + } + } + $this->setResult($chunks); + } + /** + * @param Server $server + */ + public function onCompletion(Server $server){ + $chunks = $this->getResult(); + $plugin = $server->getPluginManager()->getPlugin("MineReset"); + if($plugin instanceof MineReset and $plugin->isEnabled()) { + $level = $server->getLevel($this->levelId); + if ($level instanceof Level) { + foreach ($chunks as $hash => $chunk) { + Level::getXZ($hash, $x, $z); + $level->setChunk($x, $z, $chunk); + } + } + $plugin->getResetProgressManager()->notifyComplete($this->name); + } + } + + /** + * @param Server $server + * @param mixed $progress + */ + public function onProgressUpdate(Server $server, $progress){ + $plugin = $server->getPluginManager()->getPlugin("MineReset"); + if($plugin instanceof MineReset and $plugin->isEnabled()) { + $plugin->getResetProgressManager()->notifyProgress($progress, $this->name); + } + } +} \ No newline at end of file From 33d253a179df4953e042f5641bf7b320d5803666 Mon Sep 17 00:00:00 2001 From: Falkirks Date: Mon, 17 Apr 2017 14:20:21 -0700 Subject: [PATCH 3/4] Mine protection and escaping --- src/falkirks/minereset/Mine.php | 15 +++- src/falkirks/minereset/MineReset.php | 14 +++- .../listener/RegionBlockerListener.php | 76 +++++++++++++++++++ src/falkirks/minereset/task/ResetTask.php | 1 + 4 files changed, 104 insertions(+), 2 deletions(-) diff --git a/src/falkirks/minereset/Mine.php b/src/falkirks/minereset/Mine.php index 1a33dc8..cb98bd8 100644 --- a/src/falkirks/minereset/Mine.php +++ b/src/falkirks/minereset/Mine.php @@ -4,6 +4,7 @@ use falkirks\minereset\task\ResetTask; use pocketmine\level\format\Chunk; use pocketmine\level\Level; +use pocketmine\level\Position; use pocketmine\math\Vector3; /** @@ -54,6 +55,19 @@ public function getPointB(): Vector3{ return $this->pointB; } + public function isPointInside(Position $position): bool{ + if($position->getLevel()->getId() !== $this->getLevel()->getId()){ + return false; + } + + return $position->getX() >= $this->getPointA()->getX() + && $position->getX() <= $this->getPointB()->getX() + && $position->getY() >= $this->getPointA()->getY() + && $position->getY() <= $this->getPointB()->getY() + && $position->getZ() >= $this->getPointA()->getZ() + && $position->getZ() <= $this->getPointB()->getZ(); + } + /** * @return Level */ @@ -106,7 +120,6 @@ public function isResetting(){ public function reset(){ if(!$this->isResetting()){ - //TODO make AsyncTask $this->isResetting = true; $chunks = []; diff --git a/src/falkirks/minereset/MineReset.php b/src/falkirks/minereset/MineReset.php index 3e6399e..d1adbfc 100644 --- a/src/falkirks/minereset/MineReset.php +++ b/src/falkirks/minereset/MineReset.php @@ -10,6 +10,7 @@ use falkirks\minereset\command\ResetCommand; use falkirks\minereset\command\SetCommand; use falkirks\minereset\listener\CreationListener; +use falkirks\minereset\listener\RegionBlockerListener; use falkirks\minereset\store\YAMLStore; use pocketmine\plugin\PluginBase; use pocketmine\utils\Config; @@ -27,6 +28,8 @@ class MineReset extends PluginBase{ private $mineManager; /** @var ResetProgressManager */ private $resetProgressManager; + /** @var RegionBlockerListener */ + private $regionBlockerListener; /** @var MineCommand */ private $mainCommand; @@ -40,6 +43,9 @@ public function onEnable(){ $this->resetProgressManager = new ResetProgressManager($this); + $this->regionBlockerListener = new RegionBlockerListener($this); + $this->getServer()->getPluginManager()->registerEvents($this->regionBlockerListener, $this); + $this->creationListener = new CreationListener($this); $this->getServer()->getPluginManager()->registerEvents($this->creationListener, $this); @@ -87,5 +93,11 @@ public function getCreationListener(): CreationListener{ return $this->creationListener; } - + /** + * @return RegionBlockerListener + */ + public function getRegionBlockerListener(): RegionBlockerListener{ + return $this->regionBlockerListener; + } + } \ No newline at end of file diff --git a/src/falkirks/minereset/listener/RegionBlockerListener.php b/src/falkirks/minereset/listener/RegionBlockerListener.php index 67ee87a..4295174 100644 --- a/src/falkirks/minereset/listener/RegionBlockerListener.php +++ b/src/falkirks/minereset/listener/RegionBlockerListener.php @@ -2,8 +2,84 @@ namespace falkirks\minereset\listener; +use falkirks\minereset\Mine; +use falkirks\minereset\MineReset; +use pocketmine\event\block\BlockBreakEvent; +use pocketmine\event\block\BlockPlaceEvent; use pocketmine\event\Listener; +use pocketmine\event\player\PlayerMoveEvent; +use pocketmine\level\Position; +use pocketmine\utils\TextFormat; class RegionBlockerListener implements Listener { + /** @var MineReset */ + private $api; + + /** + * RegionBlockerListener constructor. + * @param MineReset $api + */ + public function __construct(MineReset $api){ + $this->api = $api; + } + + + public function clearMine(string $mineName){ + /** @var Mine $mine */ + $mine = $this->getApi()->getMineManager()[$mineName]; + if($mine !== null){ + foreach ($this->getApi()->getServer()->getOnlinePlayers() as $player){ + if($mine->isPointInside($player->getPosition())){ + $player->teleport($player->getLevel()->getSafeSpawn($player->getPosition())); + $player->sendMessage("You have teleported to escape a resetting mine."); + } + } + } + } + + /** + * @priority HIGH + * + * @param BlockPlaceEvent $event + */ + public function onBlockPlace(BlockPlaceEvent $event){ + + $mine = $this->getResettingMineAtPosition($event->getBlock()); + if($mine != null){ + $event->getPlayer()->sendMessage(TextFormat::RED . "A mine is currently resetting in this area. You may not place blocks." . TextFormat::RESET); + $event->setCancelled(); + } + } + + /** + * @priority HIGH + * + * @param BlockBreakEvent $event + */ + public function onBlockDestroy(BlockBreakEvent $event){ + + $mine = $this->getResettingMineAtPosition($event->getBlock()); + if($mine != null){ + $event->getPlayer()->sendMessage(TextFormat::RED . "A mine is currently resetting in this area. You may not break blocks." . TextFormat::RESET); + $event->setCancelled(); + } + } + + private function getResettingMineAtPosition(Position $position){ + foreach ($this->getApi()->getMineManager() as $mine) { + if($mine->isResetting() && $mine->isPointInside($position)){ + return $mine; + } + } + return null; + } + + /** + * @return MineReset + */ + public function getApi(): MineReset{ + return $this->api; + } + } \ No newline at end of file diff --git a/src/falkirks/minereset/task/ResetTask.php b/src/falkirks/minereset/task/ResetTask.php index 0c06626..915b583 100644 --- a/src/falkirks/minereset/task/ResetTask.php +++ b/src/falkirks/minereset/task/ResetTask.php @@ -103,6 +103,7 @@ public function onCompletion(Server $server){ $level->setChunk($x, $z, $chunk); } } + $plugin->getRegionBlockerListener()->clearMine($this->name); $plugin->getResetProgressManager()->notifyComplete($this->name); } } From 191e02e64aca443e000bbe7b8bfc67370c3bcac1 Mon Sep 17 00:00:00 2001 From: Falkirks Date: Mon, 17 Apr 2017 15:28:41 -0700 Subject: [PATCH 4/4] Add about command --- src/falkirks/minereset/Mine.php | 9 ++-- src/falkirks/minereset/MineReset.php | 4 +- .../minereset/command/AboutCommand.php | 13 ++++++ src/falkirks/minereset/store/EntityStore.php | 34 +++++++++++++++ src/falkirks/minereset/task/AboutPullTask.php | 41 +++++++++++++++++++ src/falkirks/minereset/task/ResetTask.php | 1 + 6 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 src/falkirks/minereset/command/AboutCommand.php create mode 100644 src/falkirks/minereset/store/EntityStore.php create mode 100644 src/falkirks/minereset/task/AboutPullTask.php diff --git a/src/falkirks/minereset/Mine.php b/src/falkirks/minereset/Mine.php index cb98bd8..c4ee3e8 100644 --- a/src/falkirks/minereset/Mine.php +++ b/src/falkirks/minereset/Mine.php @@ -56,7 +56,7 @@ public function getPointB(): Vector3{ } public function isPointInside(Position $position): bool{ - if($position->getLevel()->getId() !== $this->getLevel()->getId()){ + if($this->getLevel() !== null && $position->getLevel()->getId() !== $this->getLevel()->getId()){ return false; } @@ -69,9 +69,9 @@ public function isPointInside(Position $position): bool{ } /** - * @return Level + * @return Level | null */ - public function getLevel(): Level{ + public function getLevel(){ return $this->api->getApi()->getServer()->getLevelByName($this->level); } @@ -119,7 +119,7 @@ public function isResetting(){ } public function reset(){ - if(!$this->isResetting()){ + if(!$this->isResetting() && $this->getLevel() !== null){ $this->isResetting = true; $chunks = []; @@ -127,6 +127,7 @@ public function reset(){ for ($x = $this->getPointA()->getX(); $x-16 <= $this->getPointB()->getX(); $x += 16){ for ($z = $this->getPointA()->getZ(); $z-16 <= $this->getPointB()->getZ(); $z += 16) { $chunk = $this->getLevel()->getChunk($x >> 4, $z >> 4, true); + $chunkClass = get_class($chunk); $chunks[Level::chunkHash($x >> 4, $z >> 4)] = $chunk->fastSerialize(); } diff --git a/src/falkirks/minereset/MineReset.php b/src/falkirks/minereset/MineReset.php index d1adbfc..569915a 100644 --- a/src/falkirks/minereset/MineReset.php +++ b/src/falkirks/minereset/MineReset.php @@ -2,6 +2,7 @@ namespace falkirks\minereset; +use falkirks\minereset\command\AboutCommand; use falkirks\minereset\command\CreateCommand; use falkirks\minereset\command\DestroyCommand; use falkirks\minereset\command\ListCommand; @@ -11,6 +12,7 @@ use falkirks\minereset\command\SetCommand; use falkirks\minereset\listener\CreationListener; use falkirks\minereset\listener\RegionBlockerListener; +use falkirks\minereset\store\EntityStore; use falkirks\minereset\store\YAMLStore; use pocketmine\plugin\PluginBase; use pocketmine\utils\Config; @@ -52,6 +54,7 @@ public function onEnable(){ $this->mainCommand = new MineCommand($this); $this->getServer()->getCommandMap()->register("minereset", $this->mainCommand); + $this->mainCommand->registerSubCommand("about", new AboutCommand($this)); $this->mainCommand->registerSubCommand("list", new ListCommand($this)); $this->mainCommand->registerSubCommand("create", new CreateCommand($this)); $this->mainCommand->registerSubCommand("set", new SetCommand($this)); @@ -99,5 +102,4 @@ public function getCreationListener(): CreationListener{ public function getRegionBlockerListener(): RegionBlockerListener{ return $this->regionBlockerListener; } - } \ No newline at end of file diff --git a/src/falkirks/minereset/command/AboutCommand.php b/src/falkirks/minereset/command/AboutCommand.php new file mode 100644 index 0000000..c1e0381 --- /dev/null +++ b/src/falkirks/minereset/command/AboutCommand.php @@ -0,0 +1,13 @@ +getApi()->getServer()->getScheduler()->scheduleAsyncTask(new AboutPullTask($sender)); + } +} \ No newline at end of file diff --git a/src/falkirks/minereset/store/EntityStore.php b/src/falkirks/minereset/store/EntityStore.php new file mode 100644 index 0000000..d07cbae --- /dev/null +++ b/src/falkirks/minereset/store/EntityStore.php @@ -0,0 +1,34 @@ +api = $api; + $this->store = []; + } + + public function storeEntities($mineName, $entities){ + $this->store[$mineName] = $entities; + } + + public function retrieveEntities($mineName){ + if(isset($this->store[$mineName])){ + $entities = $this->store[$mineName]; + unset($this->store[$mineName]); + return $entities; + } + return null; + } + +} \ No newline at end of file diff --git a/src/falkirks/minereset/task/AboutPullTask.php b/src/falkirks/minereset/task/AboutPullTask.php new file mode 100644 index 0000000..cd403a6 --- /dev/null +++ b/src/falkirks/minereset/task/AboutPullTask.php @@ -0,0 +1,41 @@ +setResult(Utils::getURL(AboutPullTask::ABOUT_URL)); + } + + public function onCompletion(Server $server){ + $sender = $this->fetchLocal($server); + if($sender instanceof CommandSender){ + $result = $this->getResult(); + if($result !== false){ + $sender->sendMessage($this->getResult()); + } + else{ + $sender->sendMessage("MineReset by Falkirks. This is a fancy plugin that allows you to make resettable mines."); + } + } + } + + +} \ No newline at end of file diff --git a/src/falkirks/minereset/task/ResetTask.php b/src/falkirks/minereset/task/ResetTask.php index 915b583..7e0f584 100644 --- a/src/falkirks/minereset/task/ResetTask.php +++ b/src/falkirks/minereset/task/ResetTask.php @@ -101,6 +101,7 @@ public function onCompletion(Server $server){ foreach ($chunks as $hash => $chunk) { Level::getXZ($hash, $x, $z); $level->setChunk($x, $z, $chunk); + } } $plugin->getRegionBlockerListener()->clearMine($this->name);