From 8b4fc87d3c08633b27e21d5f62423d492a35d8a8 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Sat, 9 Jul 2022 04:20:07 +0200 Subject: [PATCH 01/24] Fix new users being unable to create selections --- src/xenialdan/MagicWE2/selection/Selection.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/xenialdan/MagicWE2/selection/Selection.php b/src/xenialdan/MagicWE2/selection/Selection.php index a2c2ab7..d8ffa4d 100644 --- a/src/xenialdan/MagicWE2/selection/Selection.php +++ b/src/xenialdan/MagicWE2/selection/Selection.php @@ -103,8 +103,10 @@ public function getWorld(): World return $world; } - public function setWorld(World $world): void - { + public function setWorld(World $world) : void{ + if($this->worldId === $world->getId()){ + return; + } $this->worldId = $world->getId(); try { (new MWESelectionChangeEvent($this, MWESelectionChangeEvent::TYPE_WORLD))->call(); From fa49f46ea3bc7d7c5392425ab10cb267631aab18 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Sat, 9 Jul 2022 04:50:19 +0200 Subject: [PATCH 02/24] Changed Selection constructor, fix crash upon loading session - Selection now takes in Vector3 instead of integers - Fixed a (potential, faced it due to a bug) crash when loading sessions from json caused by undefined shape properties - Removed some unnecessary return values from methods - Fixed some crashes when updating Outline or Scoreboard - Updated rotate action to use the API method - Added Shape::rotate() - Fixed crash with ScoreFactory when leaving the server - Added many try-catch blocks and debug TODO remove --- src/xenialdan/MagicWE2/API.php | 6 +- src/xenialdan/MagicWE2/EventListener.php | 50 +++-- .../commands/debug/TestAPICommand.php | 9 +- .../commands/selection/ChunkCommand.php | 28 ++- .../commands/selection/HPos1Command.php | 24 ++- .../commands/selection/HPos2Command.php | 24 ++- .../commands/selection/Pos1Command.php | 23 +- .../commands/selection/Pos2Command.php | 23 +- .../event/MWESelectionChangeEvent.php | 15 -- src/xenialdan/MagicWE2/helper/AsyncWorld.php | 23 +- src/xenialdan/MagicWE2/helper/Scoreboard.php | 15 +- .../MagicWE2/helper/SessionHelper.php | 134 ++++++------ .../MagicWE2/selection/Selection.php | 197 ++++++++---------- .../MagicWE2/selection/shape/Cone.php | 30 +-- .../MagicWE2/selection/shape/Cube.php | 15 +- .../MagicWE2/selection/shape/Cuboid.php | 39 ++-- .../MagicWE2/selection/shape/Custom.php | 18 +- .../MagicWE2/selection/shape/Cylinder.php | 33 +-- .../MagicWE2/selection/shape/Ellipsoid.php | 40 ++-- .../MagicWE2/selection/shape/Pyramid.php | 88 ++++---- .../MagicWE2/selection/shape/Shape.php | 13 +- .../MagicWE2/selection/shape/Sphere.php | 22 +- src/xenialdan/MagicWE2/session/Session.php | 7 +- .../MagicWE2/session/UserSession.php | 8 +- .../MagicWE2/session/data/Outline.php | 42 ++-- .../MagicWE2/task/action/ClipboardAction.php | 2 +- .../MagicWE2/task/action/FlipAction.php | 3 +- .../MagicWE2/task/action/RotateAction.php | 94 +-------- 28 files changed, 504 insertions(+), 521 deletions(-) diff --git a/src/xenialdan/MagicWE2/API.php b/src/xenialdan/MagicWE2/API.php index d40b129..77bd2bc 100644 --- a/src/xenialdan/MagicWE2/API.php +++ b/src/xenialdan/MagicWE2/API.php @@ -580,7 +580,11 @@ private static function rotateClipboard(SingleClipboard $structure, int $rotatio if($rotation === 0) return $structure; //width is x axis, length is z axis - $newClipboard = new SingleClipboard(Vector3::zero()); + $newClipboard = new SingleClipboard($structure->position); + $newClipboard->selection = $structure->selection; + $newClipboard->selection->free();//TODO check if this is necessary + $newClipboard->selection->shape = $structure->selection->getShape()->rotate($rotation); + //$x = $y = $z = null; /** @var BlockEntry $entry */ foreach($structure->iterateEntries($x, $y, $z) as $entry){ diff --git a/src/xenialdan/MagicWE2/EventListener.php b/src/xenialdan/MagicWE2/EventListener.php index c41d7f2..5c3f9dc 100644 --- a/src/xenialdan/MagicWE2/EventListener.php +++ b/src/xenialdan/MagicWE2/EventListener.php @@ -24,7 +24,6 @@ use pocketmine\plugin\Plugin; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\TextFormat as TF; -use pocketmine\world\Position; use RuntimeException; use xenialdan\libstructure\tile\StructureBlockTile; use xenialdan\MagicWE2\event\MWESelectionChangeEvent; @@ -34,6 +33,7 @@ use xenialdan\MagicWE2\selection\Selection; use xenialdan\MagicWE2\session\UserSession; use xenialdan\MagicWE2\tool\Brush; +use function is_null; use function var_dump; class EventListener implements Listener @@ -170,7 +170,6 @@ public function onBreak(BlockBreakEvent $event): void * @param BlockBreakEvent $event * @throws AssumptionFailedError * @throws Error - * @throws InvalidArgumentException * @throws SessionException */ private function onBreakBlock(BlockBreakEvent $event): void @@ -180,15 +179,21 @@ private function onBreakBlock(BlockBreakEvent $event): void switch ($event->getItem()->getId()) { case ItemIds::WOODEN_AXE: { - if (!$session->isWandEnabled()) { + if(!$session->isWandEnabled()){ $session->sendMessage(TF::RED . $session->getLanguage()->translateString("tool.wand.disabled")); break; } - $selection = $session->getLatestSelection() ?? $session->addSelection(new Selection($session->getUUID(), $event->getBlock()->getPosition()->getWorld())); // TODO check if the selection inside of the session updates - if (is_null($selection)) { + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); + if(($selection = $session->getLatestSelection()) === null){ + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); + $session->addSelection(($selection = new Selection($session->getUUID(), $event->getBlock()->getPosition()->getWorld()))); // TODO check if the selection inside of the session updates + } + if(is_null($selection)){ throw new Error("No selection created - Check the console for errors"); } - $selection->setPos1(new Position($event->getBlock()->getPosition()->x, $event->getBlock()->getPosition()->y, $event->getBlock()->getPosition()->z, $event->getBlock()->getPosition()->getWorld())); + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); + $selection->setPos1($event->getBlock()->getPosition()); + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); break; } case ItemIds::STICK: @@ -222,15 +227,21 @@ private function onRightClickBlock(PlayerInteractEvent $event): void switch ($event->getItem()->getId()) { case ItemIds::WOODEN_AXE: { - if (!$session->isWandEnabled()) { + if(!$session->isWandEnabled()){ $session->sendMessage(TF::RED . $session->getLanguage()->translateString("tool.wand.disabled")); break; } - $selection = $session->getLatestSelection() ?? $session->addSelection(new Selection($session->getUUID(), $event->getBlock()->getPosition()->getWorld())); // TODO check if the selection inside of the session updates - if (is_null($selection)) { + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); + if(($selection = $session->getLatestSelection()) === null){ + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); + $session->addSelection(($selection = new Selection($session->getUUID(), $event->getBlock()->getPosition()->getWorld()))); // TODO check if the selection inside of the session updates + } + if(is_null($selection)){ throw new Error("No selection created - Check the console for errors"); } - $selection->setPos2(new Position($event->getBlock()->getPosition()->x, $event->getBlock()->getPosition()->y, $event->getBlock()->getPosition()->z, $event->getBlock()->getPosition()->getWorld())); + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); + $selection->setPos2($event->getBlock()->getPosition()); + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); break; } case ItemIds::STICK: @@ -292,15 +303,21 @@ private function onLeftClickBlock(PlayerInteractEvent $event): void switch ($event->getItem()->getId()) { case ItemIds::WOODEN_AXE: { - if (!$session->isWandEnabled()) { + if(!$session->isWandEnabled()){ $session->sendMessage(TF::RED . $session->getLanguage()->translateString("tool.wand.disabled")); break; } - $selection = $session->getLatestSelection() ?? $session->addSelection(new Selection($session->getUUID(), $event->getBlock()->getPosition()->getWorld())); // TODO check if the selection inside of the session updates - if (is_null($selection)) { + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); + if(($selection = $session->getLatestSelection()) === null){ + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); + $session->addSelection(($selection = new Selection($session->getUUID(), $event->getBlock()->getPosition()->getWorld()))); // TODO check if the selection inside of the session updates + } + if(is_null($selection)){ throw new Error("No selection created - Check the console for errors"); } - $selection->setPos1(new Position($event->getBlock()->getPosition()->x, $event->getBlock()->getPosition()->y, $event->getBlock()->getPosition()->z, $event->getBlock()->getPosition()->getWorld())); + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); + $selection->setPos1($event->getBlock()->getPosition()); + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); break; } case ItemIds::STICK: @@ -382,9 +399,10 @@ public function onSelectionChange(MWESelectionChangeEvent $event): void { #Loader::getInstance()->getLogger()->debug("Called " . $event->getEventName()); $session = $event->getSession(); - if ($session instanceof UserSession && $event->getPlayer() !== null) { + if ($session instanceof UserSession && $event->getPlayer() !== null){ /** @var UserSession $session */ - if ($session->isOutlineEnabled()) $session->createOrUpdateOutline($event->getSelection()); + $session->setOutlineEnabled($session->isOutlineEnabled()); + //if ($session->isOutlineEnabled()) $session->createOrUpdateOutline($event->getSelection()); $session->sidebar->handleScoreboard($session); } } diff --git a/src/xenialdan/MagicWE2/commands/debug/TestAPICommand.php b/src/xenialdan/MagicWE2/commands/debug/TestAPICommand.php index 7255642..21f1aff 100644 --- a/src/xenialdan/MagicWE2/commands/debug/TestAPICommand.php +++ b/src/xenialdan/MagicWE2/commands/debug/TestAPICommand.php @@ -8,6 +8,7 @@ use Exception; use InvalidArgumentException; use pocketmine\command\CommandSender; +use pocketmine\math\Vector3; use pocketmine\player\Player; use pocketmine\Server; use pocketmine\utils\TextFormat as TF; @@ -46,7 +47,7 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo try { //TODO REMOVE DEBUG $pluginSession = SessionHelper::createPluginSession(Loader::getInstance()); - $selection = new Selection($pluginSession->getUUID(), Server::getInstance()->getWorldManager()->getDefaultWorld(), 0, 0, 0, 0, 0, 0); + $selection = new Selection($pluginSession->getUUID(), Server::getInstance()->getWorldManager()->getDefaultWorld(), new Vector3(0, 0, 0), new Vector3(0, 0, 0)); $pluginSession->addSelection($selection); Server::getInstance()->getAsyncPool()->submitTask( new AsyncActionTask( @@ -57,7 +58,7 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo BlockPalette::fromString("minecraft:tnt") ) ); - $selection = new Selection($pluginSession->getUUID(), Server::getInstance()->getWorldManager()->getDefaultWorld(), 0, 0, 0, 1, 1, 1); + $selection = new Selection($pluginSession->getUUID(), Server::getInstance()->getWorldManager()->getDefaultWorld(), new Vector3(0, 0, 0), new Vector3(1, 1, 1)); Server::getInstance()->getAsyncPool()->submitTask( new AsyncActionTask( $pluginSession->getUUID(), @@ -67,7 +68,7 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo BlockPalette::fromString("minecraft:tnt") ) ); - $selection = new Selection($pluginSession->getUUID(), Server::getInstance()->getWorldManager()->getDefaultWorld(), 0, 0, 0, 2, 2, 2); + $selection = new Selection($pluginSession->getUUID(), Server::getInstance()->getWorldManager()->getDefaultWorld(), new Vector3(0, 0, 0), new Vector3(2, 2, 2)); Server::getInstance()->getAsyncPool()->submitTask( new AsyncActionTask( $pluginSession->getUUID(), @@ -77,7 +78,7 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo BlockPalette::fromString("minecraft:tnt") ) ); - $selection = new Selection($pluginSession->getUUID(), Server::getInstance()->getWorldManager()->getDefaultWorld(), 0, 0, 0, 1, 2, 3); + $selection = new Selection($pluginSession->getUUID(), Server::getInstance()->getWorldManager()->getDefaultWorld(), new Vector3(0, 0, 0), new Vector3(1, 2, 3)); Server::getInstance()->getAsyncPool()->submitTask( new AsyncActionTask( $pluginSession->getUUID(), diff --git a/src/xenialdan/MagicWE2/commands/selection/ChunkCommand.php b/src/xenialdan/MagicWE2/commands/selection/ChunkCommand.php index e107138..68eacfe 100644 --- a/src/xenialdan/MagicWE2/commands/selection/ChunkCommand.php +++ b/src/xenialdan/MagicWE2/commands/selection/ChunkCommand.php @@ -19,16 +19,16 @@ use xenialdan\MagicWE2\Loader; use xenialdan\MagicWE2\selection\Selection; use xenialdan\MagicWE2\session\UserSession; +use function is_null; +use function var_dump; -class ChunkCommand extends BaseCommand -{ +class ChunkCommand extends BaseCommand{ /** * This is where all the arguments, permissions, sub-commands, etc would be registered * @throws InvalidArgumentException */ - protected function prepare(): void - { + protected function prepare() : void{ $this->setPermission("we.command.selection.chunk"); } @@ -49,23 +49,31 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo return; } /** @var Player $sender */ - try { + try{ $session = SessionHelper::getUserSession($sender); - if (!$session instanceof UserSession) { + if(!$session instanceof UserSession){ throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()])); } - $selection = $session->getLatestSelection() ?? $session->addSelection(new Selection($session->getUUID(), $sender->getWorld())); // TODO check if the selection inside of the session updates - if (is_null($selection)) { + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); + if(($selection = $session->getLatestSelection()) === null){ + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); + $session->addSelection(($selection = new Selection($session->getUUID(), $sender->getWorld()))); // TODO check if the selection inside of the session updates + } + if(is_null($selection)){ throw new Error("No selection created - Check the console for errors"); } + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $chunk = $sender->getWorld()->getOrLoadChunkAtPosition($sender->getPosition()); - if (is_null($chunk)) { + if(is_null($chunk)){ throw new Error("Could not find a chunk at your position"); } $x = $sender->getPosition()->x >> 4; $z = $sender->getPosition()->x >> 4; - $selection->setPos1(Position::fromObject(new Vector3($x * 16, 0, $z * 16), $sender->getWorld())); + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); + $selection->setPos1(Position::fromObject(new Vector3($x * 16, World::Y_MIN, $z * 16), $sender->getWorld())); + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $selection->setPos2(Position::fromObject(new Vector3($x * 16 + 15, World::Y_MAX, $z * 16 + 15), $sender->getWorld())); + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); } catch (Exception $error) { $sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error')); $sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage()); diff --git a/src/xenialdan/MagicWE2/commands/selection/HPos1Command.php b/src/xenialdan/MagicWE2/commands/selection/HPos1Command.php index 2b66e41..68e8195 100644 --- a/src/xenialdan/MagicWE2/commands/selection/HPos1Command.php +++ b/src/xenialdan/MagicWE2/commands/selection/HPos1Command.php @@ -16,16 +16,16 @@ use xenialdan\MagicWE2\Loader; use xenialdan\MagicWE2\selection\Selection; use xenialdan\MagicWE2\session\UserSession; +use function is_null; +use function var_dump; -class HPos1Command extends BaseCommand -{ +class HPos1Command extends BaseCommand{ /** * This is where all the arguments, permissions, sub-commands, etc would be registered * @throws InvalidArgumentException */ - protected function prepare(): void - { + protected function prepare() : void{ $this->setPermission("we.command.selection.hpos"); } @@ -46,21 +46,27 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo return; } /** @var Player $sender */ - try { + try{ $session = SessionHelper::getUserSession($sender); - if (!$session instanceof UserSession) { + if(!$session instanceof UserSession){ throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()])); } - $selection = $session->getLatestSelection() ?? $session->addSelection(new Selection($session->getUUID(), $sender->getWorld())); // TODO check if the selection inside of the session updates - if (is_null($selection)) { + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); + if(($selection = $session->getLatestSelection()) === null){ + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); + $session->addSelection(($selection = new Selection($session->getUUID(), $sender->getWorld()))); // TODO check if the selection inside of the session updates + } + if(is_null($selection)){ throw new Error("No selection created - Check the console for errors"); } $target = $sender->getTargetBlock(Loader::getInstance()->getToolDistance()); - if ($target === null) { + if($target === null){ $sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.notarget')); return; } + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $selection->setPos1($target->getPosition()); + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); } catch (Exception $error) { $sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error')); $sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage()); diff --git a/src/xenialdan/MagicWE2/commands/selection/HPos2Command.php b/src/xenialdan/MagicWE2/commands/selection/HPos2Command.php index 6bf1da4..1913b96 100644 --- a/src/xenialdan/MagicWE2/commands/selection/HPos2Command.php +++ b/src/xenialdan/MagicWE2/commands/selection/HPos2Command.php @@ -16,16 +16,16 @@ use xenialdan\MagicWE2\Loader; use xenialdan\MagicWE2\selection\Selection; use xenialdan\MagicWE2\session\UserSession; +use function is_null; +use function var_dump; -class HPos2Command extends BaseCommand -{ +class HPos2Command extends BaseCommand{ /** * This is where all the arguments, permissions, sub-commands, etc would be registered * @throws InvalidArgumentException */ - protected function prepare(): void - { + protected function prepare() : void{ $this->setPermission("we.command.selection.hpos"); } @@ -46,21 +46,27 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo return; } /** @var Player $sender */ - try { + try{ $session = SessionHelper::getUserSession($sender); - if (!$session instanceof UserSession) { + if(!$session instanceof UserSession){ throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()])); } - $selection = $session->getLatestSelection() ?? $session->addSelection(new Selection($session->getUUID(), $sender->getWorld())); // TODO check if the selection inside of the session updates - if (is_null($selection)) { + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); + if(($selection = $session->getLatestSelection()) === null){ + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); + $session->addSelection(($selection = new Selection($session->getUUID(), $sender->getWorld()))); // TODO check if the selection inside of the session updates + } + if(is_null($selection)){ throw new Error("No selection created - Check the console for errors"); } $target = $sender->getTargetBlock(Loader::getInstance()->getToolDistance()); - if ($target === null) { + if($target === null){ $sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.notarget')); return; } + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $selection->setPos2($target->getPosition()); + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); } catch (Exception $error) { $sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error')); $sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage()); diff --git a/src/xenialdan/MagicWE2/commands/selection/Pos1Command.php b/src/xenialdan/MagicWE2/commands/selection/Pos1Command.php index 61d5d8e..77e710b 100644 --- a/src/xenialdan/MagicWE2/commands/selection/Pos1Command.php +++ b/src/xenialdan/MagicWE2/commands/selection/Pos1Command.php @@ -16,16 +16,16 @@ use xenialdan\MagicWE2\Loader; use xenialdan\MagicWE2\selection\Selection; use xenialdan\MagicWE2\session\UserSession; +use function is_null; +use function var_dump; -class Pos1Command extends BaseCommand -{ +class Pos1Command extends BaseCommand{ /** * This is where all the arguments, permissions, sub-commands, etc would be registered * @throws InvalidArgumentException */ - protected function prepare(): void - { + protected function prepare() : void{ $this->setPermission("we.command.selection.pos"); } @@ -46,17 +46,24 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo return; } /** @var Player $sender */ - try { + try{ $session = SessionHelper::getUserSession($sender); - if (!$session instanceof UserSession) { + if(!$session instanceof UserSession){ throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()])); } - $selection = $session->getLatestSelection() ?? $session->addSelection(new Selection($session->getUUID(), $sender->getWorld())); // TODO check if the selection inside of the session updates - if (is_null($selection)) { + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); + if(($selection = $session->getLatestSelection()) === null){ + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); + $session->addSelection(($selection = new Selection($session->getUUID(), $sender->getWorld()))); // TODO check if the selection inside of the session updates + } + if(is_null($selection)){ throw new Error("No selection created - Check the console for errors"); } + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $selection->setPos1($sender->getPosition()); + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); } catch (Exception $error) { + Loader::getInstance()->getLogger()->logException($error); $sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error')); $sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage()); $sender->sendMessage($this->getUsage()); diff --git a/src/xenialdan/MagicWE2/commands/selection/Pos2Command.php b/src/xenialdan/MagicWE2/commands/selection/Pos2Command.php index 5288892..d9a15da 100644 --- a/src/xenialdan/MagicWE2/commands/selection/Pos2Command.php +++ b/src/xenialdan/MagicWE2/commands/selection/Pos2Command.php @@ -16,16 +16,16 @@ use xenialdan\MagicWE2\Loader; use xenialdan\MagicWE2\selection\Selection; use xenialdan\MagicWE2\session\UserSession; +use function is_null; +use function var_dump; -class Pos2Command extends BaseCommand -{ +class Pos2Command extends BaseCommand{ /** * This is where all the arguments, permissions, sub-commands, etc would be registered * @throws InvalidArgumentException */ - protected function prepare(): void - { + protected function prepare() : void{ $this->setPermission("we.command.selection.pos"); } @@ -46,17 +46,24 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo return; } /** @var Player $sender */ - try { + try{ $session = SessionHelper::getUserSession($sender); - if (!$session instanceof UserSession) { + if(!$session instanceof UserSession){ throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()])); } - $selection = $session->getLatestSelection() ?? $session->addSelection(new Selection($session->getUUID(), $sender->getWorld())); // TODO check if the selection inside of the session updates - if (is_null($selection)) { + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); + if(($selection = $session->getLatestSelection()) === null){ + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); + $session->addSelection(($selection = new Selection($session->getUUID(), $sender->getWorld()))); // TODO check if the selection inside of the session updates + } + if(is_null($selection)){ throw new Error("No selection created - Check the console for errors"); } + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $selection->setPos2($sender->getPosition()); + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); } catch (Exception $error) { + Loader::getInstance()->getLogger()->logException($error); $sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error')); $sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage()); $sender->sendMessage($this->getUsage()); diff --git a/src/xenialdan/MagicWE2/event/MWESelectionChangeEvent.php b/src/xenialdan/MagicWE2/event/MWESelectionChangeEvent.php index 3ee6b11..1dbca6f 100644 --- a/src/xenialdan/MagicWE2/event/MWESelectionChangeEvent.php +++ b/src/xenialdan/MagicWE2/event/MWESelectionChangeEvent.php @@ -34,33 +34,21 @@ public function __construct(Selection $selection, int $type) } } - /** - * @return Selection - */ public function getSelection(): Selection { return $this->selection; } - /** - * @param Selection $selection - */ public function setSelection(Selection $selection): void { $this->selection = $selection; } - /** - * @return null|Session - */ public function getSession(): ?Session { return $this->session; } - /** - * @return null|Player - */ public function getPlayer(): ?Player { if (($session = $this->getSession()) instanceof UserSession) @@ -69,9 +57,6 @@ public function getPlayer(): ?Player return null; } - /** - * @return int - */ public function getType(): int { return $this->type; diff --git a/src/xenialdan/MagicWE2/helper/AsyncWorld.php b/src/xenialdan/MagicWE2/helper/AsyncWorld.php index 1cb44d8..1a59b92 100644 --- a/src/xenialdan/MagicWE2/helper/AsyncWorld.php +++ b/src/xenialdan/MagicWE2/helper/AsyncWorld.php @@ -7,15 +7,19 @@ use pocketmine\world\format\Chunk; use pocketmine\world\SimpleChunkManager; use pocketmine\world\World; +use RuntimeException; +use xenialdan\MagicWE2\exception\SelectionException; use xenialdan\MagicWE2\selection\Selection; -class AsyncWorld extends SimpleChunkManager -{ +class AsyncWorld extends SimpleChunkManager{ // /** @var CompoundTag[] *///TODO maybe CacheableNbt // protected array $tiles = []; - public function __construct(Selection $selection) - { + /** + * @throws SelectionException + * @throws RuntimeException + */ + public function __construct(Selection $selection){ parent::__construct(World::Y_MIN, World::Y_MAX); $this->copyChunks($selection); } @@ -23,14 +27,15 @@ public function __construct(Selection $selection) /** * @return Chunk[] */ - public function getChunks(): array - { + public function getChunks() : array{ return $this->chunks; } - public function copyChunks(Selection $selection): void - { - if (!$selection->isValid()) return; + /** + * @throws SelectionException|RuntimeException + */ + public function copyChunks(Selection $selection) : void{ + if(!$selection->isValid()) return; $this->cleanChunks(); $shape = $selection->getShape(); diff --git a/src/xenialdan/MagicWE2/helper/Scoreboard.php b/src/xenialdan/MagicWE2/helper/Scoreboard.php index 1f18bea..1285d19 100644 --- a/src/xenialdan/MagicWE2/helper/Scoreboard.php +++ b/src/xenialdan/MagicWE2/helper/Scoreboard.php @@ -11,8 +11,10 @@ use pocketmine\utils\TextFormat as TF; use ReflectionClass; use ReflectionException; +use RuntimeException; use xenialdan\MagicWE2\API; use xenialdan\MagicWE2\clipboard\SingleClipboard; +use xenialdan\MagicWE2\exception\SelectionException; use xenialdan\MagicWE2\Loader; use xenialdan\MagicWE2\selection\Selection; use xenialdan\MagicWE2\session\UserSession; @@ -24,17 +26,20 @@ public function handleScoreboard(UserSession $session) : void{ try{ ScoreFactory::setObjective($player, Loader::PREFIX . TF::BOLD . TF::LIGHT_PURPLE . "Sidebar", SetDisplayObjectivePacket::SORT_ORDER_ASCENDING, SetDisplayObjectivePacket::DISPLAY_SLOT_SIDEBAR, "MWE_sidebar_default"); ScoreFactory::sendObjective($player); - if($session->getLatestSelection() !== null){ + if(($selection = $session->getLatestSelection()) !== null){ $line = 0; - $selection = $session->getLatestSelection(); ScoreFactory::setScoreLine($player, ++$line, TF::GOLD . $session->getLanguage()->translateString("spacer", ["Selection"])); - ScoreFactory::setScoreLine($player, ++$line, TF::BOLD . " Position: " . TF::RESET . API::vecToString($selection->getPos1()->asVector3()) . " » " . API::vecToString($selection->getPos2()->asVector3())); + try{ + ScoreFactory::setScoreLine($player, ++$line, TF::BOLD . " Position: " . TF::RESET . API::vecToString($selection->getPos1()->asVector3()) . " » " . API::vecToString($selection->getPos2()->asVector3())); + }catch(SelectionException | RuntimeException | ScoreFactoryException){ + } ScoreFactory::setScoreLine($player, ++$line, TF::BOLD . " World: " . TF::RESET . $selection->getWorld()->getFolderName()); if($selection->shape === null) ScoreFactory::setScoreLine($player, ++$line, TF::BOLD . " Shape: " . TF::RESET . 'N/A'); - else + else{ ScoreFactory::setScoreLine($player, ++$line, TF::BOLD . " Shape: " . TF::RESET . (new ReflectionClass($selection->shape))->getShortName()); - ScoreFactory::setScoreLine($player, ++$line, TF::BOLD . " Size: " . TF::RESET . API::vecToString(new Vector3($selection->getSizeX(), $selection->getSizeY(), $selection->getSizeZ())) . " ({$selection->getShape()->getTotalCount()})"); + ScoreFactory::setScoreLine($player, ++$line, TF::BOLD . " Size: " . TF::RESET . API::vecToString(new Vector3($selection->getSizeX(), $selection->getSizeY(), $selection->getSizeZ())) . " ({$selection->shape->getTotalCount()})"); + } ScoreFactory::setScoreLine($player, ++$line, TF::GOLD . $session->getLanguage()->translateString("spacer", ["Settings"])); ScoreFactory::setScoreLine($player, ++$line, TF::BOLD . " Tool Range: " . TF::RESET . Loader::getInstance()->getToolDistance()); diff --git a/src/xenialdan/MagicWE2/helper/SessionHelper.php b/src/xenialdan/MagicWE2/helper/SessionHelper.php index 63674f9..24c4b2c 100644 --- a/src/xenialdan/MagicWE2/helper/SessionHelper.php +++ b/src/xenialdan/MagicWE2/helper/SessionHelper.php @@ -30,17 +30,16 @@ use function array_filter; use function array_values; use function count; +use function var_dump; -class SessionHelper -{ +class SessionHelper{ /** @var array */ private static array $userSessions = []; /** @var array */ private static array $pluginSessions = []; - public static function init(): void - { - if (!@mkdir($concurrentDirectory = Loader::getInstance()->getDataFolder() . "sessions") && !is_dir($concurrentDirectory)) { + public static function init() : void{ + if(!@mkdir($concurrentDirectory = Loader::getInstance()->getDataFolder() . "sessions") && !is_dir($concurrentDirectory)){ throw new RuntimeException(sprintf('Directory "%s" was not created', $concurrentDirectory)); } } @@ -51,32 +50,32 @@ public static function init(): void * @throws InvalidSkinException * @throws JsonException */ - public static function addSession(Session $session): void - { - if ($session instanceof UserSession) { + public static function addSession(Session $session) : void{ + if($session instanceof UserSession){ self::$userSessions[$session->getUUID()->toString()] = $session; - if (!empty(Loader::getInstance()->donatorData) && (($player = $session->getPlayer())->hasPermission("we.donator") || in_array($player->getName(), Loader::getInstance()->donators))) { + if(!empty(Loader::getInstance()->donatorData) && (($player = $session->getPlayer())->hasPermission("we.donator") || in_array($player->getName(), Loader::getInstance()->donators))){ $oldSkin = $player->getSkin(); $newSkin = new Skin($oldSkin->getSkinId(), $oldSkin->getSkinData(), Loader::getInstance()->donatorData, $oldSkin->getGeometryName(), $oldSkin->getGeometryData()); $player->setSkin($newSkin); $player->sendSkin(); } - } else if ($session instanceof PluginSession) self::$pluginSessions[$session->getUUID()->toString()] = $session; + }else if($session instanceof PluginSession) self::$pluginSessions[$session->getUUID()->toString()] = $session; } /** * Destroys a session and removes it from cache. Saves to file if $save is true + * * @param Session $session - * @param bool $save + * @param bool $save + * * @throws JsonException */ - public static function destroySession(Session $session, bool $save = true): void - { - if ($session instanceof UserSession) { + public static function destroySession(Session $session, bool $save = true) : void{ + if($session instanceof UserSession){ $session->cleanupInventory(); unset(self::$userSessions[$session->getUUID()->toString()]); - } else if ($session instanceof PluginSession) unset(self::$pluginSessions[($session->getUUID()->toString())]); - if ($save && $session instanceof UserSession) { + }else if($session instanceof PluginSession) unset(self::$pluginSessions[($session->getUUID()->toString())]); + if($save && $session instanceof UserSession){ $session->save(); } } @@ -93,11 +92,10 @@ public static function destroySession(Session $session, bool $save = true): void * @throws SessionException*@throws JsonException * @throws JsonException */ - public static function createUserSession(Player $player, bool $add = true): UserSession - { - if (!$player->hasPermission("we.session")) throw new SessionException(TF::RED . "You do not have the permission \"magicwe.session\""); + public static function createUserSession(Player $player, bool $add = true) : UserSession{ + if(!$player->hasPermission("we.session")) throw new SessionException(TF::RED . "You do not have the permission \"magicwe.session\""); $session = new UserSession($player); - if ($add) { + if($add){ self::addSession($session); (new MWESessionLoadEvent(Loader::getInstance(), $session))->call(); } @@ -114,142 +112,142 @@ public static function createUserSession(Player $player, bool $add = true): User * @throws InvalidSkinException*@throws JsonException * @throws JsonException */ - public static function createPluginSession(Plugin $plugin, bool $add = true): PluginSession - { + public static function createPluginSession(Plugin $plugin, bool $add = true) : PluginSession{ $session = new PluginSession($plugin); - if ($add) self::addSession($session); + if($add) self::addSession($session); return $session; } /** * @param Player $player + * * @return bool */ - public static function hasSession(Player $player): bool - { - try { + public static function hasSession(Player $player) : bool{ + try{ return self::getUserSession($player) instanceof UserSession; - } catch (SessionException) { + }catch(SessionException){ return false; } } /** * @param Player $player + * * @return null|UserSession * @throws SessionException */ - public static function getUserSession(Player $player): ?UserSession - { - if (count(self::$userSessions) === 0) return null; - $filtered = array_filter(self::$userSessions, function (Session $session) use ($player) { + public static function getUserSession(Player $player) : ?UserSession{ + if(count(self::$userSessions) === 0) return null; + $filtered = array_filter(self::$userSessions, function(Session $session) use ($player){ return $session instanceof UserSession && $session->getPlayer() === $player; }); - if (count($filtered) === 0) return null; - if (count($filtered) > 1) throw new SessionException("Multiple sessions found for player {$player->getName()}. This should never happen!"); + if(count($filtered) === 0) return null; + if(count($filtered) > 1) throw new SessionException("Multiple sessions found for player {$player->getName()}. This should never happen!"); return array_values($filtered)[0]; } /** * TODO cleanup or optimize + * * @param UuidInterface $uuid + * * @return null|Session * @throws SessionException */ - public static function getSessionByUUID(UuidInterface $uuid): ?Session - { + public static function getSessionByUUID(UuidInterface $uuid) : ?Session{ $v = self::$userSessions[$uuid->toString()] ?? self::$pluginSessions[$uuid->toString()] ?? null; - if (!$v instanceof Session) throw new SessionException("Session with uuid {$uuid->toString()} not found"); + if(!$v instanceof Session) throw new SessionException("Session with uuid {$uuid->toString()} not found"); return $v; } /** * @return array */ - public static function getUserSessions(): array - { + public static function getUserSessions() : array{ return self::$userSessions; } /** * @return array */ - public static function getPluginSessions(): array - { + public static function getPluginSessions() : array{ return self::$pluginSessions; } /** * @param Player $player + * * @return UserSession|null * @throws InvalidSkinException * @throws JsonException * @throws RuntimeException + * + * TODO use libmarshal */ - public static function loadUserSession(Player $player): ?UserSession - { - $path = Loader::getInstance()->getDataFolder() . "sessions" . DIRECTORY_SEPARATOR . - $player->getName() . ".json"; - if (!file_exists($path)) return null; + public static function loadUserSession(Player $player) : ?UserSession{ + $path = Loader::getInstance()->getDataFolder() . "sessions" . DIRECTORY_SEPARATOR . $player->getName() . ".json"; + if(!file_exists($path)) return null; $contents = file_get_contents($path); - if ($contents === false) return null; + if($contents === false) return null; $data = json_decode($contents, true, 512, JSON_THROW_ON_ERROR); - if (is_null($data) || json_last_error() !== JSON_ERROR_NONE) { + if(is_null($data) || json_last_error() !== JSON_ERROR_NONE){ Loader::getInstance()->getLogger()->error("Could not load user session from json file $path: " . json_last_error_msg()); #unlink($path);//TODO make safe return null; } $session = new UserSession($player); - try { + try{ $session->setUUID(UuidV4::fromString($data["uuid"])); $session->setWandEnabled($data["wandEnabled"]); $session->setDebugToolEnabled($data["debugToolEnabled"]); $session->setWailaEnabled($data["wailaEnabled"]); $session->setSidebarEnabled($data["sidebarEnabled"]); $session->setLanguage($data["language"]); - foreach ($data["brushes"] as $brushJson) { - try { + foreach($data["brushes"] as $brushJson){ + try{ $properties = BrushProperties::fromJson($brushJson["properties"]); $brush = new Brush($properties); $session->getBrushes()->addBrush($brush); - } catch (InvalidArgumentException) { + }catch(InvalidArgumentException){ continue; } } - if (!is_null(($latestSelection = $data["latestSelection"] ?? null))) { - try { + if(!is_null(($latestSelection = $data["latestSelection"] ?? null))){ + try{ $world = Server::getInstance()->getWorldManager()->getWorld($latestSelection["worldId"]); - if (is_null($world)) { + if(is_null($world)){ $session->sendMessage(TF::RED . "The world of the saved sessions selection is not loaded, the last selection was not restored.");//TODO translate better - } else { + }else{ $shapeClass = $latestSelection["shapeClass"] ?? Cuboid::class; - $pasteVector = $latestSelection["shape"]["pasteVector"]; + $pasteVector = $latestSelection["shape"]["pasteVector"] ?? null; unset($latestSelection["shape"]["pasteVector"]); - if (!is_null($pasteVector)) { + if(!is_null($pasteVector)){ $pasteV = new Vector3(...array_values($pasteVector)); - $shape = new $shapeClass($pasteV, ...array_values($latestSelection["shape"])); + $shape = new $shapeClass($pasteV, ...array_values($latestSelection["shape"]));//TODO why is this done this way } $selection = new Selection( $session->getUUID(), - Server::getInstance()->getWorldManager()->getWorld($latestSelection["worldId"]), - $latestSelection["pos1"]["x"], - $latestSelection["pos1"]["y"], - $latestSelection["pos1"]["z"], - $latestSelection["pos2"]["x"], - $latestSelection["pos2"]["y"], - $latestSelection["pos2"]["z"], + $world, + isset($latestSelection["pos1"]) ? new Vector3($latestSelection["pos1"]["x"], $latestSelection["pos1"]["y"], $latestSelection["pos1"]["z"]) : null, + isset($latestSelection["pos2"]) ? new Vector3($latestSelection["pos2"]["x"], $latestSelection["pos2"]["y"], $latestSelection["pos2"]["z"]) : null, $shape ?? null ); - if ($selection->isValid()) { + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); + if($selection->isValid()){ + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $session->addSelection($selection); + var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); } } - } catch (RuntimeException) { + }catch(RuntimeException $e){ + Loader::getInstance()->getLogger()->logException($e); } } $session->setOutlineEnabled($data["outlineEnabled"]); //TODO clipboard - } catch (Exception) { + }catch(Exception $e){ + Loader::getInstance()->getLogger()->logException($e); return null; } self::addSession($session); diff --git a/src/xenialdan/MagicWE2/selection/Selection.php b/src/xenialdan/MagicWE2/selection/Selection.php index d8ffa4d..20f7fc3 100644 --- a/src/xenialdan/MagicWE2/selection/Selection.php +++ b/src/xenialdan/MagicWE2/selection/Selection.php @@ -22,82 +22,63 @@ use xenialdan\MagicWE2\helper\AsyncWorld; use xenialdan\MagicWE2\helper\SessionHelper; use xenialdan\MagicWE2\helper\SubChunkIterator; +use xenialdan\MagicWE2\Loader; use xenialdan\MagicWE2\selection\shape\Cuboid; use xenialdan\MagicWE2\selection\shape\Shape; use xenialdan\MagicWE2\session\Session; +use function var_dump; /** * Class Selection * @package xenialdan\MagicWE2 */ -class Selection implements Serializable, JsonSerializable -{ - /** @var int|null */ +class Selection implements Serializable, JsonSerializable{ public ?int $worldId = null; - /** @var Vector3|null */ public ?Vector3 $pos1 = null; - /** @var Vector3|null */ public ?Vector3 $pos2 = null; - /** @var UuidInterface */ public UuidInterface $uuid; - /** @var UuidInterface */ public UuidInterface $sessionUUID; - /** @var Shape|null */ public ?Shape $shape = null; private SubChunkIterator $iterator; - /** - * Selection constructor. - * @param UuidInterface $sessionUUID - * @param World $world - * @param ?int $minX - * @param ?int $minY - * @param ?int $minZ - * @param ?int $maxX - * @param ?int $maxY - * @param ?int $maxZ - * @param ?Shape $shape - */ - public function __construct(UuidInterface $sessionUUID, World $world, ?int $minX = null, ?int $minY = null, ?int $minZ = null, ?int $maxX = null, ?int $maxY = null, ?int $maxZ = null, ?Shape $shape = null) - { + public function __construct(UuidInterface $sessionUUID, World $world, ?Vector3 $minPos = null, ?Vector3 $maxPos = null, ?Shape $shape = null){ $this->sessionUUID = $sessionUUID; $this->worldId = $world->getId(); - if (isset($minX, $minY, $minZ)) { - $this->pos1 = (new Vector3($minX, $minY, $minZ))->floor(); - } - if (isset($maxX, $maxY, $maxZ)) { - $this->pos2 = (new Vector3($maxX, $maxY, $maxZ))->floor(); - } - if ($shape !== null) $this->shape = $shape; + if($minPos !== null) $minPos = $minPos->floor(); + if($maxPos !== null) $maxPos = $maxPos->floor(); + $this->pos1 = $minPos; + $this->pos2 = $maxPos; + $this->shape = $shape; $this->setUUID(Uuid::uuid4()); - try { + try{ (new MWESelectionChangeEvent($this, MWESelectionChangeEvent::TYPE_CREATE))->call(); - } catch (RuntimeException) { + }catch(RuntimeException $e){ + Loader::getInstance()->getLogger()->logException($e); } + var_dump($this); + $this->iterator = new SubChunkIterator(new AsyncWorld($this)); } - public function free(): void - { + public function free() : void{ $this->iterator->invalidate(); $manager = $this->iterator->getManager(); - if ($manager instanceof AsyncWorld) $manager->cleanChunks(); + if($manager instanceof AsyncWorld) $manager->cleanChunks(); } /** * @return World - * @throws Exception + * @throws SelectionException|RuntimeException */ - public function getWorld(): World - { - if (is_null($this->worldId)) { + public function getWorld() : World{ + if(is_null($this->worldId)){ throw new SelectionException("World is not set!"); } $world = Server::getInstance()->getWorldManager()->getWorld($this->worldId); - if (is_null($world)) { + if(is_null($world)){ throw new SelectionException("World is not found!"); } return $world; @@ -108,22 +89,22 @@ public function setWorld(World $world) : void{ return; } $this->worldId = $world->getId(); - try { + try{ (new MWESelectionChangeEvent($this, MWESelectionChangeEvent::TYPE_WORLD))->call(); - } catch (RuntimeException) { + }catch(RuntimeException $e){ + Loader::getInstance()->getLogger()->logException($e); } $this->free(); $manager = $this->getIterator()->getManager(); - if ($manager instanceof AsyncWorld) $manager->copyChunks($this); + if($manager instanceof AsyncWorld) $manager->copyChunks($this); } /** * @return Position - * @throws Exception + * @throws SelectionException|RuntimeException */ - public function getPos1(): Position - { - if (is_null($this->pos1)) { + public function getPos1() : Position{ + if(is_null($this->pos1)){ throw new SelectionException("Position 1 is not set!"); } return Position::fromObject($this->pos1, $this->getWorld()); @@ -131,10 +112,10 @@ public function getPos1(): Position /** * @param Position $position + * * @throws AssumptionFailedError */ - public function setPos1(Position $position): void - { + public function setPos1(Position $position) : void{ $this->pos1 = $position->asVector3()->floor(); if ($this->pos1->y >= World::Y_MAX) $this->pos1->y = World::Y_MAX; if ($this->pos1->y < 0) $this->pos1->y = 0; @@ -142,32 +123,36 @@ public function setPos1(Position $position): void $this->pos2 = null; } $this->setWorld($position->getWorld()); - if (($this->shape instanceof Cuboid || $this->shape === null) && $this->isValid())//TODO test change + var_dump($this); + if(($this->shape === null || $this->shape instanceof Cuboid) && $this->isValid()) $this->setShape(Cuboid::constructFromPositions($this->pos1, $this->pos2)); - try { + var_dump($this); + try{ $session = SessionHelper::getSessionByUUID($this->sessionUUID); - if ($session instanceof Session) { + if($session instanceof Session){ $session->sendMessage(TF::GREEN . $session->getLanguage()->translateString('selection.pos1.set', [$this->pos1->getX(), $this->pos1->getY(), $this->pos1->getZ()])); - try { + try{ (new MWESelectionChangeEvent($this, MWESelectionChangeEvent::TYPE_POS1))->call(); - } catch (RuntimeException) { + }catch(RuntimeException $e){ + Loader::getInstance()->getLogger()->logException($e); } $this->free(); $manager = $this->getIterator()->getManager(); - if ($manager instanceof AsyncWorld) $manager->copyChunks($this); + if($manager instanceof AsyncWorld) $manager->copyChunks($this); } - } catch (SessionException) { + }catch(SessionException){ //TODO log? kick? + }catch(SelectionException | RuntimeException $e){ + Loader::getInstance()->getLogger()->logException($e); } } /** * @return Position - * @throws Exception + * @throws SelectionException|RuntimeException */ - public function getPos2(): Position - { - if (is_null($this->pos2)) { + public function getPos2() : Position{ + if(is_null($this->pos2)){ throw new SelectionException("Position 2 is not set!"); } return Position::fromObject($this->pos2, $this->getWorld()); @@ -175,10 +160,8 @@ public function getPos2(): Position /** * @param Position $position - * @throws AssumptionFailedError */ - public function setPos2(Position $position): void - { + public function setPos2(Position $position) : void{ $this->pos2 = $position->asVector3()->floor(); if ($this->pos2->y >= World::Y_MAX) $this->pos2->y = World::Y_MAX; if ($this->pos2->y < 0) $this->pos2->y = 0; @@ -186,45 +169,48 @@ public function setPos2(Position $position): void $this->pos1 = null; } $this->setWorld($position->getWorld()); - if (($this->shape instanceof Cuboid || $this->shape === null) && $this->isValid()) + var_dump($this); + if(($this->shape === null || $this->shape instanceof Cuboid) && $this->isValid()) $this->setShape(Cuboid::constructFromPositions($this->pos1, $this->pos2)); - try { + var_dump($this); + try{ $session = SessionHelper::getSessionByUUID($this->sessionUUID); - if ($session instanceof Session) { + if($session instanceof Session){ $session->sendMessage(TF::GREEN . $session->getLanguage()->translateString('selection.pos2.set', [$this->pos2->getX(), $this->pos2->getY(), $this->pos2->getZ()])); - try { + try{ (new MWESelectionChangeEvent($this, MWESelectionChangeEvent::TYPE_POS2))->call(); - } catch (RuntimeException) { + }catch(RuntimeException $e){ + Loader::getInstance()->getLogger()->logException($e); } $this->free(); $manager = $this->getIterator()->getManager(); - if ($manager instanceof AsyncWorld) $manager->copyChunks($this); + if($manager instanceof AsyncWorld) $manager->copyChunks($this); } - } catch (SessionException) { - //TODO log? kick? + }catch(SessionException | SelectionException | RuntimeException $e){//TODO log? kick? + Loader::getInstance()->getLogger()->logException($e); } } /** * @return Shape - * @throws Exception + * @throws SelectionException */ - public function getShape(): Shape - { - if (!$this->shape instanceof Shape) throw new SelectionException("Shape is not valid"); + public function getShape() : Shape{ + if(!$this->shape instanceof Shape) throw new SelectionException("Shape is not valid"); return $this->shape; } - public function setShape(Shape $shape): void - { + public function setShape(Shape $shape) : void{ + var_dump($shape); $this->shape = $shape; - try { - (new MWESelectionChangeEvent($this, MWESelectionChangeEvent::TYPE_SHAPE))->call(); - } catch (RuntimeException) { - }//might cause duplicated call - $this->free(); - $manager = $this->getIterator()->getManager(); - if ($manager instanceof AsyncWorld) $manager->copyChunks($this); + try{ + (new MWESelectionChangeEvent($this, MWESelectionChangeEvent::TYPE_SHAPE))->call();//might cause duplicated call + $this->free(); + $manager = $this->getIterator()->getManager(); + if($manager instanceof AsyncWorld) $manager->copyChunks($this); + }catch(RuntimeException | SelectionException $e){ + Loader::getInstance()->getLogger()->debug($e); + } } /** @@ -235,46 +221,41 @@ public function setShape(Shape $shape): void * - The positions are not in the same world * @return bool */ - public function isValid(): bool - { - try { - #$this->getShape(); + public function isValid() : bool{ + try{ + var_dump("World: " . $this->getWorld()->getId() . " Pos1: " . $this->pos1 . " Pos2: " . $this->pos2 . " Shape: " . $this->shape?->serialize()); + //$this->getShape(); $this->getWorld(); $this->getPos1(); $this->getPos2(); - } catch (Exception) { + }catch(Exception $e){ + Loader::getInstance()->getLogger()->debug($e); return false; } return true; } - public function getSizeX(): int - { - return (int)(abs($this->pos1->x - $this->pos2->x) + 1); + public function getSizeX() : int{ + return (int) (abs($this->pos1->x - $this->pos2->x) + 1); } - public function getSizeY(): int - { - return (int)(abs($this->pos1->y - $this->pos2->y) + 1); + public function getSizeY() : int{ + return (int) (abs($this->pos1->y - $this->pos2->y) + 1); } - public function getSizeZ(): int - { - return (int)(abs($this->pos1->z - $this->pos2->z) + 1); + public function getSizeZ() : int{ + return (int) (abs($this->pos1->z - $this->pos2->z) + 1); } - public function setUUID(UuidInterface $uuid): void - { + public function setUUID(UuidInterface $uuid) : void{ $this->uuid = $uuid; } - public function getUUID(): UuidInterface - { + public function getUUID() : UuidInterface{ return $this->uuid; } - public function getIterator(): SubChunkIterator - { + public function getIterator() : SubChunkIterator{ return $this->iterator; } @@ -284,8 +265,7 @@ public function getIterator(): SubChunkIterator * @return string the string representation of the object or null * @since 5.1.0 */ - public function serialize(): string - { + public function serialize() : string{ return serialize([ $this->worldId, $this->pos1, @@ -327,10 +307,9 @@ public function unserialize(string $data){ * which is a value of any type other than a resource. * @since 5.4.0 */ - public function jsonSerialize(): array - { - $arr = (array)$this; - if ($this->shape !== null) + public function jsonSerialize() : array{ + $arr = (array) $this; + if($this->shape !== null) $arr["shapeClass"] = get_class($this->shape); return $arr; } diff --git a/src/xenialdan/MagicWE2/selection/shape/Cone.php b/src/xenialdan/MagicWE2/selection/shape/Cone.php index d3aa6e8..bbd60f8 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Cone.php +++ b/src/xenialdan/MagicWE2/selection/shape/Cone.php @@ -36,28 +36,33 @@ public function __construct(Vector3 $pasteVector, int $height, int $diameter, bo $this->flipped = $flipped; } - public function offset(Vector3 $offset): Shape - { + public function offset(Vector3 $offset) : Shape{ $shape = clone $this; - $shape->setPasteVector($this->getPasteVector()->addVector($offset)); + $shape->setPasteVector($this->pasteVector->addVector($offset)); return $shape; } + public function rotate(int $rotation) : self{ + return clone $this; + } + /** * Returns the blocks by their actual position - * @param AsyncWorld $manager The world or AsyncChunkManager + * + * @param AsyncWorld $manager The world or AsyncChunkManager * @param BlockPalette $filterblocks If not empty, applying a filter on the block list + * * @return Block[]|Generator * @phpstan-return Generator * @noinspection PhpDocSignatureInspection */ - public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks): Generator + public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Generator { ##$reducePerLayer = ($this->diameter / $this->height); - $centerVec2 = new Vector2($this->getPasteVector()->getX(), $this->getPasteVector()->getZ()); - for ($x = (int)floor($centerVec2->x - $this->diameter / 2 - 1); $x <= floor($centerVec2->x + $this->diameter / 2 + 1); $x++) { - for ($y = (int)floor($this->getPasteVector()->y), $ry = 0; $y < floor($this->getPasteVector()->y + $this->height); $y++, $ry++) { - for ($z = (int)floor($centerVec2->y - $this->diameter / 2 - 1); $z <= floor($centerVec2->y + $this->diameter / 2 + 1); $z++) { + $centerVec2 = new Vector2($this->pasteVector->getX(), $this->pasteVector->getZ()); + for ($x = (int)floor($centerVec2->x - $this->diameter / 2 - 1); $x <= floor($centerVec2->x + $this->diameter / 2 + 1); $x++){ + for($y = (int) floor($this->pasteVector->y), $ry = 0; $y < floor($this->pasteVector->y + $this->height); $y++, $ry++){ + for($z = (int) floor($centerVec2->y - $this->diameter / 2 - 1); $z <= floor($centerVec2->y + $this->diameter / 2 + 1); $z++){ // $vec2 = new Vector2($x, $z); $vec3 = new Vector3($x, $y, $z); /*if ($this->flipped) @@ -66,7 +71,7 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks): Gene $radiusLayer = ($this->diameter - $reducePerLayer * $ry) / 2;*/ // if ($vec2->distanceSquared($centerVec2) > ($radiusLayer ** 2) || (API::hasFlag($flags, API::FLAG_HOLLOW_CLOSED) && ($ry !== 0 && $ry !== $this->height - 1) && $vec2->distanceSquared($centerVec2) <= ((($this->diameter / 2) - 1) ** 2)) || ((API::hasFlag($flags, API::FLAG_HOLLOW) && $vec2->distanceSquared($centerVec2) <= ((($this->diameter / 2) - 1) ** 2)))) // continue; - $block = API::setComponents($manager->getBlockAt($vec3->getFloorX(), $vec3->getFloorY(), $vec3->getFloorZ()), (int)$vec3->x, (int)$vec3->y, (int)$vec3->z); + $block = API::setComponents($manager->getBlockAt($vec3->getFloorX(), $vec3->getFloorY(), $vec3->getFloorZ()), (int) $vec3->x, (int) $vec3->y, (int) $vec3->z); // if (API::hasFlag($flags, API::FLAG_KEEP_BLOCKS) && $block->getId() !== BlockLegacyIds::AIR) continue; // if (API::hasFlag($flags, API::FLAG_KEEP_AIR) && $block->getId() === BlockLegacyIds::AIR) continue; @@ -90,9 +95,8 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks): Gene * @param int $flags * @return Generator */ - public function getLayer(AsyncWorld $manager, int $flags = API::FLAG_BASE): Generator - { - $centerVec2 = new Vector2($this->getPasteVector()->getX(), $this->getPasteVector()->getZ()); + public function getLayer(AsyncWorld $manager, int $flags = API::FLAG_BASE): Generator{ + $centerVec2 = new Vector2($this->pasteVector->getX(), $this->pasteVector->getZ()); for ($x = (int)floor($centerVec2->x - $this->diameter / 2 - 1); $x <= floor($centerVec2->x + $this->diameter / 2 + 1); $x++) { for ($z = (int)floor($centerVec2->y - $this->diameter / 2 - 1); $z <= floor($centerVec2->y + $this->diameter / 2 + 1); $z++) { $vec2 = new Vector2($x, $z); diff --git a/src/xenialdan/MagicWE2/selection/shape/Cube.php b/src/xenialdan/MagicWE2/selection/shape/Cube.php index 184f943..2b33af1 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Cube.php +++ b/src/xenialdan/MagicWE2/selection/shape/Cube.php @@ -23,22 +23,27 @@ public function __construct(Vector3 $pasteVector, int $width) $this->width = $width; } - public function offset(Vector3 $offset): Shape - { + public function offset(Vector3 $offset) : Shape{ $shape = clone $this; - $shape->setPasteVector($this->getPasteVector()->addVector($offset)); + $shape->setPasteVector($this->pasteVector->addVector($offset)); return $shape; } + public function rotate(int $rotation) : self{ + return clone $this; + } + /** * Returns the blocks by their actual position - * @param AsyncWorld $manager The world or AsyncChunkManager + * + * @param AsyncWorld $manager The world or AsyncChunkManager * @param BlockPalette $filterblocks If not empty, applying a filter on the block list + * * @return Block[]|Generator * @phpstan-return Generator * @noinspection PhpDocSignatureInspection */ - public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks): Generator + public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Generator { for ($x = (int)floor($this->getMinVec3()->x), $rx = 0; $x <= floor($this->getMaxVec3()->x); $x++, $rx++) { for ($y = (int)floor($this->getMinVec3()->y), $ry = 0; $y <= floor($this->getMaxVec3()->y); $y++, $ry++) { diff --git a/src/xenialdan/MagicWE2/selection/shape/Cuboid.php b/src/xenialdan/MagicWE2/selection/shape/Cuboid.php index 8798379..ad2f7c0 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Cuboid.php +++ b/src/xenialdan/MagicWE2/selection/shape/Cuboid.php @@ -3,6 +3,7 @@ namespace xenialdan\MagicWE2\selection\shape; use Generator; +use InvalidArgumentException; use pocketmine\block\Block; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Vector2; @@ -14,11 +15,8 @@ class Cuboid extends Shape { - /** @var int */ public int $width = 5; - /** @var int */ public int $height = 5; - /** @var int */ public int $depth = 5; /** @@ -36,30 +34,42 @@ public function __construct(Vector3 $pasteVector, int $width, int $height, int $ $this->depth = $depth; } - public static function constructFromPositions(Vector3 $pos1, Vector3 $pos2): self - { - $width = (int)abs($pos1->getX() - $pos2->getX()) + 1; - $height = (int)abs($pos1->getY() - $pos2->getY()) + 1; - $depth = (int)abs($pos1->getZ() - $pos2->getZ()) + 1; + public static function constructFromPositions(Vector3 $p1, Vector3 $p2) : self{ + $pos1 = Vector3::minComponents($p1, $p2); + $pos2 = Vector3::maxComponents($p1, $p2); + $width = (int) abs($pos1->getX() - $pos2->getX()) + 1; + $height = (int) abs($pos1->getY() - $pos2->getY()) + 1; + $depth = (int) abs($pos1->getZ() - $pos2->getZ()) + 1; return new Cuboid((new Vector3(($pos1->x + $pos2->x) / 2, min($pos1->y, $pos2->y), ($pos1->z + $pos2->z) / 2)), $width, $height, $depth); } - public function offset(Vector3 $offset): Shape - { + public function offset(Vector3 $offset) : Shape{ $shape = clone $this; - $shape->setPasteVector($this->getPasteVector()->addVector($offset)); + $shape->setPasteVector($this->pasteVector->addVector($offset)); return $shape; } + public function rotate(int $rotation) : self{ + if($rotation % 90 !== 0){ + throw new InvalidArgumentException("Rotation must be divisible by 90"); + } + return match ($rotation % 180 === 0) { + true => clone $this, + false => new self($this->pasteVector, $this->depth, $this->height, $this->width) + }; + } + /** * Returns the blocks by their actual position - * @param AsyncWorld $manager The world or AsyncChunkManager + * + * @param AsyncWorld $manager The world or AsyncChunkManager * @param BlockPalette $filterblocks If not empty, applying a filter on the block list + * * @return Block[]|Generator * @phpstan-return Generator * @noinspection PhpDocSignatureInspection */ - public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks): Generator + public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Generator { for ($x = (int)floor($this->getMinVec3()->x); $x <= floor($this->getMaxVec3()->x); $x++) { for ($y = (int)floor($this->getMinVec3()->y); $y <= floor($this->getMaxVec3()->y); $y++) { @@ -111,9 +121,6 @@ public function getAABB(): AxisAlignedBB ); } - /** - * @return int - */ public function getTotalCount(): int { return $this->width * $this->height * $this->depth; diff --git a/src/xenialdan/MagicWE2/selection/shape/Custom.php b/src/xenialdan/MagicWE2/selection/shape/Custom.php index 3050184..84129ad 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Custom.php +++ b/src/xenialdan/MagicWE2/selection/shape/Custom.php @@ -3,6 +3,7 @@ namespace xenialdan\MagicWE2\selection\shape; use Generator; +use InvalidArgumentException; use pocketmine\block\Block; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Vector2; @@ -28,25 +29,30 @@ public function __construct(Vector3 $pasteVector, array $positions) $this->positions = $positions; } - public function offset(Vector3 $offset): Shape - { + public function offset(Vector3 $offset) : Shape{ $shape = clone $this; $pos = $this->positions; $this->positions = []; - foreach ($pos as $vector3)$this->positions[]=$vector3->addVector($offset); - $shape->setPasteVector($this->getPasteVector()->addVector($offset)); + foreach($pos as $vector3) $this->positions[] = $vector3->addVector($offset); + $shape->setPasteVector($this->pasteVector->addVector($offset)); return $shape; } + public function rotate(int $rotation) : self{ + throw new InvalidArgumentException("Rotation is not supported"); + } + /** * Returns the blocks by their actual position - * @param AsyncWorld $manager The world or AsyncChunkManager + * + * @param AsyncWorld $manager The world or AsyncChunkManager * @param BlockPalette $filterblocks If not empty, applying a filter on the block list + * * @return Block[]|Generator * @phpstan-return Generator * @noinspection PhpDocSignatureInspection */ - public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks): Generator + public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Generator { foreach ($this->positions as $position) { //TODO filterblocks diff --git a/src/xenialdan/MagicWE2/selection/shape/Cylinder.php b/src/xenialdan/MagicWE2/selection/shape/Cylinder.php index 3fafd59..f072ea2 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Cylinder.php +++ b/src/xenialdan/MagicWE2/selection/shape/Cylinder.php @@ -32,36 +32,40 @@ public function __construct(Vector3 $pasteVector, int $height, int $diameter) $this->diameter = $diameter; } - public function offset(Vector3 $offset): Shape - { + public function offset(Vector3 $offset) : Shape{ $shape = clone $this; - $shape->setPasteVector($this->getPasteVector()->addVector($offset)); + $shape->setPasteVector($this->pasteVector->addVector($offset)); return $shape; } + public function rotate(int $rotation) : self{ + return clone $this; + } + /** * Returns the blocks by their actual position - * @param AsyncWorld $manager The world or AsyncChunkManager + * + * @param AsyncWorld $manager The world or AsyncChunkManager * @param BlockPalette $filterblocks If not empty, applying a filter on the block list + * * @return Block[]|Generator * @phpstan-return Generator * @noinspection PhpDocSignatureInspection */ - public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks): Generator - { - $centerVec2 = new Vector2($this->getPasteVector()->getX(), $this->getPasteVector()->getZ()); - for ($x = (int)floor($centerVec2->x - $this->diameter / 2 - 1); $x <= floor($centerVec2->x + $this->diameter / 2 + 1); $x++) { - for ($y = (int)floor($this->getPasteVector()->y), $ry = 0; $y < floor($this->getPasteVector()->y + $this->height); $y++, $ry++) { - for ($z = (int)floor($centerVec2->y - $this->diameter / 2 - 1); $z <= floor($centerVec2->y + $this->diameter / 2 + 1); $z++) { + public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Generator{ + $centerVec2 = new Vector2($this->pasteVector->getX(), $this->pasteVector->getZ()); + for ($x = (int)floor($centerVec2->x - $this->diameter / 2 - 1); $x <= floor($centerVec2->x + $this->diameter / 2 + 1); $x++){ + for($y = (int) floor($this->pasteVector->y), $ry = 0; $y < floor($this->pasteVector->y + $this->height); $y++, $ry++){ + for($z = (int) floor($centerVec2->y - $this->diameter / 2 - 1); $z <= floor($centerVec2->y + $this->diameter / 2 + 1); $z++){ // $vec2 = new Vector2($x, $z); $vec3 = new Vector3($x, $y, $z); // if ($vec2->distanceSquared($centerVec2) > (($this->diameter / 2) ** 2) || (API::hasFlag($flags, API::FLAG_HOLLOW_CLOSED) && ($ry !== 0 && $ry !== $this->height - 1) && $vec2->distanceSquared($centerVec2) <= ((($this->diameter / 2) - 1) ** 2)) || ((API::hasFlag($flags, API::FLAG_HOLLOW) && $vec2->distanceSquared($centerVec2) <= ((($this->diameter / 2) - 1) ** 2)))) // continue; - $block = API::setComponents($manager->getBlockAt($vec3->getFloorX(), $vec3->getFloorY(), $vec3->getFloorZ()), (int)$vec3->x, (int)$vec3->y, (int)$vec3->z); + $block = API::setComponents($manager->getBlockAt($vec3->getFloorX(), $vec3->getFloorY(), $vec3->getFloorZ()), (int) $vec3->x, (int) $vec3->y, (int) $vec3->z); // if (API::hasFlag($flags, API::FLAG_KEEP_BLOCKS) && $block->getId() !== BlockLegacyIds::AIR) continue; // if (API::hasFlag($flags, API::FLAG_KEEP_AIR) && $block->getId() === BlockLegacyIds::AIR) continue; - if ($block->getPosition()->y >= World::Y_MAX || $block->getPosition()->y < 0) continue;//TODO fuufufufuuu + if($block->getPosition()->y >= World::Y_MAX || $block->getPosition()->y < 0) continue;//TODO fuufufufuuu if ($filterblocks->empty()) yield $block; else { foreach ($filterblocks->palette() as $filterblock) { @@ -81,9 +85,8 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks): Gene * @param int $flags * @return Generator */ - public function getLayer(AsyncWorld $manager, int $flags = API::FLAG_BASE): Generator - { - $centerVec2 = new Vector2($this->getPasteVector()->getX(), $this->getPasteVector()->getZ()); + public function getLayer(AsyncWorld $manager, int $flags = API::FLAG_BASE): Generator{ + $centerVec2 = new Vector2($this->pasteVector->getX(), $this->pasteVector->getZ()); for ($x = (int)floor($centerVec2->x - $this->diameter / 2 - 1); $x <= floor($centerVec2->x + $this->diameter / 2 + 1); $x++) { for ($z = (int)floor($centerVec2->y - $this->diameter / 2 - 1); $z <= floor($centerVec2->y + $this->diameter / 2 + 1); $z++) { $vec2 = new Vector2($x, $z); diff --git a/src/xenialdan/MagicWE2/selection/shape/Ellipsoid.php b/src/xenialdan/MagicWE2/selection/shape/Ellipsoid.php index 2becaea..f72dac4 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Ellipsoid.php +++ b/src/xenialdan/MagicWE2/selection/shape/Ellipsoid.php @@ -3,6 +3,7 @@ namespace xenialdan\MagicWE2\selection\shape; use Generator; +use InvalidArgumentException; use pocketmine\block\Block; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Vector2; @@ -36,25 +37,35 @@ public function __construct(Vector3 $pasteVector, int $width, int $height, int $ $this->depth = $depth; } - public function offset(Vector3 $offset): Shape - { + public function offset(Vector3 $offset) : Shape{ $shape = clone $this; - $shape->setPasteVector($this->getPasteVector()->addVector($offset)); + $shape->setPasteVector($this->pasteVector->addVector($offset)); return $shape; } + public function rotate(int $rotation) : self{ + if($rotation % 90 !== 0){ + throw new InvalidArgumentException("Rotation must be divisible by 90"); + } + return match ($rotation % 180 === 0) { + true => clone $this, + false => new self($this->pasteVector, $this->depth, $this->height, $this->width) + }; + } + /** * Returns the blocks by their actual position - * @param AsyncWorld $manager The world or AsyncChunkManager + * + * @param AsyncWorld $manager The world or AsyncChunkManager * @param BlockPalette $filterblocks If not empty, applying a filter on the block list + * * @return Block[]|Generator * @phpstan-return Generator * @noinspection PhpDocSignatureInspection */ - public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks): Generator - { - $centerVec2 = new Vector2($this->getPasteVector()->getX(), $this->getPasteVector()->getZ()); - $this->pasteVector = $this->getPasteVector()->add(0, -0.5, 0); + public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Generator{ + $centerVec2 = new Vector2($this->pasteVector->getX(), $this->pasteVector->getZ()); + $this->pasteVector = $this->pasteVector->add(0, -0.5, 0); $xrad = $this->width / 2; $yrad = $this->height / 2; @@ -68,15 +79,15 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks): Gene for ($x = (int)floor($centerVec2->x - $this->width / 2 /*- 1*/); $x <= floor($centerVec2->x + $this->width / 2 /*+ 1*/); $x++) { $xSquared = ($targetX - $x) ** 2; - for ($y = (int)floor($this->getPasteVector()->y) + 1, $ry = 0; $y <= floor($this->getPasteVector()->y + $this->height); $y++, $ry++) { + for($y = (int) floor($this->pasteVector->y) + 1, $ry = 0; $y <= floor($this->pasteVector->y + $this->height); $y++, $ry++){ $ySquared = ($targetY - $y + $yrad) ** 2; - for ($z = (int)floor($centerVec2->y - $this->depth / 2 /*- 1*/); $z <= floor($centerVec2->y + $this->depth / 2 /*+ 1*/); $z++) { + for($z = (int) floor($centerVec2->y - $this->depth / 2 /*- 1*/); $z <= floor($centerVec2->y + $this->depth / 2 /*+ 1*/); $z++){ $zSquared = ($targetZ - $z) ** 2; $vec3 = new Vector3($x, $y, $z); //TODO hollow - if ($xSquared / $xradSquared + $ySquared / $yradSquared + $zSquared / $zradSquared >= 1) continue; - $block = API::setComponents($manager->getBlockAt($vec3->getFloorX(), $vec3->getFloorY(), $vec3->getFloorZ()), (int)$vec3->x, (int)$vec3->y, (int)$vec3->z); + if($xSquared / $xradSquared + $ySquared / $yradSquared + $zSquared / $zradSquared >= 1) continue; + $block = API::setComponents($manager->getBlockAt($vec3->getFloorX(), $vec3->getFloorY(), $vec3->getFloorZ()), (int) $vec3->x, (int) $vec3->y, (int) $vec3->z); // if (API::hasFlag($flags, API::FLAG_KEEP_BLOCKS) && $block->getId() !== BlockLegacyIds::AIR) continue; // if (API::hasFlag($flags, API::FLAG_KEEP_AIR) && $block->getId() === BlockLegacyIds::AIR) continue; @@ -100,9 +111,8 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks): Gene * @param int $flags * @return Generator */ - public function getLayer(AsyncWorld $manager, int $flags = API::FLAG_BASE): Generator - { - $centerVec2 = new Vector2($this->getPasteVector()->getX(), $this->getPasteVector()->getZ()); + public function getLayer(AsyncWorld $manager, int $flags = API::FLAG_BASE): Generator{ + $centerVec2 = new Vector2($this->pasteVector->getX(), $this->pasteVector->getZ()); $xrad = $this->width / 2; $zrad = $this->depth / 2; diff --git a/src/xenialdan/MagicWE2/selection/shape/Pyramid.php b/src/xenialdan/MagicWE2/selection/shape/Pyramid.php index ea87ae4..61692a4 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Pyramid.php +++ b/src/xenialdan/MagicWE2/selection/shape/Pyramid.php @@ -3,6 +3,7 @@ namespace xenialdan\MagicWE2\selection\shape; use Generator; +use InvalidArgumentException; use pocketmine\block\Block; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Vector2; @@ -12,8 +13,7 @@ use xenialdan\MagicWE2\helper\AsyncWorld; use xenialdan\MagicWE2\helper\BlockPalette; -class Pyramid extends Shape -{ +class Pyramid extends Shape{ /** @var int */ public int $width = 5; /** @var int */ @@ -25,14 +25,14 @@ class Pyramid extends Shape /** * Pyramid constructor. + * * @param Vector3 $pasteVector - * @param int $width - * @param int $height - * @param int $depth - * @param bool $flipped + * @param int $width + * @param int $height + * @param int $depth + * @param bool $flipped */ - public function __construct(Vector3 $pasteVector, int $width, int $height, int $depth, bool $flipped = false) - { + public function __construct(Vector3 $pasteVector, int $width, int $height, int $depth, bool $flipped = false){ $this->pasteVector = $pasteVector; $this->width = $width; $this->height = $height; @@ -40,51 +40,61 @@ public function __construct(Vector3 $pasteVector, int $width, int $height, int $ $this->flipped = $flipped; } - public function offset(Vector3 $offset): Shape - { + public function offset(Vector3 $offset) : Shape{ $shape = clone $this; - $shape->setPasteVector($this->getPasteVector()->addVector($offset)); + $shape->setPasteVector($this->pasteVector->addVector($offset)); return $shape; } + public function rotate(int $rotation) : self{ + if($rotation % 90 !== 0){ + throw new InvalidArgumentException("Rotation must be divisible by 90"); + } + return match ($rotation % 180 === 0) { + true => clone $this, + false => new self($this->pasteVector, $this->depth, $this->height, $this->width, $this->flipped) + }; + } + /** * Returns the blocks by their actual position - * @param AsyncWorld $manager The world or AsyncChunkManager + * + * @param AsyncWorld $manager The world or AsyncChunkManager * @param BlockPalette $filterblocks If not empty, applying a filter on the block list + * * @return Block[]|Generator * @phpstan-return Generator * @noinspection PhpDocSignatureInspection */ - public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks): Generator - { + public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Generator{ $reduceXPerLayer = -($this->width / $this->height); $reduceZPerLayer = -($this->depth / $this->height); - $centerVec2 = new Vector2($this->getPasteVector()->getX(), $this->getPasteVector()->getZ()); - for ($x = (int)floor($centerVec2->x - $this->width / 2 - 1); $x <= floor($centerVec2->x + $this->width / 2 + 1); $x++) { - for ($y = (int)floor($this->getPasteVector()->y), $ry = 0; $y < floor($this->getPasteVector()->y + $this->height); $y++, $ry++) { - for ($z = (int)floor($centerVec2->y - $this->depth / 2 - 1); $z <= floor($centerVec2->y + $this->depth / 2 + 1); $z++) { + $centerVec2 = new Vector2($this->pasteVector->getX(), $this->pasteVector->getZ()); + for($x = (int) floor($centerVec2->x - $this->width / 2 - 1); $x <= floor($centerVec2->x + $this->width / 2 + 1); $x++){ + for($y = (int) floor($this->pasteVector->y), $ry = 0; $y < floor($this->pasteVector->y + $this->height); $y++, $ry++){ + for($z = (int) floor($centerVec2->y - $this->depth / 2 - 1); $z <= floor($centerVec2->y + $this->depth / 2 + 1); $z++){ $vec2 = new Vector2($x, $z); $vec3 = new Vector3($x, $y, $z); - if ($this->flipped) { + if($this->flipped){ $radiusLayerX = ($this->width + $reduceXPerLayer * ($this->height - $ry)) / 2; $radiusLayerZ = ($this->depth + $reduceZPerLayer * ($this->height - $ry)) / 2; - } else { + }else{ $radiusLayerX = ($this->width + $reduceXPerLayer * $ry) / 2; $radiusLayerZ = ($this->depth + $reduceZPerLayer * $ry) / 2; } //TODO hollow - if (floor(abs($centerVec2->x - $vec2->x)) >= $radiusLayerX || floor(abs($centerVec2->y - $vec2->y)) >= $radiusLayerZ) + if(floor(abs($centerVec2->x - $vec2->x)) >= $radiusLayerX || floor(abs($centerVec2->y - $vec2->y)) >= $radiusLayerZ) continue; - $block = API::setComponents($manager->getBlockAt($vec3->getFloorX(), $vec3->getFloorY(), $vec3->getFloorZ()), (int)$vec3->x, (int)$vec3->y, (int)$vec3->z); + $block = API::setComponents($manager->getBlockAt($vec3->getFloorX(), $vec3->getFloorY(), $vec3->getFloorZ()), (int) $vec3->x, (int) $vec3->y, (int) $vec3->z); // if (API::hasFlag($flags, API::FLAG_KEEP_BLOCKS) && $block->getId() !== BlockLegacyIds::AIR) continue; // if (API::hasFlag($flags, API::FLAG_KEEP_AIR) && $block->getId() === BlockLegacyIds::AIR) continue; - if ($block->getPosition()->y >= World::Y_MAX || $block->getPosition()->y < 0) continue;//TODO fuufufufuuu - if ($filterblocks->empty()) yield $block; - else { - foreach ($filterblocks->palette() as $filterblock) { + if($block->getPosition()->y >= World::Y_MAX || $block->getPosition()->y < 0) continue;//TODO fuufufufuuu + if($filterblocks->empty()) yield $block; + else{ + foreach($filterblocks->palette() as $filterblock){ // if (($block->getId() === $filterblock->getId()) && ((API::hasFlag($flags, API::FLAG_VARIANT) && $block->getIdInfo()->getVariant() === $filterblock->getIdInfo()->getVariant()) || (!API::hasFlag($flags, API::FLAG_VARIANT) && ($block->getMeta() === $filterblock->getMeta() || API::hasFlag($flags, API::FLAG_KEEP_META))))) - if ($block->getFullId() === $filterblock->getFullId()) + if($block->getFullId() === $filterblock->getFullId()) yield $block; } } @@ -95,23 +105,23 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks): Gene /** * Returns a flat layer of all included x z positions in selection + * * @param AsyncWorld $manager The world or AsyncChunkManager - * @param int $flags + * @param int $flags + * * @return Generator */ - public function getLayer(AsyncWorld $manager, int $flags = API::FLAG_BASE): Generator - { - $centerVec2 = new Vector2($this->getPasteVector()->getX(), $this->getPasteVector()->getZ()); - for ($x = (int)floor($centerVec2->x - $this->width / 2 - 1); $x <= floor($centerVec2->x + $this->width / 2 + 1); $x++) { - for ($z = (int)floor($centerVec2->y - $this->depth / 2 - 1); $z <= floor($centerVec2->y + $this->depth / 2 + 1); $z++) { + public function getLayer(AsyncWorld $manager, int $flags = API::FLAG_BASE) : Generator{ + $centerVec2 = new Vector2($this->pasteVector->getX(), $this->pasteVector->getZ()); + for($x = (int) floor($centerVec2->x - $this->width / 2 - 1); $x <= floor($centerVec2->x + $this->width / 2 + 1); $x++){ + for($z = (int) floor($centerVec2->y - $this->depth / 2 - 1); $z <= floor($centerVec2->y + $this->depth / 2 + 1); $z++){ //TODO hollow yield new Vector2($x, $z); } } } - public function getAABB(): AxisAlignedBB - { + public function getAABB() : AxisAlignedBB{ return new AxisAlignedBB( floor($this->pasteVector->x - $this->width / 2), $this->pasteVector->y, @@ -122,13 +132,11 @@ public function getAABB(): AxisAlignedBB ); } - public function getTotalCount(): int - { - return (int)ceil((1 / 3) * ($this->width * $this->depth) * $this->height); + public function getTotalCount() : int{ + return (int) ceil((1 / 3) * ($this->width * $this->depth) * $this->height); } - public static function getName(): string - { + public static function getName() : string{ return "Pyramid"; } } \ No newline at end of file diff --git a/src/xenialdan/MagicWE2/selection/shape/Shape.php b/src/xenialdan/MagicWE2/selection/shape/Shape.php index 994cfde..4e4adfe 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Shape.php +++ b/src/xenialdan/MagicWE2/selection/shape/Shape.php @@ -69,22 +69,23 @@ public function getMaxVec3(): Vector3 return new Vector3($this->getAABB()->maxX, $this->getAABB()->maxY, $this->getAABB()->maxZ); } - abstract public static function getName(): string; + abstract public static function getName() : string; - public function getShapeProperties(): array - { + public function getShapeProperties() : array{ return array_diff(get_object_vars($this), get_class_vars(__CLASS__)); } + //TODO add Shape::flip() and Shape::rotate() + abstract public function rotate(int $rotation) : self; + /** * String representation of object * @link http://php.net/manual/en/serializable.serialize.php * @return string the string representation of the object or null * @since 5.1.0 */ - public function serialize(): string - { - return serialize((array)$this); + public function serialize() : string{ + return serialize((array) $this); } /** diff --git a/src/xenialdan/MagicWE2/selection/shape/Sphere.php b/src/xenialdan/MagicWE2/selection/shape/Sphere.php index c6f7b02..e436c9f 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Sphere.php +++ b/src/xenialdan/MagicWE2/selection/shape/Sphere.php @@ -28,28 +28,33 @@ public function __construct(Vector3 $pasteVector, int $diameter) $this->diameter = $diameter; } - public function offset(Vector3 $offset): Shape - { + public function offset(Vector3 $offset) : Shape{ $shape = clone $this; - $shape->setPasteVector($this->getPasteVector()->addVector($offset)); + $shape->setPasteVector($this->pasteVector->addVector($offset)); return $shape; } + public function rotate(int $rotation) : self{ + return clone $this; + } + /** * Returns the blocks by their actual position - * @param AsyncWorld $manager The world or AsyncChunkManager + * + * @param AsyncWorld $manager The world or AsyncChunkManager * @param BlockPalette $filterblocks If not empty, applying a filter on the block list + * * @return Block[]|Generator * @phpstan-return Generator * @noinspection PhpDocSignatureInspection */ - public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks): Generator + public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Generator { for ($x = (int)floor($this->pasteVector->x - $this->diameter / 2 - 1); $x <= floor($this->pasteVector->x + $this->diameter / 2 + 1); $x++) { for ($y = (int)floor($this->pasteVector->y - $this->diameter / 2 - 1); $y <= floor($this->pasteVector->y + $this->diameter / 2 + 1); $y++) { for ($z = (int)floor($this->pasteVector->z - $this->diameter / 2 - 1); $z <= floor($this->pasteVector->z + $this->diameter / 2 + 1); $z++) { $vec3 = new Vector3($x, $y, $z); -// if ($vec3->distanceSquared($this->getPasteVector()) > (($this->diameter / 2) ** 2) || (API::hasFlag(API::FLAG_BASE, API::FLAG_HOLLOW) && $vec3->distanceSquared($this->getPasteVector()) <= ((($this->diameter / 2) - 1) ** 2))) +// if ($vec3->distanceSquared($this->pasteVector) > (($this->diameter / 2) ** 2) || (API::hasFlag(API::FLAG_BASE, API::FLAG_HOLLOW) && $vec3->distanceSquared($this->pasteVector) <= ((($this->diameter / 2) - 1) ** 2))) // continue; $block = API::setComponents($manager->getBlockAt($vec3->getFloorX(), $vec3->getFloorY(), $vec3->getFloorZ()), (int)$vec3->x, (int)$vec3->y, (int)$vec3->z); // if (API::hasFlag(API::FLAG_BASE, API::FLAG_KEEP_BLOCKS) && $block->getId() !== BlockLegacyIds::AIR) continue; @@ -75,9 +80,8 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks): Gene * @param int $flags * @return Generator */ - public function getLayer(AsyncWorld $manager, int $flags = API::FLAG_BASE): Generator - { - $centerVec2 = new Vector2($this->getPasteVector()->getX(), $this->getPasteVector()->getZ()); + public function getLayer(AsyncWorld $manager, int $flags = API::FLAG_BASE): Generator{ + $centerVec2 = new Vector2($this->pasteVector->getX(), $this->pasteVector->getZ()); for ($x = (int)floor($centerVec2->x - $this->diameter / 2 - 1); $x <= floor($centerVec2->x + $this->diameter / 2 + 1); $x++) { for ($z = (int)floor($centerVec2->y - $this->diameter / 2 - 1); $z <= floor($centerVec2->y + $this->diameter / 2 + 1); $z++) { $vec2 = new Vector2($x, $z); diff --git a/src/xenialdan/MagicWE2/session/Session.php b/src/xenialdan/MagicWE2/session/Session.php index 4f50881..9ac0003 100644 --- a/src/xenialdan/MagicWE2/session/Session.php +++ b/src/xenialdan/MagicWE2/session/Session.php @@ -56,15 +56,10 @@ public function setUUID(UuidInterface $uuid): void $this->uuid = $uuid; } - /** - * @param Selection $selection - * @return null|Selection - */ - public function &addSelection(Selection $selection): ?Selection + public function addSelection(Selection $selection) : void//TODO why do i return the same thing? { $this->selections[$selection->getUUID()->toString()] = $selection; $this->setLatestSelectionUUID($selection->getUUID()); - return $this->getLatestSelection(); } /** diff --git a/src/xenialdan/MagicWE2/session/UserSession.php b/src/xenialdan/MagicWE2/session/UserSession.php index e51c74d..e08240c 100644 --- a/src/xenialdan/MagicWE2/session/UserSession.php +++ b/src/xenialdan/MagicWE2/session/UserSession.php @@ -62,14 +62,14 @@ public function __construct(Player $player) Loader::getInstance()->getLogger()->debug("Created new session for player {$player->getName()}"); } - /** - * @throws ScoreFactoryException - */ public function __destruct(){ Loader::getInstance()->getLogger()->debug("Destructing session {$this->getUUID()} for user " . $this->getPlayer()->getName()); $this->bossBar->removeAllPlayers(); if(Loader::hasScoreboard() && $this->sidebar !== null){ - ScoreFactory::removeObjective($this->getPlayer(), true); + try{ + ScoreFactory::removeObjective($this->getPlayer(), true); + }catch(ScoreFactoryException){ + } } } diff --git a/src/xenialdan/MagicWE2/session/data/Outline.php b/src/xenialdan/MagicWE2/session/data/Outline.php index cc52578..2ec010a 100644 --- a/src/xenialdan/MagicWE2/session/data/Outline.php +++ b/src/xenialdan/MagicWE2/session/data/Outline.php @@ -18,32 +18,30 @@ use xenialdan\libstructure\tile\StructureBlockTile; use xenialdan\MagicWE2\selection\Selection; -class Outline -{ +class Outline{ private Selection $selection; private Player $player; private Position $position; private Block $fakeBlock; private StructureBlockTile $fakeTile; - public function __construct(Selection $selection, Player $player) - { + public function __construct(Selection $selection, Player $player){ $this->selection = $selection; $this->player = $player; - $this->fakeBlock = BlockFactory::getInstance()->get(BlockLegacyIds::STRUCTURE_BLOCK); + /** @var BlockFactory $blockFactory */ + $blockFactory = BlockFactory::getInstance(); + $this->fakeBlock = $blockFactory->get(BlockLegacyIds::STRUCTURE_BLOCK, 0); $this->position = $this->updateBlockPosition(); $this->fakeTile = new StructureBlockTile($this->position->getWorld(), $this->position); $this->fakeTile->setShowBoundingBox(true)->setFromV3($selection->getPos1())->setToV3($selection->getPos2()); $this->send(); } - public function getSelection(): Selection - { + public function getSelection() : Selection{ return $this->selection; } - public function setSelection(Selection $selection): self - { + public function setSelection(Selection $selection) : self{ $this->selection = $selection; $this->remove(); $this->updatePosition(); @@ -54,35 +52,31 @@ public function setSelection(Selection $selection): self return $this; } - public function send(): void - { + public function send() : void{ $this->player->getNetworkSession()->sendDataPacket(UpdateBlockPacket::create(BlockPosition::fromVector3($this->position->asVector3()), RuntimeBlockMapping::getInstance()->toRuntimeId($this->fakeBlock->getFullId()), UpdateBlockPacket::FLAG_NETWORK, UpdateBlockPacket::DATA_LAYER_NORMAL)); - if ($this->fakeTile instanceof Spawnable) { + if($this->fakeTile instanceof Spawnable){ $this->player->getNetworkSession()->sendDataPacket(BlockActorDataPacket::create(BlockPosition::fromVector3($this->position->asVector3()), $this->fakeTile->getSerializedSpawnCompound()), true); } } - public function remove(): void - { + public function remove() : void{ $network = $this->player->getNetworkSession(); $world = $this->player->getWorld(); $runtime_block_mapping = RuntimeBlockMapping::getInstance(); - $block = $world->getBlockAt((int)$this->position->x, (int)$this->position->y, (int)$this->position->z); + $block = $world->getBlockAt((int) $this->position->x, (int) $this->position->y, (int) $this->position->z); $network->sendDataPacket(UpdateBlockPacket::create(BlockPosition::fromVector3($this->position->asVector3()), $runtime_block_mapping->toRuntimeId($block->getFullId()), UpdateBlockPacket::FLAG_NETWORK, UpdateBlockPacket::DATA_LAYER_NORMAL), true); - $tile = $world->getTileAt((int)$this->position->x, (int)$this->position->y, (int)$this->position->z); - if ($tile instanceof Spawnable) { + $tile = $world->getTileAt((int) $this->position->x, (int) $this->position->y, (int) $this->position->z); + if($tile instanceof Spawnable){ $network->sendDataPacket(BlockActorDataPacket::create(BlockPosition::fromVector3($this->position->asVector3()), $tile->getSerializedSpawnCompound()), true); } } - public function __toString(): string - { + public function __toString() : string{ return 'Outline'; } - private function updatePosition(): void - { + private function updatePosition() : void{ $this->position = $this->updateBlockPosition(); $reflectionc = new ReflectionClass($this->fakeTile); $reflection = $reflectionc->getProperty('position'); @@ -90,13 +84,11 @@ private function updatePosition(): void $reflection->setValue($this->fakeTile, $this->position); } - private function updateBlockPosition(): Position - { + private function updateBlockPosition() : Position{ return Position::fromObject($this->player->getPosition()->withComponents(null, $this->player->getPosition()->getWorld()->getMinY(), null)->floor(), $this->player->getWorld()); } - public function getPosition(): Position - { + public function getPosition() : Position{ return $this->position; } } \ No newline at end of file diff --git a/src/xenialdan/MagicWE2/task/action/ClipboardAction.php b/src/xenialdan/MagicWE2/task/action/ClipboardAction.php index fdf36b2..0adc381 100644 --- a/src/xenialdan/MagicWE2/task/action/ClipboardAction.php +++ b/src/xenialdan/MagicWE2/task/action/ClipboardAction.php @@ -28,7 +28,7 @@ abstract class ClipboardAction * @param string[] $messages * @return Generator */ - abstract public function execute(string $sessionUUID, Selection $selection, ?int &$changed, SingleClipboard $clipboard, array &$messages = []): Generator; + abstract public function execute(string $sessionUUID, Selection $selection, ?int &$changed, SingleClipboard &$clipboard, array &$messages = []) : Generator; abstract public static function getName(): string; diff --git a/src/xenialdan/MagicWE2/task/action/FlipAction.php b/src/xenialdan/MagicWE2/task/action/FlipAction.php index b15712c..6f0694a 100644 --- a/src/xenialdan/MagicWE2/task/action/FlipAction.php +++ b/src/xenialdan/MagicWE2/task/action/FlipAction.php @@ -46,8 +46,7 @@ public static function getName(): string * @return Generator * @throws Exception */ - public function execute(string $sessionUUID, Selection $selection, ?int &$changed, SingleClipboard $clipboard, array &$messages = []): Generator - { + public function execute(string $sessionUUID, Selection $selection, ?int &$changed, SingleClipboard &$clipboard, array &$messages = []) : Generator{ //TODO modify position. For now, just flip the blocks around their own axis $changed = 0; #$oldBlocks = []; diff --git a/src/xenialdan/MagicWE2/task/action/RotateAction.php b/src/xenialdan/MagicWE2/task/action/RotateAction.php index 39f679e..0fdeded 100644 --- a/src/xenialdan/MagicWE2/task/action/RotateAction.php +++ b/src/xenialdan/MagicWE2/task/action/RotateAction.php @@ -8,12 +8,10 @@ use Generator; use InvalidArgumentException; use pocketmine\block\BlockFactory; -use pocketmine\math\Vector3; -use xenialdan\libblockstate\BlockEntry; +use xenialdan\MagicWE2\API; use xenialdan\MagicWE2\clipboard\SingleClipboard; use xenialdan\MagicWE2\helper\Progress; use xenialdan\MagicWE2\selection\Selection; -use xenialdan\MagicWE2\selection\shape\Cuboid; class RotateAction extends ClipboardAction { @@ -50,96 +48,18 @@ public static function getName(): string * @return Generator * @throws Exception */ - public function execute(string $sessionUUID, Selection $selection, ?int &$changed, SingleClipboard $clipboard, array &$messages = []): Generator - { + public function execute(string $sessionUUID, Selection $selection, ?int &$changed, SingleClipboard &$clipboard, array &$messages = []) : Generator{ //TODO modify position. For now, just flip the blocks around their own axis $changed = 0; #$oldBlocks = []; - $count = $selection->getShape()->getTotalCount(); - $lastProgress = new Progress(0, ""); + $count = $clipboard->getTotalCount(); + yield new Progress(0, ""); BlockFactory::getInstance(); // /** @var BlockStatesParser $blockStatesParser */ // $blockStatesParser = BlockStatesParser::getInstance(); - $clonedClipboard = clone $clipboard; - $clonedClipboard->clear(); - //$x = $y = $z = null; - $maxX = $clipboard->selection->getSizeX() - 1; - $maxZ = $clipboard->selection->getSizeZ() - 1; - foreach ($clipboard->iterateEntries($x, $y, $z) as $blockEntry) {//only fully works if xyz is positive //TODO make sure this is always positive, see next comment - #var_dump("$x $y $z"); - $newX = $x; - $newZ = $z; - //TODO if aroundOrigin is true (or false, unsure right now), modify the paste vector instead, and always keep the blocks in the positive range? - if ($this->rotation === self::ROTATE_90) { - $newX = -$z; - $newZ = $x; - if ($this->aroundOrigin) { - $newX += $maxZ; - } - } - if ($this->rotation === self::ROTATE_180) { - $newX = -$x; - $newZ = -$z; - if ($this->aroundOrigin) { - $newX += $maxX; - $newZ += $maxZ; - } - } - if ($this->rotation === self::ROTATE_270) { - $newX = $z; - $newZ = -$x; - if ($this->aroundOrigin) { - $newZ += $maxX; - } - } - #var_dump("$newX $y $newZ"); - $block1 = $blockEntry->toBlock(); - #$blockStatesEntry = $instance->getFromBlock($block1); - $block = $block1; - //TODO re-add flip/rotate in libblockstate -// $rotated = $blockStatesEntry->rotate($this->rotation); -// $block = $rotated->toBlock(); - $entry = BlockEntry::fromBlock($block); - #var_dump($blockStatesEntry->__toString(), $rotated->__toString(), $entry); - /** @var int $y */ - $clonedClipboard->addEntry($newX, $y, $newZ, $entry); - $changed++; - $progress = new Progress($changed / $count, "$changed/$count"); - if (floor($progress->progress * 100) > floor($lastProgress->progress * 100)) { - yield $progress; - $lastProgress = $progress; - } - } - $clonedSelection = $clonedClipboard->selection; - $pos1 = $clonedSelection->pos1; - $pos2 = $clonedSelection->pos2; - if ($this->rotation === self::ROTATE_90) {//TODO rewrite to be cleaner - #$pos2 = $pos2->setComponents($pos1->x, $pos2->y, $pos1->z + $maxX); - $pos2 = new Vector3($pos1->x, $pos2->y, $pos1->z + $maxX); - $pos1 = $pos1->subtract($maxZ, 0, 0); - if ($this->aroundOrigin) { - $pos1 = $pos1->add($maxZ, 0, 0); - $pos2 = $pos2->add($maxZ, 0, 0); - } - } - if ($this->rotation === self::ROTATE_180) { - if (!$this->aroundOrigin) { - $pos1 = $pos1->subtract($maxX, 0, $maxZ); - $pos2 = $pos2->subtract($maxX, 0, $maxZ); - } - } - if ($this->rotation === self::ROTATE_270) {//TODO rewrite to be cleaner - #$pos2 = $pos2->setComponents($pos1->x + $maxZ, $pos2->y, $pos1->z); - $pos2 = new Vector3($pos1->x + $maxZ, $pos2->y, $pos1->z); - $pos1 = $pos1->subtract(0, 0, $maxX); - if ($this->aroundOrigin) { - $pos1 = $pos1->add(0, 0, $maxX); - $pos2 = $pos2->add(0, 0, $maxX); - } - } - $clonedSelection->shape = (Cuboid::constructFromPositions($pos1, $pos2));//TODO figure out how to keep the shape (not always Cuboid) - $clonedClipboard->selection = $clonedSelection; - //$clipboard = $clonedClipboard; + $clipboard = API::rotate($clipboard, $this->rotation); + + yield new Progress($changed / $count, "$changed/$count"); } } \ No newline at end of file From 241ccdd1310371e3ffe3d88cec66a88990b358e6 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Sat, 9 Jul 2022 21:17:30 +0200 Subject: [PATCH 03/24] Make rotate go clockwise --- src/xenialdan/MagicWE2/API.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xenialdan/MagicWE2/API.php b/src/xenialdan/MagicWE2/API.php index 77bd2bc..0c87c6b 100644 --- a/src/xenialdan/MagicWE2/API.php +++ b/src/xenialdan/MagicWE2/API.php @@ -552,9 +552,9 @@ private static function rotateSchematic(Schematic $structure, int $rotation) : S $blocks[] = match ($rotation) { //TODO check if the new positions are calculated correctly - RotateAction::ROTATE_90 => self::setComponents($block, $block->getPosition()->getFloorZ(), $block->getPosition()->getFloorY(), $structure->getWidth() - $block->getPosition()->getFloorX() - 1), + RotateAction::ROTATE_90 => self::setComponents($block, $structure->getLength() - $block->getPosition()->getFloorZ() - 1, $block->getPosition()->getFloorY(), $block->getPosition()->getFloorX()), RotateAction::ROTATE_180 => self::setComponents($block, $structure->getWidth() - $block->getPosition()->getFloorX() - 1, $block->getPosition()->getFloorY(), $structure->getLength() - $block->getPosition()->getFloorZ() - 1), - RotateAction::ROTATE_270 => self::setComponents($block, $structure->getLength() - $block->getPosition()->getFloorZ() - 1, $block->getPosition()->getFloorY(), $block->getPosition()->getFloorX()), + RotateAction::ROTATE_270 => self::setComponents($block, $block->getPosition()->getFloorZ(), $block->getPosition()->getFloorY(), $structure->getWidth() - $block->getPosition()->getFloorX() - 1), default => $block }; //TODO move origin of structure From 3c2be7229f0a1d112199137f907369da96548b6a Mon Sep 17 00:00:00 2001 From: XenialDan Date: Sat, 9 Jul 2022 21:27:38 +0200 Subject: [PATCH 04/24] Replace 0 with World::Y_MIN for $y values --- src/xenialdan/MagicWE2/helper/SubChunkIterator.php | 7 +++---- src/xenialdan/MagicWE2/selection/Selection.php | 12 ++++++------ src/xenialdan/MagicWE2/selection/shape/Cone.php | 10 +++++----- src/xenialdan/MagicWE2/selection/shape/Cube.php | 10 +++++----- src/xenialdan/MagicWE2/selection/shape/Cuboid.php | 10 +++++----- src/xenialdan/MagicWE2/selection/shape/Cylinder.php | 10 +++++----- src/xenialdan/MagicWE2/selection/shape/Ellipsoid.php | 10 +++++----- src/xenialdan/MagicWE2/selection/shape/Pyramid.php | 2 +- src/xenialdan/MagicWE2/selection/shape/Sphere.php | 12 ++++++------ src/xenialdan/MagicWE2/task/AsyncFillTask.php | 2 +- src/xenialdan/MagicWE2/tool/Flood.php | 4 ++-- 11 files changed, 44 insertions(+), 45 deletions(-) diff --git a/src/xenialdan/MagicWE2/helper/SubChunkIterator.php b/src/xenialdan/MagicWE2/helper/SubChunkIterator.php index 2e4376a..8dd4b74 100644 --- a/src/xenialdan/MagicWE2/helper/SubChunkIterator.php +++ b/src/xenialdan/MagicWE2/helper/SubChunkIterator.php @@ -63,7 +63,7 @@ public function getBlock(Vector3 $vector): int */ public function getBlockAt(int $x, int $y, int $z): int { - $y = (int)min(World::Y_MAX - 1, max(0, $y)); + $y = (int) min(World::Y_MAX - 1, max(World::Y_MIN, $y));//TODO check if this should be 255 or World::Y_MAX - 1 $this->moveTo($x, $y, $z); return $this->getCurrentSubChunk()->getFullBlock($x & 0x0f, $y & 0x0f, $z & 0x0f); } @@ -87,9 +87,8 @@ public function setBlock(Vector3 $vector, int $block): void * @throws BadMethodCallException * @throws BadMethodCallException */ - public function setBlockAt(int $x, int $y, int $z, int $block): void - { - $y = (int)min(World::Y_MAX - 1, max(0, $y)); + public function setBlockAt(int $x, int $y, int $z, int $block): void{ + $y = (int) min(World::Y_MAX - 1, max(World::Y_MIN, $y));//TODO check if this should be 255 or World::Y_MAX - 1 $this->moveTo($x, $y, $z); $this->getCurrentSubChunk()->setFullBlock($x & 0x0f, $y & 0x0f, $z & 0x0f, $block); } diff --git a/src/xenialdan/MagicWE2/selection/Selection.php b/src/xenialdan/MagicWE2/selection/Selection.php index 20f7fc3..f4e40a9 100644 --- a/src/xenialdan/MagicWE2/selection/Selection.php +++ b/src/xenialdan/MagicWE2/selection/Selection.php @@ -117,9 +117,9 @@ public function getPos1() : Position{ */ public function setPos1(Position $position) : void{ $this->pos1 = $position->asVector3()->floor(); - if ($this->pos1->y >= World::Y_MAX) $this->pos1->y = World::Y_MAX; - if ($this->pos1->y < 0) $this->pos1->y = 0; - if ($this->worldId !== $position->getWorld()->getId()) {//reset other position if in different world + if($this->pos1->y > World::Y_MAX) $this->pos1->y = World::Y_MAX;//TODO check if this should be 255 or World::Y_MAX + if($this->pos1->y < World::Y_MIN) $this->pos1->y = World::Y_MIN; + if($this->worldId !== $position->getWorld()->getId()){//reset other position if in different world $this->pos2 = null; } $this->setWorld($position->getWorld()); @@ -163,9 +163,9 @@ public function getPos2() : Position{ */ public function setPos2(Position $position) : void{ $this->pos2 = $position->asVector3()->floor(); - if ($this->pos2->y >= World::Y_MAX) $this->pos2->y = World::Y_MAX; - if ($this->pos2->y < 0) $this->pos2->y = 0; - if ($this->worldId !== $position->getWorld()->getId()) { + if($this->pos2->y > World::Y_MAX) $this->pos2->y = World::Y_MAX; + if($this->pos2->y < World::Y_MIN) $this->pos2->y = World::Y_MIN; + if($this->worldId !== $position->getWorld()->getId()){ $this->pos1 = null; } $this->setWorld($position->getWorld()); diff --git a/src/xenialdan/MagicWE2/selection/shape/Cone.php b/src/xenialdan/MagicWE2/selection/shape/Cone.php index bbd60f8..4bce5c9 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Cone.php +++ b/src/xenialdan/MagicWE2/selection/shape/Cone.php @@ -75,12 +75,12 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Gen // if (API::hasFlag($flags, API::FLAG_KEEP_BLOCKS) && $block->getId() !== BlockLegacyIds::AIR) continue; // if (API::hasFlag($flags, API::FLAG_KEEP_AIR) && $block->getId() === BlockLegacyIds::AIR) continue; - if ($block->getPosition()->y >= World::Y_MAX || $block->getPosition()->y < 0) continue;//TODO fuufufufuuu EDIT: And.. fufufu is what? - if ($filterblocks->empty()) yield $block; - else { - foreach ($filterblocks->palette() as $filterblock) { + if($block->getPosition()->y >= World::Y_MAX || $block->getPosition()->y < World::Y_MIN) continue;//TODO check if this should be 255 or World::Y_MAX + if($filterblocks->empty()) yield $block; + else{ + foreach($filterblocks->palette() as $filterblock){ // if (($block->getId() === $filterblock->getId()) && ((API::hasFlag($flags, API::FLAG_VARIANT) && $block->getIdInfo()->getVariant() === $filterblock->getIdInfo()->getVariant()) || (!API::hasFlag($flags, API::FLAG_VARIANT) && ($block->getMeta() === $filterblock->getMeta() || API::hasFlag($flags, API::FLAG_KEEP_META))))) - if ($block->getFullId() === $filterblock->getFullId()) + if($block->getFullId() === $filterblock->getFullId()) yield $block; } } diff --git a/src/xenialdan/MagicWE2/selection/shape/Cube.php b/src/xenialdan/MagicWE2/selection/shape/Cube.php index 2b33af1..988943c 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Cube.php +++ b/src/xenialdan/MagicWE2/selection/shape/Cube.php @@ -52,13 +52,13 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Gen // if (API::hasFlag($flags, API::FLAG_KEEP_BLOCKS) && $block->getId() !== BlockLegacyIds::AIR) continue; // if (API::hasFlag($flags, API::FLAG_KEEP_AIR) && $block->getId() === BlockLegacyIds::AIR) continue; - if ($block->getPosition()->y >= World::Y_MAX || $block->getPosition()->y < 0) continue;//TODO check for removal because relative might be at other y + if($block->getPosition()->y >= World::Y_MAX || $block->getPosition()->y < World::Y_MIN) continue;//TODO check if this should be 255 or World::Y_MAX //TODO check for removal because relative might be at other y // if (API::hasFlag($flags, API::FLAG_HOLLOW) && ($block->getPosition()->x > $this->getMinVec3()->getX() && $block->getPosition()->x < $this->getMaxVec3()->getX()) && ($block->getPosition()->y > $this->getMinVec3()->getY() && $block->getPosition()->y < $this->getMaxVec3()->getY()) && ($block->getPosition()->z > $this->getMinVec3()->getZ() && $block->getPosition()->z < $this->getMaxVec3()->getZ())) continue; - if ($filterblocks->empty()) yield $block; - else { - foreach ($filterblocks->palette() as $filterblock) { + if($filterblocks->empty()) yield $block; + else{ + foreach($filterblocks->palette() as $filterblock){ // if (($block->getId() === $filterblock->getId()) && ((API::hasFlag($flags, API::FLAG_VARIANT) && $block->getIdInfo()->getVariant() === $filterblock->getIdInfo()->getVariant()) || (!API::hasFlag($flags, API::FLAG_VARIANT) && ($block->getMeta() === $filterblock->getMeta() || API::hasFlag($flags, API::FLAG_KEEP_META))))) - if ($block->getFullId() === $filterblock->getFullId()) + if($block->getFullId() === $filterblock->getFullId()) yield $block; } } diff --git a/src/xenialdan/MagicWE2/selection/shape/Cuboid.php b/src/xenialdan/MagicWE2/selection/shape/Cuboid.php index ad2f7c0..574e3ed 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Cuboid.php +++ b/src/xenialdan/MagicWE2/selection/shape/Cuboid.php @@ -79,13 +79,13 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Gen // if (API::hasFlag($flags, API::FLAG_KEEP_BLOCKS) && $block->getId() !== BlockLegacyIds::AIR) continue; // if (API::hasFlag($flags, API::FLAG_KEEP_AIR) && $block->getId() === BlockLegacyIds::AIR) continue; - if ($block->getPosition()->y >= World::Y_MAX || $block->getPosition()->y < 0) continue;//TODO check for removal because relative might be at other y + if($block->getPosition()->y >= World::Y_MAX || $block->getPosition()->y < World::Y_MIN) continue;//TODO check if this should be 255 or World::Y_MAX //TODO check for removal because relative might be at other y // if (API::hasFlag($flags, API::FLAG_HOLLOW) && ($block->getPosition()->x > $this->getMinVec3()->getX() && $block->getPosition()->x < $this->getMaxVec3()->getX()) && ($block->getPosition()->y > $this->getMinVec3()->getY() && $block->getPosition()->y < $this->getMaxVec3()->getY()) && ($block->getPosition()->z > $this->getMinVec3()->getZ() && $block->getPosition()->z < $this->getMaxVec3()->getZ())) continue; - if ($filterblocks->empty()) yield $block; - else { - foreach ($filterblocks->palette() as $filterblock) { + if($filterblocks->empty()) yield $block; + else{ + foreach($filterblocks->palette() as $filterblock){ // if (($block->getId() === $filterblock->getId()) && ((API::hasFlag($flags, API::FLAG_VARIANT) && $block->getIdInfo()->getVariant() === $filterblock->getIdInfo()->getVariant()) || (!API::hasFlag($flags, API::FLAG_VARIANT) && ($block->getMeta() === $filterblock->getMeta() || API::hasFlag($flags, API::FLAG_KEEP_META))))) - if ($block->getFullId() === $filterblock->getFullId()) + if($block->getFullId() === $filterblock->getFullId()) yield $block; } } diff --git a/src/xenialdan/MagicWE2/selection/shape/Cylinder.php b/src/xenialdan/MagicWE2/selection/shape/Cylinder.php index f072ea2..147047f 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Cylinder.php +++ b/src/xenialdan/MagicWE2/selection/shape/Cylinder.php @@ -65,12 +65,12 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Gen // if (API::hasFlag($flags, API::FLAG_KEEP_BLOCKS) && $block->getId() !== BlockLegacyIds::AIR) continue; // if (API::hasFlag($flags, API::FLAG_KEEP_AIR) && $block->getId() === BlockLegacyIds::AIR) continue; - if($block->getPosition()->y >= World::Y_MAX || $block->getPosition()->y < 0) continue;//TODO fuufufufuuu - if ($filterblocks->empty()) yield $block; - else { - foreach ($filterblocks->palette() as $filterblock) { + if($block->getPosition()->y >= World::Y_MAX || $block->getPosition()->y < World::Y_MIN) continue;//TODO check if this should be 255 or World::Y_MAX + if($filterblocks->empty()) yield $block; + else{ + foreach($filterblocks->palette() as $filterblock){ // if (($block->getId() === $filterblock->getId()) && ((API::hasFlag($flags, API::FLAG_VARIANT) && $block->getIdInfo()->getVariant() === $filterblock->getIdInfo()->getVariant()) || (!API::hasFlag($flags, API::FLAG_VARIANT) && ($block->getMeta() === $filterblock->getMeta() || API::hasFlag($flags, API::FLAG_KEEP_META))))) - if ($block->getFullId() === $filterblock->getFullId()) + if($block->getFullId() === $filterblock->getFullId()) yield $block; } } diff --git a/src/xenialdan/MagicWE2/selection/shape/Ellipsoid.php b/src/xenialdan/MagicWE2/selection/shape/Ellipsoid.php index f72dac4..2bc450e 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Ellipsoid.php +++ b/src/xenialdan/MagicWE2/selection/shape/Ellipsoid.php @@ -91,12 +91,12 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Gen // if (API::hasFlag($flags, API::FLAG_KEEP_BLOCKS) && $block->getId() !== BlockLegacyIds::AIR) continue; // if (API::hasFlag($flags, API::FLAG_KEEP_AIR) && $block->getId() === BlockLegacyIds::AIR) continue; - if ($block->getPosition()->y >= World::Y_MAX || $block->getPosition()->y < 0) continue;//TODO fuufufufuuu - if ($filterblocks->empty()) yield $block; - else { - foreach ($filterblocks->palette() as $filterblock) { + if($block->getPosition()->y >= World::Y_MAX || $block->getPosition()->y < World::Y_MIN) continue;//TODO check if this should be 255 or World::Y_MAX + if($filterblocks->empty()) yield $block; + else{ + foreach($filterblocks->palette() as $filterblock){ // if (($block->getId() === $filterblock->getId()) && ((API::hasFlag($flags, API::FLAG_VARIANT) && $block->getIdInfo()->getVariant() === $filterblock->getIdInfo()->getVariant()) || (!API::hasFlag($flags, API::FLAG_VARIANT) && ($block->getMeta() === $filterblock->getMeta() || API::hasFlag($flags, API::FLAG_KEEP_META))))) - if ($block->getFullId() === $filterblock->getFullId()) + if($block->getFullId() === $filterblock->getFullId()) yield $block; } } diff --git a/src/xenialdan/MagicWE2/selection/shape/Pyramid.php b/src/xenialdan/MagicWE2/selection/shape/Pyramid.php index 61692a4..ade548b 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Pyramid.php +++ b/src/xenialdan/MagicWE2/selection/shape/Pyramid.php @@ -89,7 +89,7 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Gen // if (API::hasFlag($flags, API::FLAG_KEEP_BLOCKS) && $block->getId() !== BlockLegacyIds::AIR) continue; // if (API::hasFlag($flags, API::FLAG_KEEP_AIR) && $block->getId() === BlockLegacyIds::AIR) continue; - if($block->getPosition()->y >= World::Y_MAX || $block->getPosition()->y < 0) continue;//TODO fuufufufuuu + if($block->getPosition()->y >= World::Y_MAX || $block->getPosition()->y < World::Y_MIN) continue;//TODO check if this should be 255 or World::Y_MAX if($filterblocks->empty()) yield $block; else{ foreach($filterblocks->palette() as $filterblock){ diff --git a/src/xenialdan/MagicWE2/selection/shape/Sphere.php b/src/xenialdan/MagicWE2/selection/shape/Sphere.php index e436c9f..be28e4e 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Sphere.php +++ b/src/xenialdan/MagicWE2/selection/shape/Sphere.php @@ -56,16 +56,16 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Gen $vec3 = new Vector3($x, $y, $z); // if ($vec3->distanceSquared($this->pasteVector) > (($this->diameter / 2) ** 2) || (API::hasFlag(API::FLAG_BASE, API::FLAG_HOLLOW) && $vec3->distanceSquared($this->pasteVector) <= ((($this->diameter / 2) - 1) ** 2))) // continue; - $block = API::setComponents($manager->getBlockAt($vec3->getFloorX(), $vec3->getFloorY(), $vec3->getFloorZ()), (int)$vec3->x, (int)$vec3->y, (int)$vec3->z); + $block = API::setComponents($manager->getBlockAt($vec3->getFloorX(), $vec3->getFloorY(), $vec3->getFloorZ()), (int) $vec3->x, (int) $vec3->y, (int) $vec3->z); // if (API::hasFlag(API::FLAG_BASE, API::FLAG_KEEP_BLOCKS) && $block->getId() !== BlockLegacyIds::AIR) continue; // if (API::hasFlag(API::FLAG_BASE, API::FLAG_KEEP_AIR) && $block->getId() === BlockLegacyIds::AIR) continue; - if ($block->getPosition()->y >= World::Y_MAX || $block->getPosition()->y < 0) continue;//TODO fufufufuuu - if ($filterblocks->empty()) yield $block; - else { - foreach ($filterblocks->palette() as $filterblock) { + if($block->getPosition()->y >= World::Y_MAX || $block->getPosition()->y < World::Y_MIN) continue;//TODO check if this should be 255 or World::Y_MAX + if($filterblocks->empty()) yield $block; + else{ + foreach($filterblocks->palette() as $filterblock){ // if (($block->getId() === $filterblock->getId()) && ((API::hasFlag($flags, API::FLAG_VARIANT) && $block->getIdInfo()->getVariant() === $filterblock->getIdInfo()->getVariant()) || (!API::hasFlag($flags, API::FLAG_VARIANT) && ($block->getMeta() === $filterblock->getMeta() || API::hasFlag($flags, API::FLAG_KEEP_META))))) - if ($block->getFullId() === $filterblock->getFullId()) + if($block->getFullId() === $filterblock->getFullId()) yield $block; } } diff --git a/src/xenialdan/MagicWE2/task/AsyncFillTask.php b/src/xenialdan/MagicWE2/task/AsyncFillTask.php index 61d10a0..c4ba10c 100644 --- a/src/xenialdan/MagicWE2/task/AsyncFillTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncFillTask.php @@ -186,7 +186,7 @@ public function onCompletion(): void foreach($resultChunks as $hash => $chunk){ World::getXZ($hash, $x, $z); $world->setChunk($x, $z, $chunk); - for($y = World::Y_MIN; $y < World::Y_MAX; $y += Chunk::EDGE_LENGTH){ + for($y = World::Y_MIN; $y < World::Y_MAX; $y += Chunk::EDGE_LENGTH){//TODO check if this should be 255 or World::Y_MAX $vector3 = new Vector3($x * 16, 0, $z * 16); $renderHack[] = $vector3; //$pk = UpdateBlockPacket::create($blockPosition, $fullId,0b1111, UpdateBlockPacket::DATA_LAYER_NORMAL); diff --git a/src/xenialdan/MagicWE2/tool/Flood.php b/src/xenialdan/MagicWE2/tool/Flood.php index ec07868..ab15981 100644 --- a/src/xenialdan/MagicWE2/tool/Flood.php +++ b/src/xenialdan/MagicWE2/tool/Flood.php @@ -172,8 +172,8 @@ private function getCenter(): Vector3 */ public static function getChunkManager(array $chunks): AsyncChunkManager { - $manager = new AsyncChunkManager(0, World::Y_MAX); - foreach ($chunks as $hash => $chunk) { + $manager = new AsyncChunkManager(World::Y_MIN, World::Y_MAX);//TODO replace AsyncChunkManager with AsyncWorld + foreach($chunks as $hash => $chunk){ World::getXZ($hash, $x, $z); $manager->setChunk($x, $z, $chunk); } From c25fa18992707d41880a11c6bd4eb6b3b63b27b3 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Sat, 9 Jul 2022 21:28:49 +0200 Subject: [PATCH 05/24] Re-enable experimental //rotate command --- src/xenialdan/MagicWE2/Loader.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/xenialdan/MagicWE2/Loader.php b/src/xenialdan/MagicWE2/Loader.php index bfee724..343022a 100644 --- a/src/xenialdan/MagicWE2/Loader.php +++ b/src/xenialdan/MagicWE2/Loader.php @@ -39,6 +39,7 @@ use xenialdan\MagicWE2\commands\clipboard\Cut2Command; use xenialdan\MagicWE2\commands\clipboard\CutCommand; use xenialdan\MagicWE2\commands\clipboard\PasteCommand; +use xenialdan\MagicWE2\commands\clipboard\RotateCommand; use xenialdan\MagicWE2\commands\debug\GenerateCommandsMDCommand; use xenialdan\MagicWE2\commands\debug\PlaceAllBlockstatesCommand; use xenialdan\MagicWE2\commands\debug\TestAPICommand; @@ -276,7 +277,7 @@ public function onEnable(): void new ClearClipboardCommand($this, "/clearclipboard", "Clear your clipboard"), //TODO re-add flip/rotate in libblockstate #new FlipCommand($this, "/flip", "Flip the contents of the clipboard across the origin", ["/mirror"]), - #new RotateCommand($this, "/rotate", "Rotate the contents of the clipboard around the origin"), + new RotateCommand($this, "/rotate", "Rotate the contents of the clipboard around the origin"), /* -- history -- */ new UndoCommand($this, "/undo", "Rolls back the last action"), new RedoCommand($this, "/redo", "Applies the last undo action again"), From 6f0e4e88b22158b959b85beb10f5e9379ea9b695 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Sat, 9 Jul 2022 21:34:03 +0200 Subject: [PATCH 06/24] Remove method/line tracking var_dumps --- src/xenialdan/MagicWE2/EventListener.php | 12 ------------ .../MagicWE2/commands/selection/ChunkCommand.php | 7 ------- .../MagicWE2/commands/selection/HPos1Command.php | 5 ----- .../MagicWE2/commands/selection/HPos2Command.php | 5 ----- .../MagicWE2/commands/selection/Pos1Command.php | 5 ----- .../MagicWE2/commands/selection/Pos2Command.php | 5 ----- src/xenialdan/MagicWE2/helper/SessionHelper.php | 4 ---- 7 files changed, 43 deletions(-) diff --git a/src/xenialdan/MagicWE2/EventListener.php b/src/xenialdan/MagicWE2/EventListener.php index 5c3f9dc..e2a5bc3 100644 --- a/src/xenialdan/MagicWE2/EventListener.php +++ b/src/xenialdan/MagicWE2/EventListener.php @@ -183,17 +183,13 @@ private function onBreakBlock(BlockBreakEvent $event): void $session->sendMessage(TF::RED . $session->getLanguage()->translateString("tool.wand.disabled")); break; } - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); if(($selection = $session->getLatestSelection()) === null){ - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $session->addSelection(($selection = new Selection($session->getUUID(), $event->getBlock()->getPosition()->getWorld()))); // TODO check if the selection inside of the session updates } if(is_null($selection)){ throw new Error("No selection created - Check the console for errors"); } - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $selection->setPos1($event->getBlock()->getPosition()); - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); break; } case ItemIds::STICK: @@ -231,17 +227,13 @@ private function onRightClickBlock(PlayerInteractEvent $event): void $session->sendMessage(TF::RED . $session->getLanguage()->translateString("tool.wand.disabled")); break; } - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); if(($selection = $session->getLatestSelection()) === null){ - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $session->addSelection(($selection = new Selection($session->getUUID(), $event->getBlock()->getPosition()->getWorld()))); // TODO check if the selection inside of the session updates } if(is_null($selection)){ throw new Error("No selection created - Check the console for errors"); } - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $selection->setPos2($event->getBlock()->getPosition()); - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); break; } case ItemIds::STICK: @@ -307,17 +299,13 @@ private function onLeftClickBlock(PlayerInteractEvent $event): void $session->sendMessage(TF::RED . $session->getLanguage()->translateString("tool.wand.disabled")); break; } - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); if(($selection = $session->getLatestSelection()) === null){ - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $session->addSelection(($selection = new Selection($session->getUUID(), $event->getBlock()->getPosition()->getWorld()))); // TODO check if the selection inside of the session updates } if(is_null($selection)){ throw new Error("No selection created - Check the console for errors"); } - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $selection->setPos1($event->getBlock()->getPosition()); - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); break; } case ItemIds::STICK: diff --git a/src/xenialdan/MagicWE2/commands/selection/ChunkCommand.php b/src/xenialdan/MagicWE2/commands/selection/ChunkCommand.php index 68eacfe..fde77b7 100644 --- a/src/xenialdan/MagicWE2/commands/selection/ChunkCommand.php +++ b/src/xenialdan/MagicWE2/commands/selection/ChunkCommand.php @@ -20,7 +20,6 @@ use xenialdan\MagicWE2\selection\Selection; use xenialdan\MagicWE2\session\UserSession; use function is_null; -use function var_dump; class ChunkCommand extends BaseCommand{ @@ -54,26 +53,20 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo if(!$session instanceof UserSession){ throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()])); } - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); if(($selection = $session->getLatestSelection()) === null){ - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $session->addSelection(($selection = new Selection($session->getUUID(), $sender->getWorld()))); // TODO check if the selection inside of the session updates } if(is_null($selection)){ throw new Error("No selection created - Check the console for errors"); } - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $chunk = $sender->getWorld()->getOrLoadChunkAtPosition($sender->getPosition()); if(is_null($chunk)){ throw new Error("Could not find a chunk at your position"); } $x = $sender->getPosition()->x >> 4; $z = $sender->getPosition()->x >> 4; - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $selection->setPos1(Position::fromObject(new Vector3($x * 16, World::Y_MIN, $z * 16), $sender->getWorld())); - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $selection->setPos2(Position::fromObject(new Vector3($x * 16 + 15, World::Y_MAX, $z * 16 + 15), $sender->getWorld())); - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); } catch (Exception $error) { $sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error')); $sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage()); diff --git a/src/xenialdan/MagicWE2/commands/selection/HPos1Command.php b/src/xenialdan/MagicWE2/commands/selection/HPos1Command.php index 68e8195..5b54c42 100644 --- a/src/xenialdan/MagicWE2/commands/selection/HPos1Command.php +++ b/src/xenialdan/MagicWE2/commands/selection/HPos1Command.php @@ -17,7 +17,6 @@ use xenialdan\MagicWE2\selection\Selection; use xenialdan\MagicWE2\session\UserSession; use function is_null; -use function var_dump; class HPos1Command extends BaseCommand{ @@ -51,9 +50,7 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo if(!$session instanceof UserSession){ throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()])); } - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); if(($selection = $session->getLatestSelection()) === null){ - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $session->addSelection(($selection = new Selection($session->getUUID(), $sender->getWorld()))); // TODO check if the selection inside of the session updates } if(is_null($selection)){ @@ -64,9 +61,7 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo $sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.notarget')); return; } - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $selection->setPos1($target->getPosition()); - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); } catch (Exception $error) { $sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error')); $sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage()); diff --git a/src/xenialdan/MagicWE2/commands/selection/HPos2Command.php b/src/xenialdan/MagicWE2/commands/selection/HPos2Command.php index 1913b96..ae34c9f 100644 --- a/src/xenialdan/MagicWE2/commands/selection/HPos2Command.php +++ b/src/xenialdan/MagicWE2/commands/selection/HPos2Command.php @@ -17,7 +17,6 @@ use xenialdan\MagicWE2\selection\Selection; use xenialdan\MagicWE2\session\UserSession; use function is_null; -use function var_dump; class HPos2Command extends BaseCommand{ @@ -51,9 +50,7 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo if(!$session instanceof UserSession){ throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()])); } - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); if(($selection = $session->getLatestSelection()) === null){ - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $session->addSelection(($selection = new Selection($session->getUUID(), $sender->getWorld()))); // TODO check if the selection inside of the session updates } if(is_null($selection)){ @@ -64,9 +61,7 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo $sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.notarget')); return; } - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $selection->setPos2($target->getPosition()); - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); } catch (Exception $error) { $sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error')); $sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage()); diff --git a/src/xenialdan/MagicWE2/commands/selection/Pos1Command.php b/src/xenialdan/MagicWE2/commands/selection/Pos1Command.php index 77e710b..2a144c5 100644 --- a/src/xenialdan/MagicWE2/commands/selection/Pos1Command.php +++ b/src/xenialdan/MagicWE2/commands/selection/Pos1Command.php @@ -17,7 +17,6 @@ use xenialdan\MagicWE2\selection\Selection; use xenialdan\MagicWE2\session\UserSession; use function is_null; -use function var_dump; class Pos1Command extends BaseCommand{ @@ -51,17 +50,13 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo if(!$session instanceof UserSession){ throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()])); } - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); if(($selection = $session->getLatestSelection()) === null){ - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $session->addSelection(($selection = new Selection($session->getUUID(), $sender->getWorld()))); // TODO check if the selection inside of the session updates } if(is_null($selection)){ throw new Error("No selection created - Check the console for errors"); } - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $selection->setPos1($sender->getPosition()); - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); } catch (Exception $error) { Loader::getInstance()->getLogger()->logException($error); $sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error')); diff --git a/src/xenialdan/MagicWE2/commands/selection/Pos2Command.php b/src/xenialdan/MagicWE2/commands/selection/Pos2Command.php index d9a15da..3866160 100644 --- a/src/xenialdan/MagicWE2/commands/selection/Pos2Command.php +++ b/src/xenialdan/MagicWE2/commands/selection/Pos2Command.php @@ -17,7 +17,6 @@ use xenialdan\MagicWE2\selection\Selection; use xenialdan\MagicWE2\session\UserSession; use function is_null; -use function var_dump; class Pos2Command extends BaseCommand{ @@ -51,17 +50,13 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo if(!$session instanceof UserSession){ throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()])); } - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); if(($selection = $session->getLatestSelection()) === null){ - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $session->addSelection(($selection = new Selection($session->getUUID(), $sender->getWorld()))); // TODO check if the selection inside of the session updates } if(is_null($selection)){ throw new Error("No selection created - Check the console for errors"); } - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $selection->setPos2($sender->getPosition()); - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); } catch (Exception $error) { Loader::getInstance()->getLogger()->logException($error); $sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error')); diff --git a/src/xenialdan/MagicWE2/helper/SessionHelper.php b/src/xenialdan/MagicWE2/helper/SessionHelper.php index 24c4b2c..ba699e0 100644 --- a/src/xenialdan/MagicWE2/helper/SessionHelper.php +++ b/src/xenialdan/MagicWE2/helper/SessionHelper.php @@ -30,7 +30,6 @@ use function array_filter; use function array_values; use function count; -use function var_dump; class SessionHelper{ /** @var array */ @@ -233,11 +232,8 @@ public static function loadUserSession(Player $player) : ?UserSession{ isset($latestSelection["pos2"]) ? new Vector3($latestSelection["pos2"]["x"], $latestSelection["pos2"]["y"], $latestSelection["pos2"]["z"]) : null, $shape ?? null ); - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); if($selection->isValid()){ - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); $session->addSelection($selection); - var_dump(__CLASS__ . "::" . __FUNCTION__ . " (line " . __LINE__ . ")"); } } }catch(RuntimeException $e){ From 81e2aa4a22526a614d36fbfc05f80a8762367c1c Mon Sep 17 00:00:00 2001 From: XenialDan Date: Wed, 20 Jul 2022 05:48:25 +0200 Subject: [PATCH 07/24] Remove var_dump spam --- src/xenialdan/MagicWE2/selection/Selection.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/xenialdan/MagicWE2/selection/Selection.php b/src/xenialdan/MagicWE2/selection/Selection.php index f4e40a9..e0642b2 100644 --- a/src/xenialdan/MagicWE2/selection/Selection.php +++ b/src/xenialdan/MagicWE2/selection/Selection.php @@ -58,8 +58,6 @@ public function __construct(UuidInterface $sessionUUID, World $world, ?Vector3 $ Loader::getInstance()->getLogger()->logException($e); } - var_dump($this); - $this->iterator = new SubChunkIterator(new AsyncWorld($this)); } @@ -123,10 +121,8 @@ public function setPos1(Position $position) : void{ $this->pos2 = null; } $this->setWorld($position->getWorld()); - var_dump($this); if(($this->shape === null || $this->shape instanceof Cuboid) && $this->isValid()) $this->setShape(Cuboid::constructFromPositions($this->pos1, $this->pos2)); - var_dump($this); try{ $session = SessionHelper::getSessionByUUID($this->sessionUUID); if($session instanceof Session){ @@ -169,10 +165,8 @@ public function setPos2(Position $position) : void{ $this->pos1 = null; } $this->setWorld($position->getWorld()); - var_dump($this); if(($this->shape === null || $this->shape instanceof Cuboid) && $this->isValid()) $this->setShape(Cuboid::constructFromPositions($this->pos1, $this->pos2)); - var_dump($this); try{ $session = SessionHelper::getSessionByUUID($this->sessionUUID); if($session instanceof Session){ From bfc4f32e494f07b42e1881898557edf0cd0a5e1d Mon Sep 17 00:00:00 2001 From: XenialDan Date: Fri, 22 Jul 2022 08:52:39 +0200 Subject: [PATCH 08/24] Add basic debug stick state iteration --- src/xenialdan/MagicWE2/API.php | 16 +- src/xenialdan/MagicWE2/EventListener.php | 177 ++++++++++-------- src/xenialdan/MagicWE2/Loader.php | 119 +++++------- .../MagicWE2/commands/tool/DebugCommand.php | 2 +- src/xenialdan/MagicWE2/helper/ArrayUtils.php | 43 +++++ .../MagicWE2/session/UserSession.php | 2 + src/xenialdan/MagicWE2/tool/Brush.php | 7 +- src/xenialdan/MagicWE2/tool/Debug.php | 160 ++++++++++++++++ 8 files changed, 370 insertions(+), 156 deletions(-) create mode 100644 src/xenialdan/MagicWE2/helper/ArrayUtils.php create mode 100644 src/xenialdan/MagicWE2/tool/Debug.php diff --git a/src/xenialdan/MagicWE2/API.php b/src/xenialdan/MagicWE2/API.php index 0c87c6b..e8fc4d5 100644 --- a/src/xenialdan/MagicWE2/API.php +++ b/src/xenialdan/MagicWE2/API.php @@ -7,6 +7,7 @@ use BlockHorizons\libschematic\Schematic; use Exception; use InvalidArgumentException; +use JsonSchema\Exception\ResourceNotFoundException; use pocketmine\block\Block; use pocketmine\block\BlockFactory; use pocketmine\math\Vector3; @@ -15,6 +16,7 @@ use pocketmine\Server; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\TextFormat as TF; +use pocketmine\utils\Utils; use pocketmine\world\Position; use RuntimeException; use xenialdan\libblockstate\BlockEntry; @@ -75,6 +77,7 @@ class API public const TAG_MAGIC_WE_BRUSH = "MagicWEBrush"; public const TAG_MAGIC_WE_ASSET = "MagicWEAsset"; public const TAG_MAGIC_WE_PALETTE = "MagicWEPalette"; + public const TAG_MAGIC_WE_DEBUG = "MagicWEDebug"; //TODO Split into separate Class (SchematicStorage?) /** @var Clipboard[] */ @@ -482,9 +485,9 @@ public static function evalAsMath(string $str): float|int{ * @param CompoundTag $compoundTag * @return array */ - public static function compoundToArray(CompoundTag $compoundTag): array{ + public static function compoundToArray(CompoundTag $compoundTag) : array{//TODO add recursive $a = []; - foreach ($compoundTag->getValue() as $key => $value) { + foreach($compoundTag->getValue() as $key => $value){ $a[$key] = $value; } return $a; @@ -603,4 +606,13 @@ private static function rotateClipboard(SingleClipboard $structure, int $rotatio return $newClipboard; } + public static function decodeJsonResource(string $filename) : array{ + $resource = Loader::getInstance()->getResource($filename); + if($resource === null) throw new ResourceNotFoundException("Resource not found: $filename"); + $array = json_decode(Utils::assumeNotFalse(stream_get_contents($resource), "Invalid json file: $filename"), true); + fclose($resource); + if($array === null) throw new AssumptionFailedError("Invalid json file: $filename"); + return $array; + } + } \ No newline at end of file diff --git a/src/xenialdan/MagicWE2/EventListener.php b/src/xenialdan/MagicWE2/EventListener.php index e2a5bc3..bd18308 100644 --- a/src/xenialdan/MagicWE2/EventListener.php +++ b/src/xenialdan/MagicWE2/EventListener.php @@ -19,6 +19,7 @@ use pocketmine\event\player\PlayerJoinEvent; use pocketmine\event\player\PlayerQuitEvent; use pocketmine\item\ItemIds; +use pocketmine\item\Stick; use pocketmine\nbt\UnexpectedTagTypeException; use pocketmine\player\Player; use pocketmine\plugin\Plugin; @@ -33,43 +34,41 @@ use xenialdan\MagicWE2\selection\Selection; use xenialdan\MagicWE2\session\UserSession; use xenialdan\MagicWE2\tool\Brush; +use xenialdan\MagicWE2\tool\Debug; use function is_null; use function var_dump; -class EventListener implements Listener -{ +class EventListener implements Listener{ /** @var Plugin */ public Plugin $owner; - public function __construct(Plugin $plugin) - { + public function __construct(Plugin $plugin){ $this->owner = $plugin; } /** * @param PlayerJoinEvent $event + * * @throws InvalidSkinException * @throws JsonException * @throws RuntimeException * @throws SessionException */ - public function onLogin(PlayerJoinEvent $event): void - { - if ($event->getPlayer()->hasPermission("we.session")) { - if (SessionHelper::hasSession($event->getPlayer()) && ($session = SessionHelper::getUserSession($event->getPlayer())) instanceof UserSession) { + public function onLogin(PlayerJoinEvent $event) : void{ + if($event->getPlayer()->hasPermission("we.session")){ + if(SessionHelper::hasSession($event->getPlayer()) && ($session = SessionHelper::getUserSession($event->getPlayer())) instanceof UserSession){ Loader::getInstance()->getLogger()->debug("Restored cached session for player {$session->getPlayer()->getName()}"); - } else if (($session = SessionHelper::loadUserSession($event->getPlayer())) instanceof UserSession) { + }else if(($session = SessionHelper::loadUserSession($event->getPlayer())) instanceof UserSession){ Loader::getInstance()->getLogger()->debug("Restored session from file for player {$session->getPlayer()->getName()}"); - } else (SessionHelper::createUserSession($event->getPlayer())); + }else (SessionHelper::createUserSession($event->getPlayer())); } } - public function onSessionLoad(MWESessionLoadEvent $event): void - { + public function onSessionLoad(MWESessionLoadEvent $event) : void{ Loader::getInstance()->wailaBossBar->addPlayer($event->getPlayer()); - if (Loader::hasScoreboard()) { + if(Loader::hasScoreboard()){ $session = $event->getSession(); - if ($session instanceof UserSession && $session->isSidebarEnabled()) + if($session instanceof UserSession && $session->isSidebarEnabled()) /** @var UserSession $session */ $session->sidebar->handleScoreboard($session); } @@ -77,12 +76,12 @@ public function onSessionLoad(MWESessionLoadEvent $event): void /** * @param PlayerQuitEvent $event + * * @throws JsonException * @throws SessionException */ - public function onLogout(PlayerQuitEvent $event): void - { - if (($session = SessionHelper::getUserSession($event->getPlayer())) instanceof UserSession) { + public function onLogout(PlayerQuitEvent $event) : void{ + if(($session = SessionHelper::getUserSession($event->getPlayer())) instanceof UserSession){ SessionHelper::destroySession($session); unset($session); } @@ -90,13 +89,13 @@ public function onLogout(PlayerQuitEvent $event): void /** * @param PlayerInteractEvent $event + * * @throws AssumptionFailedError * @throws Error */ - public function onInteract(PlayerInteractEvent $event): void - { - try { - switch ($event->getAction()) { + public function onInteract(PlayerInteractEvent $event) : void{ + try{ + switch($event->getAction()){ case PlayerInteractEvent::RIGHT_CLICK_BLOCK: { $this->onRightClickBlock($event); @@ -108,7 +107,7 @@ public function onInteract(PlayerInteractEvent $event): void break; } } - } catch (Exception $error) { + }catch(Exception $error){ $event->getPlayer()->sendMessage(Loader::PREFIX . TF::RED . "Interaction failed!"); $event->getPlayer()->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage()); } @@ -116,13 +115,13 @@ public function onInteract(PlayerInteractEvent $event): void /** * @param PlayerItemUseEvent $event + * * @throws AssumptionFailedError */ - public function onItemRightClick(PlayerItemUseEvent $event): void - { - try { + public function onItemRightClick(PlayerItemUseEvent $event) : void{ + try{ $this->onRightClickAir($event); - } catch (Exception $error) { + }catch(Exception $error){ $event->getPlayer()->sendMessage(Loader::PREFIX . TF::RED . "Interaction failed!"); $event->getPlayer()->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage()); } @@ -130,19 +129,20 @@ public function onItemRightClick(PlayerItemUseEvent $event): void /** * @param BlockBreakEvent $event + * * @throws AssumptionFailedError * @throws Error * @throws UnexpectedTagTypeException */ - public function onBreak(BlockBreakEvent $event): void - { - if (!is_null($event->getItem()->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE)) || !is_null($event->getItem()->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE_BRUSH))) { + public function onBreak(BlockBreakEvent $event) : void{ + if(!is_null($event->getItem()->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE)) || !is_null($event->getItem()->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE_BRUSH))){ $event->cancel(); - try { + try{ $this->onBreakBlock($event); - } catch (Exception $error) { + }catch(Exception $error){ $event->getPlayer()->sendMessage(Loader::PREFIX . TF::RED . "Interaction failed!"); $event->getPlayer()->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage()); + Loader::getInstance()->getLogger()->logException($error); } } } @@ -167,16 +167,18 @@ public function onBreak(BlockBreakEvent $event): void /** * TODO use tool classes + * * @param BlockBreakEvent $event + * * @throws AssumptionFailedError * @throws Error * @throws SessionException */ - private function onBreakBlock(BlockBreakEvent $event): void - { + private function onBreakBlock(BlockBreakEvent $event) : void{ $session = SessionHelper::getUserSession($event->getPlayer()); - if (!$session instanceof UserSession) return; - switch ($event->getItem()->getId()) { + if(!$session instanceof UserSession) return; + $item = $event->getItem(); + switch($item->getId()){ case ItemIds::WOODEN_AXE: { if(!$session->isWandEnabled()){ @@ -194,11 +196,20 @@ private function onBreakBlock(BlockBreakEvent $event): void } case ItemIds::STICK: { - if (!$session->isDebugToolEnabled()) { + if(!$session->isDebugToolEnabled()){ $session->sendMessage(TF::RED . $session->getLanguage()->translateString("tool.debug.disabled")); break; } - $event->getPlayer()->sendMessage($event->getBlock()->__toString() . ', variant: ' . $event->getBlock()->getIdInfo()->getVariant()); + if($item instanceof Stick){ + $event->cancel(); + $session = SessionHelper::getUserSession($event->getPlayer()); + if(!$session instanceof UserSession) return; + $session->debug ??= Debug::fromItem($item); + var_dump( + $session->debug->states, + ); + $session->debug->usePrimary($session, $event->getBlock()); + } break; } } @@ -206,7 +217,9 @@ private function onBreakBlock(BlockBreakEvent $event): void /** * TODO use tool classes + * * @param PlayerInteractEvent $event + * * @throws AssumptionFailedError * @throws Error * @throws InvalidArgumentException @@ -214,13 +227,14 @@ private function onBreakBlock(BlockBreakEvent $event): void * @throws UnexpectedTagTypeException * @throws LogicException */ - private function onRightClickBlock(PlayerInteractEvent $event): void - { - if (!is_null($event->getItem()->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE)) || !is_null($event->getItem()->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE_ASSET))) { + private function onRightClickBlock(PlayerInteractEvent $event) : void{ + //TODO cleanup this method + $item = $event->getItem(); + if(!is_null($item->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE)) || !is_null($item->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE_ASSET)) || !is_null($item->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE_DEBUG))){ $event->cancel(); $session = SessionHelper::getUserSession($event->getPlayer()); - if (!$session instanceof UserSession) return; - switch ($event->getItem()->getId()) { + if(!$session instanceof UserSession) return; + switch($item->getId()){ case ItemIds::WOODEN_AXE: { if(!$session->isWandEnabled()){ @@ -238,30 +252,36 @@ private function onRightClickBlock(PlayerInteractEvent $event): void } case ItemIds::STICK: { - if (!$session->isDebugToolEnabled()) { + if(!$session->isDebugToolEnabled()){ $session->sendMessage(TF::RED . $session->getLanguage()->translateString("tool.debug.disabled")); break; } - $event->getPlayer()->sendMessage($event->getBlock()->__toString() . ', variant: ' . $event->getBlock()->getIdInfo()->getVariant()); + if($item instanceof Stick){ + $event->cancel(); + $session = SessionHelper::getUserSession($event->getPlayer()); + if(!$session instanceof UserSession) return; + $debug = Debug::fromItem($item);//FIXME avoid reconstructing the object every time + $debug->useSecondary($session, $event->getBlock()); + } break; } case ItemIds::BUCKET: { #if (){// && has perms - API::floodArea($event->getBlock()->getSide($event->getFace()), $event->getItem()->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE), $session); + API::floodArea($event->getBlock()->getSide($event->getFace()), $item->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE), $session); #} break; } case ItemIds::SCAFFOLDING: { - $tag = $event->getItem()->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE_ASSET); - if ($tag !== null) { + $tag = $item->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE_ASSET); + if($tag !== null){ $filename = $tag->getString('filename'); $asset = Loader::$assetCollection->assets[$filename];//TODO allow private assets again $target = $event->getBlock()->getSide($event->getFace())->getPosition(); - if (API::placeAsset($target, $asset, $tag, $session)) { + if(API::placeAsset($target, $asset, $tag, $session)){ $event->getPlayer()->sendMessage("Asset placed!"); - } else { + }else{ $event->getPlayer()->sendMessage("Asset not placed!"); } } @@ -269,7 +289,7 @@ private function onRightClickBlock(PlayerInteractEvent $event): void } default: { - var_dump($event->getItem()); + var_dump($item); $event->cancel(); break; } @@ -279,6 +299,7 @@ private function onRightClickBlock(PlayerInteractEvent $event): void /** * @param PlayerInteractEvent $event + * * @throws AssumptionFailedError * @throws Error * @throws InvalidArgumentException @@ -286,13 +307,12 @@ private function onRightClickBlock(PlayerInteractEvent $event): void * @throws UnexpectedTagTypeException * @throws LogicException */ - private function onLeftClickBlock(PlayerInteractEvent $event): void - { - if (!is_null($event->getItem()->getNamedTag()->getTag(API::TAG_MAGIC_WE))) { + private function onLeftClickBlock(PlayerInteractEvent $event) : void{ + if(!is_null($event->getItem()->getNamedTag()->getTag(API::TAG_MAGIC_WE))){ $event->cancel(); $session = SessionHelper::getUserSession($event->getPlayer()); - if (!$session instanceof UserSession) return; - switch ($event->getItem()->getId()) { + if(!$session instanceof UserSession) return; + switch($event->getItem()->getId()){ case ItemIds::WOODEN_AXE: { if(!$session->isWandEnabled()){ @@ -310,7 +330,7 @@ private function onLeftClickBlock(PlayerInteractEvent $event): void } case ItemIds::STICK: { - if (!$session->isDebugToolEnabled()) { + if(!$session->isDebugToolEnabled()){ $session->sendMessage(TF::RED . $session->getLanguage()->translateString("tool.debug.disabled")); break; } @@ -330,6 +350,7 @@ private function onLeftClickBlock(PlayerInteractEvent $event): void /** * @param PlayerItemUseEvent $event + * * @throws AssumptionFailedError * @throws InvalidArgumentException * @throws SessionException @@ -337,16 +358,15 @@ private function onLeftClickBlock(PlayerInteractEvent $event): void * @throws RuntimeException * @throws Exception */ - private function onRightClickAir(PlayerItemUseEvent $event): void - { - if (!is_null($event->getItem()->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE_BRUSH))) { + private function onRightClickAir(PlayerItemUseEvent $event) : void{ + if(!is_null(($item = $event->getItem())->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE_BRUSH))){ $event->cancel(); $session = SessionHelper::getUserSession($event->getPlayer()); - if (!$session instanceof UserSession) return; + if(!$session instanceof UserSession) return; $target = $event->getPlayer()->getTargetBlock(Loader::getInstance()->getToolDistance()); $brush = $session->getBrushes()->getBrushFromItem($event->getItem()); var_dump(json_encode($brush, JSON_THROW_ON_ERROR)); - if ($brush instanceof Brush && !is_null($target)) {// && has perms + if($brush instanceof Brush && !is_null($target)){// && has perms API::createBrush($target, $brush, $session); } } @@ -355,16 +375,15 @@ private function onRightClickAir(PlayerItemUseEvent $event): void /** * @param PlayerDropItemEvent $event */ - public function onDropItem(PlayerDropItemEvent $event): void - { - try { - if (!is_null($event->getItem()->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE_BRUSH))) { + public function onDropItem(PlayerDropItemEvent $event) : void{ + try{ + if(!is_null($event->getItem()->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE_BRUSH))){ $event->cancel(); $session = SessionHelper::getUserSession($event->getPlayer()); - if (!$session instanceof UserSession) return; + if(!$session instanceof UserSession) return; $brush = $session->getBrushes()->getBrushFromItem($event->getItem()); - if ($brush instanceof Brush) { - $form = (new ModalForm(function (Player $player, $data) use ($session, $brush) { + if($brush instanceof Brush){ + $form = (new ModalForm(function(Player $player, $data) use ($session, $brush){ $session->getBrushes()->removeBrush($brush, $data); })) ->setTitle(TF::BOLD . $brush->getName()) @@ -375,19 +394,18 @@ public function onDropItem(PlayerDropItemEvent $event): void ->setButton2(TF::BOLD . TF::DARK_GREEN . "Remove"); $event->getPlayer()->sendForm($form); } - } else if (!is_null($event->getItem()->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE))) { + }else if(!is_null($event->getItem()->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE))){ $event->cancel(); $event->getPlayer()->getInventory()->remove($event->getItem()); } - } catch (Exception) { + }catch(Exception){ } } - public function onSelectionChange(MWESelectionChangeEvent $event): void - { + public function onSelectionChange(MWESelectionChangeEvent $event) : void{ #Loader::getInstance()->getLogger()->debug("Called " . $event->getEventName()); $session = $event->getSession(); - if ($session instanceof UserSession && $event->getPlayer() !== null){ + if($session instanceof UserSession && $event->getPlayer() !== null){ /** @var UserSession $session */ $session->setOutlineEnabled($session->isOutlineEnabled()); //if ($session->isOutlineEnabled()) $session->createOrUpdateOutline($event->getSelection()); @@ -397,10 +415,10 @@ public function onSelectionChange(MWESelectionChangeEvent $event): void /** * TODO use tool classes + * * @param PlayerItemHeldEvent $event */ - public function onChangeSlot(PlayerItemHeldEvent $event): void - { + public function onChangeSlot(PlayerItemHeldEvent $event) : void{ /*var_dump($event->getSlot()); $player = $event->getPlayer(); #$item = $player->getInventory()->getItemInHand(); @@ -434,14 +452,13 @@ public function onChangeSlot(PlayerItemHeldEvent $event): void }*/ } - public function onStructureBlockClick(PlayerInteractEvent $event): void - { + public function onStructureBlockClick(PlayerInteractEvent $event) : void{ //$player = $event->getPlayer(); $blockTouched = $event->getBlock(); - if ($blockTouched->getId() === BlockLegacyIds::STRUCTURE_BLOCK) { - var_dump("Clicked Structure Block", (string)$blockTouched); + if($blockTouched->getId() === BlockLegacyIds::STRUCTURE_BLOCK){ + var_dump("Clicked Structure Block", (string) $blockTouched); $tile = $blockTouched->getPosition()->getWorld()->getTile($blockTouched->getPosition()->asVector3()); - if ($tile instanceof StructureBlockTile) { + if($tile instanceof StructureBlockTile){ var_dump("Is Structure Block Tile", $tile->getSpawnCompound()->toString()); // $item = $player->getInventory()->getItemInHand(); // if (!is_null(($tag = $item->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE_ASSET)))) { diff --git a/src/xenialdan/MagicWE2/Loader.php b/src/xenialdan/MagicWE2/Loader.php index 343022a..0584a98 100644 --- a/src/xenialdan/MagicWE2/Loader.php +++ b/src/xenialdan/MagicWE2/Loader.php @@ -84,45 +84,34 @@ use xenialdan\MagicWE2\session\UserSession; use xenialdan\MagicWE2\task\action\ActionRegistry; -class Loader extends PluginBase -{ +class Loader extends PluginBase{ public const FAKE_ENCH_ID = 201; public const PREFIX = TF::RESET . TF::BOLD . TF::GOLD . "[MagicWE2]" . TF::RESET . " "; public const PREFIX_ASSETS = TF::RESET . TF::BOLD . TF::GOLD . "[Asset]" . TF::RESET . " "; public const PREFIX_BRUSH = TF::RESET . TF::BOLD . TF::GOLD . "[Brush]" . TF::RESET . " "; public const PREFIX_PALETTE = TF::RESET . TF::BOLD . TF::GOLD . "[Palette]" . TF::RESET . " "; public const PREFIX_FORM = TF::RESET . TF::BOLD . TF::DARK_PURPLE . "[MWE2]" . TF::RESET . " "; - /** @var Loader|null */ private static ?Loader $instance; - /** @var null|ShapeRegistry */ public static ?ShapeRegistry $shapeRegistry; - /** @var null|ActionRegistry */ public static ?ActionRegistry $actionRegistry; - /** @var Enchantment */ public static Enchantment $ench; - /** @var Language */ private Language $baseLang; /** @var string[] Donator names */ public array $donators = []; - /** @var string */ public string $donatorData = ""; - /** @var string */ private static string $rotPath; - /** @var string */ private static string $doorRotPath; - /** @var DiverseBossBar */#BossBar + #BossBar public DiverseBossBar $wailaBossBar; - /** @var null|string */ public static ?string $scoreboardAPI; - /** @var AssetCollection */ public static AssetCollection $assetCollection; + private array $possibleBlockstates = []; /** * Returns an instance of the plugin * @return Loader */ - public static function getInstance(): Loader - { + public static function getInstance() : Loader{ return self::$instance; } @@ -131,29 +120,22 @@ public static function getInstance(): Loader * @return ShapeRegistry * @throws ShapeRegistryException */ - public static function getShapeRegistry(): ShapeRegistry - { - if (self::$shapeRegistry) return self::$shapeRegistry; + public static function getShapeRegistry() : ShapeRegistry{ + if(self::$shapeRegistry) return self::$shapeRegistry; throw new ShapeRegistryException("Shape registry is not initialized"); } - public static function getRotFlipPath(): string - { + public static function getRotFlipPath() : string{ return self::$rotPath; #return self::getInstance()->getFile() . "resources" . DIRECTORY_SEPARATOR . "rotation_flip_data.json"; } - public static function getDoorRotFlipPath(): string - { + public static function getDoorRotFlipPath() : string{ return self::$doorRotPath; #return self::getInstance()->getFile() . "resources" . DIRECTORY_SEPARATOR . "door_data.json"; } - /** - * @return bool - */ - public static function hasScoreboard(): bool - { + public static function hasScoreboard() : bool{ return self::$scoreboardAPI !== null; } @@ -169,8 +151,7 @@ public static function hasScoreboard(): bool * @throws SplitIDException * @throws TextureNotFoundException */ - public function onLoad(): void - { + public function onLoad() : void{ self::$instance = $this; self::$ench = new Enchantment("", 0, ItemFlags::AXE, ItemFlags::NONE, 1); $enchantmapinstance = EnchantmentIdMap::getInstance(); @@ -189,12 +170,14 @@ public function onLoad(): void #$blockstateparserInstance::$doorRotPath = $this->getFile() . "resources" . DIRECTORY_SEPARATOR . "door_data.json"; $fileGetContents = file_get_contents($this->getDataFolder() . "blockstate_alias_map.json"); - if ($fileGetContents === false) { + if($fileGetContents === false){ throw new PluginException("blockstate_alias_map.json could not be loaded! Blockstate support has been disabled!"); } $blockstateparserInstance->setAliasMap(json_decode($fileGetContents, true, 512, JSON_THROW_ON_ERROR)); - if ($this->getConfig()->get("developer-extended-debug", false)) $blockstateparserInstance->runTest(); + $this->possibleBlockstates = API::decodeJsonResource("possible_blockstates.json"); + + if($this->getConfig()->get("developer-extended-debug", false)) $blockstateparserInstance->runTest(); self::$assetCollection = new AssetCollection(new PluginSession($this)); } @@ -204,9 +187,8 @@ public function onLoad(): void * @return ActionRegistry * @throws ActionRegistryException */ - public static function getActionRegistry(): ActionRegistry - { - if (self::$actionRegistry) return self::$actionRegistry; + public static function getActionRegistry() : ActionRegistry{ + if(self::$actionRegistry) return self::$actionRegistry; throw new ActionRegistryException("Action registry is not initialized"); } @@ -216,13 +198,12 @@ public static function getActionRegistry(): ActionRegistry * @throws LanguageNotFoundException * @throws RuntimeException */ - public function onEnable(): void - { + public function onEnable() : void{ $lang = $this->getConfig()->get("language", Language::FALLBACK_LANGUAGE); - $this->baseLang = new Language((string)$lang, $this->getFile() . "resources" . DIRECTORY_SEPARATOR . "lang" . DIRECTORY_SEPARATOR); + $this->baseLang = new Language((string) $lang, $this->getFile() . "resources" . DIRECTORY_SEPARATOR . "lang" . DIRECTORY_SEPARATOR); $registerDeveloperCommands = $this->getConfig()->get("developer-commands", false); - if (!InvMenuHandler::isRegistered()) InvMenuHandler::register($this); - if (!PacketListener::isRegistered()) PacketListener::register($this); + if(!InvMenuHandler::isRegistered()) InvMenuHandler::register($this); + if(!PacketListener::isRegistered()) PacketListener::register($this); //PacketListener::register($this);//TODO currently this just doubles the debug spam $this->getServer()->getPluginManager()->registerEvents(new EventListener($this), $this); $this->getServer()->getCommandMap()->registerAll("MagicWE2", [ @@ -319,13 +300,13 @@ public function onEnable(): void new ToggleSidebarCommand($this, "/togglesidebar", "Toggle the sidebar", ["/sidebar"]), new ToggleOutlineCommand($this, "/toggleoutline", "Toggle the selection outline", ["/outline", "/showbounds"]), ]); - if ($registerDeveloperCommands) $this->getServer()->getCommandMap()->registerAll("MagicWE2", [ + if($registerDeveloperCommands) $this->getServer()->getCommandMap()->registerAll("MagicWE2", [ /* -- developer commands -- */ new PlaceAllBlockstatesCommand($this, "/placeallblockstates", "Place all blockstates similar to Java debug worlds"), new TestAPICommand($this, "/testapi", "Internal command for testing API methods"), new GenerateCommandsMDCommand($this, "/generatecommandsmd", "Generates the commands.md file"), ]); - if (class_exists(FormAPI::class)) { + if(class_exists(FormAPI::class)){ $this->getLogger()->notice("FormAPI found, can use ui-based commands"); $this->getServer()->getCommandMap()->registerAll("MagicWE2", [ /* -- assets -- */ @@ -337,13 +318,13 @@ public function onEnable(): void /* -- tool -- */ new FloodCommand($this, "/flood", "Opens the flood fill tool menu", ["/floodfill"]), ]); - } else { + }else{ $this->getLogger()->notice(TF::RED . "FormAPI NOT found, can NOT use ui-based commands"); } - if (class_exists(ScoreFactory::class)) { + if(class_exists(ScoreFactory::class)){ $this->getLogger()->notice("Scoreboard API found, can use scoreboards"); self::$scoreboardAPI = ScoreFactory::class; - } else { + }else{ $this->getLogger()->notice(TF::RED . "Scoreboard API NOT found, can NOT use scoreboards"); } @@ -351,38 +332,37 @@ public function onEnable(): void $this->wailaBossBar = (new DiverseBossBar())->setPercentage(1.0)/*->setColor(BarColor::RED)*/ ; //WAILA updater - $this->getScheduler()->scheduleDelayedRepeatingTask(new ClosureTask(function (): void { + $this->getScheduler()->scheduleDelayedRepeatingTask(new ClosureTask(function() : void{ /** @var BlockStatesParser $blockStatesParser */ $blockStatesParser = BlockStatesParser::getInstance(); $players = Loader::getInstance()->wailaBossBar->getPlayers(); - foreach ($players as $player) { - if (!$player->isOnline() || !SessionHelper::hasSession($player) || (($session = SessionHelper::getUserSession($player)) instanceof UserSession && !$session->isWailaEnabled())) { + foreach($players as $player){ + if(!$player->isOnline() || !SessionHelper::hasSession($player) || (($session = SessionHelper::getUserSession($player)) instanceof UserSession && !$session->isWailaEnabled())){ Loader::getInstance()->wailaBossBar->hideFrom([$player]); continue; } - if (($block = $player->getTargetBlock(10)) instanceof Block && $block->getId() !== 0) { + if(($block = $player->getTargetBlock(10)) instanceof Block && $block->getId() !== 0){ $stateEntry = $blockStatesParser->get($block->getId(), $block->getMeta()); - $title = (string)$block; + $title = (string) $block; $sub = implode("," . TF::EOL, explode(",", $blockStatesParser->prettyPrintStates($stateEntry, false))); $distancePercentage = round(floor($block->getPosition()->distance($player->getEyePos())) / 10, 1); Loader::getInstance()->wailaBossBar->showTo([$player]); Loader::getInstance()->wailaBossBar->setTitleFor([$player], $title)->setSubTitleFor([$player], $sub)->setPercentage($distancePercentage); - } else + }else Loader::getInstance()->wailaBossBar->hideFrom([$player]); } }), 60, 1); } - public function onDisable(): void - { - try { - foreach (SessionHelper::getPluginSessions() as $session) { + public function onDisable() : void{ + try{ + foreach(SessionHelper::getPluginSessions() as $session){ SessionHelper::destroySession($session, false); } - foreach (SessionHelper::getUserSessions() as $session) { + foreach(SessionHelper::getUserSessions() as $session){ SessionHelper::destroySession($session); } - } catch (JsonException $e) { + }catch(JsonException $e){ $this->getLogger()->logException($e); } } @@ -391,27 +371,23 @@ public function onDisable(): void * @return Language * @api */ - public function getLanguage(): Language - { + public function getLanguage() : Language{ return $this->baseLang; } - public function getToolDistance(): int - { - return (int)$this->getConfig()->get("tool-range", 100); + public function getToolDistance() : int{ + return (int) $this->getConfig()->get("tool-range", 100); } - public function getEditLimit(): int - { - return (int)$this->getConfig()->get("limit", -1); + public function getEditLimit() : int{ + return (int) $this->getConfig()->get("limit", -1); } /** * @return array * @throws RuntimeException */ - public static function getInfo(): array - { + public static function getInfo() : array{ return [ "| " . TF::GREEN . self::getInstance()->getFullName() . TF::RESET . " | Information |", "| --- | --- |", @@ -434,8 +410,7 @@ public static function getInfo(): array * * @return string */ - public function getLanguageFolder(): string - { + public function getLanguageFolder() : string{ return $this->getFile() . "resources" . DIRECTORY_SEPARATOR . "lang" . DIRECTORY_SEPARATOR; } @@ -445,8 +420,12 @@ public function getLanguageFolder(): string * @phpstan-return array code=>name * @throws LanguageNotFoundException */ - public function getLanguageList(): array - { + public function getLanguageList() : array{ return Language::getLanguageList($this->getLanguageFolder()); } + + //TODO move to API? + public function getPossibleBlockstates(string $state) : array{ + return $this->possibleBlockstates[$state] ?? []; + } } \ No newline at end of file diff --git a/src/xenialdan/MagicWE2/commands/tool/DebugCommand.php b/src/xenialdan/MagicWE2/commands/tool/DebugCommand.php index c7286e1..044da0a 100644 --- a/src/xenialdan/MagicWE2/commands/tool/DebugCommand.php +++ b/src/xenialdan/MagicWE2/commands/tool/DebugCommand.php @@ -53,7 +53,7 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo ->addEnchantment(new EnchantmentInstance(Loader::$ench)) ->setCustomName(Loader::PREFIX . TF::BOLD . TF::LIGHT_PURPLE . $lang->translateString('tool.debug')) ->setLore([ - TF::RESET . $lang->translateString('tool.debug.lore.1'), + TF::RESET . $lang->translateString('tool.debug.lore.1'),//TODO change lore strings TF::RESET . $lang->translateString('tool.debug.lore.2'), TF::RESET . $lang->translateString('tool.debug.lore.3') ]); diff --git a/src/xenialdan/MagicWE2/helper/ArrayUtils.php b/src/xenialdan/MagicWE2/helper/ArrayUtils.php new file mode 100644 index 0000000..1763aae --- /dev/null +++ b/src/xenialdan/MagicWE2/helper/ArrayUtils.php @@ -0,0 +1,43 @@ +getNamedTag()->setTag(API::TAG_MAGIC_WE_BRUSH, CompoundTag::create() - ->setString("id", $uuid) - ->setInt("version", $this->properties->version) - ->setString("properties", $properties) + ->setString(self::TAG_BRUSH_ID, $uuid) + ->setInt(self::TAG_BRUSH_VERSION, $this->properties->version) + ->setString(self::TAG_BRUSH_PROPERTIES, $properties) ); $item->setCustomName(Loader::PREFIX . TF::BOLD . TF::LIGHT_PURPLE . $this->getName()); $item->setLore($this->properties->generateLore()); diff --git a/src/xenialdan/MagicWE2/tool/Debug.php b/src/xenialdan/MagicWE2/tool/Debug.php new file mode 100644 index 0000000..f26668a --- /dev/null +++ b/src/xenialdan/MagicWE2/tool/Debug.php @@ -0,0 +1,160 @@ +getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE_DEBUG); + if($compoundTag !== null){ + var_dump(API::compoundToArray($compoundTag)); + //blockIdentifier is the namespaced name of the block + //state is the most recently modified state of the block + foreach($compoundTag->getValue() as $blockIdentifier => $state){ + $possibleBlockstates = Loader::getInstance()->getPossibleBlockstates($state->getValue()); + if(array_key_exists($state->getValue(), $possibleBlockstates)){ + $debug->states[$blockIdentifier][$state->getValue()] = $possibleBlockstates[$state->getValue()];//TODO + } + } + } + var_dump($debug->states); + return $debug; + } + + /** + * @throws TypeError + */ + public function toItem(Language $lang) : Item{ + $item = VanillaItems::STICK() + ->addEnchantment(new EnchantmentInstance(Loader::$ench)) + ->setCustomName(Loader::PREFIX . TF::BOLD . TF::LIGHT_PURPLE . $lang->translateString('tool.debug')) + ->setLore([ + TF::RESET . $lang->translateString('tool.debug.lore.1'),//TODO change lore strings + TF::RESET . $lang->translateString('tool.debug.lore.2'), + TF::RESET . $lang->translateString('tool.debug.lore.3') + ]); + $compound = CompoundTag::create(); + foreach($this->states as $blockIdentifier => $state){ + $compound->setString($blockIdentifier, (string) current($state));//TODO + } + $item->getNamedTag()->setTag(API::TAG_MAGIC_WE_DEBUG, $compound); + return $item; + } + + public function getCurrentState(string $blockIdentifier) : ?string{ + if(array_key_exists($blockIdentifier, $this->states)){ + return key($this->states[$blockIdentifier]); + } + return null; + } + + public function advanceState(string $blockIdentifier, bool $reverse = false) : ?string{ + if(array_key_exists($blockIdentifier, $this->states)){ + return $reverse ? ArrayUtils::regressWrap($this->states[$blockIdentifier])[0] : ArrayUtils::advanceWrap($this->states[$blockIdentifier])[0]; + } + return null; + } + + public function getCurrentValue(string $blockIdentifier) : mixed{ + if(array_key_exists($blockIdentifier, $this->states)){ + return current($this->states[$blockIdentifier]); + } + return null; + } + + public function getName() : string{ + return "Debug";//TODO Loader::PREFIX . TF::BOLD . TF::LIGHT_PURPLE . $lang->translateString('tool.debug') + } + + public function useSecondary(UserSession $session, Block $block){ + //cycle values + /** @var BlockStatesParser $blockStatesParser */ + $blockStatesParser = BlockStatesParser::getInstance(); + $blockState = $blockStatesParser->getFromBlock($block); + $stringId = $blockState->state->getId(); + + $array = Loader::getInstance()->getPossibleBlockstates($stringId); + + /** @var Tag $state */ + $state = current($this->states[$stringId]); + var_dump($state->toString()); + } + + public function usePrimary(UserSession $session, Block $block){ + //cycle states + /** @var BlockStatesParser $blockStatesParser */ + $blockStatesParser = BlockStatesParser::getInstance(); + $blockState = $blockStatesParser->getFromBlock($block); + $stringId = $blockState->state->getId(); + + //TODO add sneak + var_dump($this->getCurrentState($stringId)); + var_dump($this->getCurrentValue($stringId)); + var_dump(__LINE__, $this->states); + //$array = ($this->states[$stringId] ??= $this->stateToArray($blockState->state->getBlockState()->getCompoundTag("states"))); + $this->states[$stringId] ??= $this->stateToArray($blockState->state->getBlockState()->getCompoundTag("states")); + $array = $this->states[$stringId]; + var_dump(__LINE__, $this->states); + var_dump($this->getCurrentState($stringId)); + var_dump($this->getCurrentValue($stringId)); + var_dump(ArrayUtils::advanceWrap($array)); + } + + private function stateToArray(CompoundTag $cstate) : array{ + $array = []; + foreach($cstate->getValue() as $state => $value2){ + $possibleBlockstates = Loader::getInstance()->getPossibleBlockstates($state); + var_dump(__LINE__, $state, $value2, $possibleBlockstates); + ArrayUtils::setPointerToValue($possibleBlockstates, $value2->getValue()); + $array[$state] = $possibleBlockstates; + } + var_dump($array); + return $array; + } + + //TODO add rightClickAir and leftClickAir to Tool +} \ No newline at end of file From c14de4ae1ff70c1276df42d3f28062dce89c4718 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Sun, 24 Jul 2022 21:12:28 +0200 Subject: [PATCH 09/24] v10.3.0: Debug stick state and value switching working TODO make compatible with JE debug stick NBT --- plugin.yml | 2 +- src/xenialdan/MagicWE2/EventListener.php | 8 +-- src/xenialdan/MagicWE2/helper/ArrayUtils.php | 4 +- src/xenialdan/MagicWE2/tool/Debug.php | 76 ++++++++++++++------ 4 files changed, 60 insertions(+), 30 deletions(-) diff --git a/plugin.yml b/plugin.yml index 9a6df1a..5b7dc63 100644 --- a/plugin.yml +++ b/plugin.yml @@ -1,7 +1,7 @@ --- name: MagicWE2 main: xenialdan\MagicWE2\Loader -version: 10.2.2 +version: 10.3.0 api: ["4.0.0"] php: [ "8.0" ] softdepend: [ "DEVirion" ] diff --git a/src/xenialdan/MagicWE2/EventListener.php b/src/xenialdan/MagicWE2/EventListener.php index bd18308..b0a867f 100644 --- a/src/xenialdan/MagicWE2/EventListener.php +++ b/src/xenialdan/MagicWE2/EventListener.php @@ -205,9 +205,6 @@ private function onBreakBlock(BlockBreakEvent $event) : void{ $session = SessionHelper::getUserSession($event->getPlayer()); if(!$session instanceof UserSession) return; $session->debug ??= Debug::fromItem($item); - var_dump( - $session->debug->states, - ); $session->debug->usePrimary($session, $event->getBlock()); } break; @@ -259,9 +256,10 @@ private function onRightClickBlock(PlayerInteractEvent $event) : void{ if($item instanceof Stick){ $event->cancel(); $session = SessionHelper::getUserSession($event->getPlayer()); + if(!$session instanceof UserSession) return; - $debug = Debug::fromItem($item);//FIXME avoid reconstructing the object every time - $debug->useSecondary($session, $event->getBlock()); + $session->debug ??= Debug::fromItem($item); + $session->debug->useSecondary($session, $event->getBlock()); } break; } diff --git a/src/xenialdan/MagicWE2/helper/ArrayUtils.php b/src/xenialdan/MagicWE2/helper/ArrayUtils.php index 1763aae..e195cd4 100644 --- a/src/xenialdan/MagicWE2/helper/ArrayUtils.php +++ b/src/xenialdan/MagicWE2/helper/ArrayUtils.php @@ -4,6 +4,7 @@ namespace xenialdan\MagicWE2\helper; +use function current; use function reset; class ArrayUtils{ @@ -38,6 +39,7 @@ public static function hasPrev(array $array) : bool{ public static function setPointerToValue(array &$array, $value) : void{ reset($array); - while(current($array) !== $value) next($array); + #var_dump($array,current($array),$value); + while(current($array) !== $value && self::hasNext($array)) next($array); } } \ No newline at end of file diff --git a/src/xenialdan/MagicWE2/tool/Debug.php b/src/xenialdan/MagicWE2/tool/Debug.php index f26668a..4756ee9 100644 --- a/src/xenialdan/MagicWE2/tool/Debug.php +++ b/src/xenialdan/MagicWE2/tool/Debug.php @@ -10,12 +10,15 @@ use pocketmine\item\Stick; use pocketmine\item\VanillaItems; use pocketmine\lang\Language; +use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\CompoundTag; -use pocketmine\nbt\tag\Tag; +use pocketmine\nbt\tag\IntTag; +use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\UnexpectedTagTypeException; use pocketmine\utils\TextFormat as TF; use TypeError; use xenialdan\libblockstate\BlockStatesParser; +use xenialdan\libblockstate\exception\BlockQueryParsingFailedException; use xenialdan\MagicWE2\API; use xenialdan\MagicWE2\helper\ArrayUtils; use xenialdan\MagicWE2\Loader; @@ -99,13 +102,6 @@ public function advanceState(string $blockIdentifier, bool $reverse = false) : ? return null; } - public function getCurrentValue(string $blockIdentifier) : mixed{ - if(array_key_exists($blockIdentifier, $this->states)){ - return current($this->states[$blockIdentifier]); - } - return null; - } - public function getName() : string{ return "Debug";//TODO Loader::PREFIX . TF::BOLD . TF::LIGHT_PURPLE . $lang->translateString('tool.debug') } @@ -117,11 +113,45 @@ public function useSecondary(UserSession $session, Block $block){ $blockState = $blockStatesParser->getFromBlock($block); $stringId = $blockState->state->getId(); - $array = Loader::getInstance()->getPossibleBlockstates($stringId); + #var_dump($this->states, $stringId); + #var_dump(Loader::getInstance()->getPossibleBlockstates($stringId)); - /** @var Tag $state */ - $state = current($this->states[$stringId]); - var_dump($state->toString()); + $current = $this->getCurrentState($stringId); + #var_dump($current); + + if($current === null){ + $session->sendMessage(TF::RED . "States uninitialized, left click the block first"); + return; + } + + //$possibleBlockstates = Loader::getInstance()->getPossibleBlockstates($stringId); + $blockStateTag = $blockState->state->getBlockState()->getCompoundTag("states")->getTag($current); + #var_dump(__LINE__, $blockStateTag); + $possibleBlockstates = $this->states[$stringId][$current]; + #var_dump(__LINE__, $possibleBlockstates, current($possibleBlockstates)); + ArrayUtils::setPointerToValue($possibleBlockstates, $blockStateTag->getValue()); + #var_dump(__LINE__, $possibleBlockstates, current($possibleBlockstates)); + //TODO add sneaking to reverse + $session->getPlayer()->isSneaking() ? ArrayUtils::regressWrap($possibleBlockstates) : ArrayUtils::advanceWrap($possibleBlockstates); + $next = current($possibleBlockstates); + #var_dump($next); + $newBS = clone $blockState->state->getBlockState(); + match (true) { + $blockStateTag instanceof StringTag => $newBS->getCompoundTag("states")->setString($current, (string) $next), + $blockStateTag instanceof IntTag => $newBS->getCompoundTag("states")->setInt($current, (int) $next), + $blockStateTag instanceof ByteTag => $newBS->getCompoundTag("states")->setByte($current, (int) $next), + default => throw new UnexpectedTagTypeException("Unexpected tag type") + }; + #var_dump($blockStateTag); + try{ + $newBlock = $blockStatesParser->getFromCompound($newBS); + }catch(BlockQueryParsingFailedException $e){ + $session->getPlayer()->sendMessage(TF::RED . "Error occurred whilst changing $current to " . $next); + Loader::getInstance()->getLogger()->logException($e); + return; + } + $block->getPosition()->getWorld()->setBlock($block->getPosition(), $newBlock->getBlock()); + $session->getPlayer()->sendMessage(TF::GREEN . "State changed to " . $next); } public function usePrimary(UserSession $session, Block $block){ @@ -131,28 +161,28 @@ public function usePrimary(UserSession $session, Block $block){ $blockState = $blockStatesParser->getFromBlock($block); $stringId = $blockState->state->getId(); - //TODO add sneak - var_dump($this->getCurrentState($stringId)); - var_dump($this->getCurrentValue($stringId)); - var_dump(__LINE__, $this->states); + #var_dump($this->getCurrentState($stringId)); + #var_dump(__LINE__, $this->states); //$array = ($this->states[$stringId] ??= $this->stateToArray($blockState->state->getBlockState()->getCompoundTag("states"))); $this->states[$stringId] ??= $this->stateToArray($blockState->state->getBlockState()->getCompoundTag("states")); - $array = $this->states[$stringId]; - var_dump(__LINE__, $this->states); - var_dump($this->getCurrentState($stringId)); - var_dump($this->getCurrentValue($stringId)); - var_dump(ArrayUtils::advanceWrap($array)); + $array = &$this->states[$stringId]; + #var_dump(__LINE__, $this->states); + #var_dump($this->getCurrentState($stringId)); + //advance state + $session->getPlayer()->isSneaking() ? ArrayUtils::regressWrap($array) : ArrayUtils::advanceWrap($array); + #$session->getPlayer()->sendTip("Targeted blockstate: " . $this->getCurrentState($stringId)); + $session->getPlayer()->sendActionBarMessage("Targeted blockstate: " . $this->getCurrentState($stringId)); } private function stateToArray(CompoundTag $cstate) : array{ $array = []; foreach($cstate->getValue() as $state => $value2){ $possibleBlockstates = Loader::getInstance()->getPossibleBlockstates($state); - var_dump(__LINE__, $state, $value2, $possibleBlockstates); + #var_dump(__LINE__, $state, $value2, $possibleBlockstates); ArrayUtils::setPointerToValue($possibleBlockstates, $value2->getValue()); $array[$state] = $possibleBlockstates; } - var_dump($array); + #var_dump($array); return $array; } From 81c4bc22c54822c23518f25e9291511fe2751f58 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Fri, 5 Aug 2022 07:08:14 +0200 Subject: [PATCH 10/24] Session debug stick saving and restoring, updated translations --- resources/lang/eng.ini | 13 ++--- src/xenialdan/MagicWE2/EventListener.php | 1 + .../MagicWE2/commands/tool/DebugCommand.php | 15 +----- .../MagicWE2/helper/SessionHelper.php | 14 ++++++ .../MagicWE2/session/UserSession.php | 13 +++-- src/xenialdan/MagicWE2/tool/Debug.php | 49 ++++++++++++++----- 6 files changed, 70 insertions(+), 35 deletions(-) diff --git a/resources/lang/eng.ini b/resources/lang/eng.ini index a79e2ee..d3264f4 100644 --- a/resources/lang/eng.ini +++ b/resources/lang/eng.ini @@ -78,12 +78,13 @@ tool.wand.lore.3 = "Use //togglewand to toggle it's functionality" tool.wand.disabled = "The wand tool is disabled. Use //togglewand to re-enable it" tool.wand.setenabled = "The wand tool is now {%0}!" ; debug tool -tool.debug = "Debug Tool" -tool.debug.lore.1 = "Left click a block to get information" -tool.debug.lore.2 = "like the name and damage values of a block" -tool.debug.lore.3 = "Use //toggledebug to toggle it's functionality" -tool.debug.disabled = "The debug tool is disabled. Use //toggledebug to re-enable it" -tool.debug.setenabled = "The debug tool is now {%0}!" +tool.debug = "Debug Stick" +tool.debug.lore.1 = "Left click a block to select a blockstate" +tool.debug.lore.2 = "Right click a block to advance the blockstate's value" +tool.debug.lore.3 = "Sneak to reverse the order" +tool.debug.lore.4 = "Use //toggledebug to toggle it's functionality" +tool.debug.disabled = "The debug stick is disabled. Use //toggledebug to re-enable it" +tool.debug.setenabled = "The debug stick is now {%0}!" ; WAILA tool (What am i looking at) tool.waila = "Waila" tool.waila.setenabled = "The Waila utility is now {%0}!" diff --git a/src/xenialdan/MagicWE2/EventListener.php b/src/xenialdan/MagicWE2/EventListener.php index b0a867f..d10728f 100644 --- a/src/xenialdan/MagicWE2/EventListener.php +++ b/src/xenialdan/MagicWE2/EventListener.php @@ -260,6 +260,7 @@ private function onRightClickBlock(PlayerInteractEvent $event) : void{ if(!$session instanceof UserSession) return; $session->debug ??= Debug::fromItem($item); $session->debug->useSecondary($session, $event->getBlock()); + var_dump($session->debug->toItem($session->getLanguage())->getNamedTag()); } break; } diff --git a/src/xenialdan/MagicWE2/commands/tool/DebugCommand.php b/src/xenialdan/MagicWE2/commands/tool/DebugCommand.php index 044da0a..21beb52 100644 --- a/src/xenialdan/MagicWE2/commands/tool/DebugCommand.php +++ b/src/xenialdan/MagicWE2/commands/tool/DebugCommand.php @@ -9,15 +9,12 @@ use Exception; use InvalidArgumentException; use pocketmine\command\CommandSender; -use pocketmine\item\enchantment\EnchantmentInstance; -use pocketmine\item\VanillaItems; -use pocketmine\nbt\tag\CompoundTag; use pocketmine\player\Player; use pocketmine\utils\TextFormat as TF; -use xenialdan\MagicWE2\API; use xenialdan\MagicWE2\exception\SessionException; use xenialdan\MagicWE2\helper\SessionHelper; use xenialdan\MagicWE2\Loader; +use xenialdan\MagicWE2\tool\Debug; class DebugCommand extends BaseCommand { @@ -49,15 +46,7 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo } /** @var Player $sender */ try { - $item = VanillaItems::STICK() - ->addEnchantment(new EnchantmentInstance(Loader::$ench)) - ->setCustomName(Loader::PREFIX . TF::BOLD . TF::LIGHT_PURPLE . $lang->translateString('tool.debug')) - ->setLore([ - TF::RESET . $lang->translateString('tool.debug.lore.1'),//TODO change lore strings - TF::RESET . $lang->translateString('tool.debug.lore.2'), - TF::RESET . $lang->translateString('tool.debug.lore.3') - ]); - $item->getNamedTag()->setTag(API::TAG_MAGIC_WE, CompoundTag::create()); + $item = ($session->debug ?? (new Debug()))->toItem($lang); $sender->getInventory()->addItem($item); } catch (Exception $error) { $sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error')); diff --git a/src/xenialdan/MagicWE2/helper/SessionHelper.php b/src/xenialdan/MagicWE2/helper/SessionHelper.php index ba699e0..d4d4729 100644 --- a/src/xenialdan/MagicWE2/helper/SessionHelper.php +++ b/src/xenialdan/MagicWE2/helper/SessionHelper.php @@ -9,6 +9,8 @@ use JsonException; use pocketmine\entity\InvalidSkinException; use pocketmine\entity\Skin; +use pocketmine\item\Item; +use pocketmine\item\Stick; use pocketmine\math\Vector3; use pocketmine\player\Player; use pocketmine\plugin\Plugin; @@ -27,9 +29,11 @@ use xenialdan\MagicWE2\session\UserSession; use xenialdan\MagicWE2\tool\Brush; use xenialdan\MagicWE2\tool\BrushProperties; +use xenialdan\MagicWE2\tool\Debug; use function array_filter; use function array_values; use function count; +use function var_dump; class SessionHelper{ /** @var array */ @@ -197,6 +201,7 @@ public static function loadUserSession(Player $player) : ?UserSession{ } $session = new UserSession($player); try{ + //TODO use libmarshal to load data $session->setUUID(UuidV4::fromString($data["uuid"])); $session->setWandEnabled($data["wandEnabled"]); $session->setDebugToolEnabled($data["debugToolEnabled"]); @@ -241,6 +246,15 @@ public static function loadUserSession(Player $player) : ?UserSession{ } } $session->setOutlineEnabled($data["outlineEnabled"]); + $debugData = $data["debug"] ?? null; + var_dump($debugData); + if(!is_null($debugData)){ + $debugStick = Item::jsonDeserialize($debugData); + var_dump($debugStick); + if(!$debugStick instanceof Stick) Loader::getInstance()->getLogger()->info("Debug stick data could not be loaded, ignoring"); + else $session->debug = Debug::fromItem($debugStick); + var_dump($session->debug->toItem($session->getLanguage())->getNamedTag()); + } //TODO clipboard }catch(Exception $e){ Loader::getInstance()->getLogger()->logException($e); diff --git a/src/xenialdan/MagicWE2/session/UserSession.php b/src/xenialdan/MagicWE2/session/UserSession.php index b720622..7efe9a2 100644 --- a/src/xenialdan/MagicWE2/session/UserSession.php +++ b/src/xenialdan/MagicWE2/session/UserSession.php @@ -23,6 +23,7 @@ use xenialdan\MagicWE2\session\data\PaletteCollection; use xenialdan\MagicWE2\tool\Debug; use function mkdir; +use function var_dump; class UserSession extends Session implements JsonSerializable //TODO use JsonMapper { @@ -240,11 +241,12 @@ public function cleanupInventory(): void public function __toString() { + //TODO translations return __CLASS__ . " UUID: " . $this->getUUID()->__toString() . " Player: " . $this->getPlayer()->getName() . " Wand tool enabled: " . ($this->isWandEnabled() ? "enabled" : "disabled") . - " Debug tool enabled: " . ($this->isDebugToolEnabled() ? "enabled" : "disabled") . + " Debug stick enabled: " . ($this->isDebugToolEnabled() ? "enabled" : "disabled") . " WAILA enabled: " . ($this->isWailaEnabled() ? "enabled" : "disabled") . " Sidebar enabled: " . ($this->sidebarEnabled ? "enabled" : "disabled") . " Outline enabled: " . ($this->outlineEnabled ? "enabled" : "disabled") . @@ -265,9 +267,10 @@ public function sendMessage(string $message): void $this->player->sendMessage(Loader::PREFIX . $message); } + //TODO use libmarshal to serialize this public function jsonSerialize(): array { - return [ + $return = [ "uuid" => $this->getUUID()->toString(), "wandEnabled" => $this->wandEnabled, "debugToolEnabled" => $this->debugToolEnabled, @@ -278,10 +281,14 @@ public function jsonSerialize(): array //todo assets, palettes "latestSelection" => $this->getLatestSelection(), "currentClipboard" => $this->getCurrentClipboard(), - "language" => $this->getLanguage()->getLang() + "language" => $this->getLanguage()->getLang(), ]; + if($this->debug !== null) $return["debug"] = $this->debug->jsonSerialize(); + var_dump($return); + return $return; } + //TODO use libmarshal to serialize this public function save(): void { @mkdir(Loader::getInstance()->getDataFolder() . "sessions", 0777, true); diff --git a/src/xenialdan/MagicWE2/tool/Debug.php b/src/xenialdan/MagicWE2/tool/Debug.php index 4756ee9..be18a89 100644 --- a/src/xenialdan/MagicWE2/tool/Debug.php +++ b/src/xenialdan/MagicWE2/tool/Debug.php @@ -4,17 +4,21 @@ namespace xenialdan\MagicWE2\tool; +use InvalidArgumentException; +use JsonSerializable; use pocketmine\block\Block; use pocketmine\item\enchantment\EnchantmentInstance; use pocketmine\item\Item; use pocketmine\item\Stick; use pocketmine\item\VanillaItems; use pocketmine\lang\Language; +use pocketmine\nbt\NoSuchTagException; use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\UnexpectedTagTypeException; +use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\TextFormat as TF; use TypeError; use xenialdan\libblockstate\BlockStatesParser; @@ -25,16 +29,17 @@ use xenialdan\MagicWE2\session\UserSession; use function array_key_exists; use function current; +use function key; use function var_dump; -class Debug extends WETool{ +class Debug extends WETool implements JsonSerializable{ // tag:{DebugProperty:{"minecraft:jungle_leaves":"waterlogged","minecraft:waxed_cut_copper_stairs":"half","minecraft:stripped_jungle_log":"axis"}} public const TAG_DEBUG_PROPERTY = "DebugProperty"; /** - * @var string[][] + * @var string[][][] * key: "minecraft:stripped_jungle_log" * key: "axis" * value: ["x","y","z"] @@ -48,23 +53,23 @@ public function __construct(){ * @param Stick $item * * @return Debug - * @throws UnexpectedTagTypeException + * @throws UnexpectedTagTypeException|NoSuchTagException */ public static function fromItem(Stick $item) : self{ $debug = new self(); - $compoundTag = $item->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE_DEBUG); + if($item->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE) === null) throw new NoSuchTagException("Tag " . API::TAG_MAGIC_WE . " not found"); + if($item->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE_DEBUG) === null) throw new NoSuchTagException("Tag " . API::TAG_MAGIC_WE_DEBUG . " not found"); + $compoundTag = $item->getNamedTag()->getCompoundTag(self::TAG_DEBUG_PROPERTY); if($compoundTag !== null){ - var_dump(API::compoundToArray($compoundTag)); //blockIdentifier is the namespaced name of the block //state is the most recently modified state of the block foreach($compoundTag->getValue() as $blockIdentifier => $state){ $possibleBlockstates = Loader::getInstance()->getPossibleBlockstates($state->getValue()); - if(array_key_exists($state->getValue(), $possibleBlockstates)){ - $debug->states[$blockIdentifier][$state->getValue()] = $possibleBlockstates[$state->getValue()];//TODO + if(!empty($possibleBlockstates)){ + $debug->states[$blockIdentifier][$state->getValue()] = $possibleBlockstates;//TODO } } } - var_dump($debug->states); return $debug; } @@ -76,15 +81,20 @@ public function toItem(Language $lang) : Item{ ->addEnchantment(new EnchantmentInstance(Loader::$ench)) ->setCustomName(Loader::PREFIX . TF::BOLD . TF::LIGHT_PURPLE . $lang->translateString('tool.debug')) ->setLore([ - TF::RESET . $lang->translateString('tool.debug.lore.1'),//TODO change lore strings + TF::RESET . $lang->translateString('tool.debug.lore.1'),//TODO change lore strings in other languages than english TF::RESET . $lang->translateString('tool.debug.lore.2'), - TF::RESET . $lang->translateString('tool.debug.lore.3') + TF::RESET . $lang->translateString('tool.debug.lore.3'), + TF::RESET . $lang->translateString('tool.debug.lore.4') ]); $compound = CompoundTag::create(); foreach($this->states as $blockIdentifier => $state){ - $compound->setString($blockIdentifier, (string) current($state));//TODO + $compound->setString($blockIdentifier, (string) key($state));//TODO } - $item->getNamedTag()->setTag(API::TAG_MAGIC_WE_DEBUG, $compound); + var_dump($compound); + $item->getNamedTag()->setTag(API::TAG_MAGIC_WE_DEBUG, CompoundTag::create()); + $item->getNamedTag()->setTag(API::TAG_MAGIC_WE, CompoundTag::create()); + $item->getNamedTag()->setTag(self::TAG_DEBUG_PROPERTY, $compound); + var_dump($item->getNamedTag()); return $item; } @@ -106,6 +116,11 @@ public function getName() : string{ return "Debug";//TODO Loader::PREFIX . TF::BOLD . TF::LIGHT_PURPLE . $lang->translateString('tool.debug') } + /** + * @throws UnexpectedTagTypeException + * @throws InvalidArgumentException + * @throws AssumptionFailedError + */ public function useSecondary(UserSession $session, Block $block){ //cycle values /** @var BlockStatesParser $blockStatesParser */ @@ -164,7 +179,12 @@ public function usePrimary(UserSession $session, Block $block){ #var_dump($this->getCurrentState($stringId)); #var_dump(__LINE__, $this->states); //$array = ($this->states[$stringId] ??= $this->stateToArray($blockState->state->getBlockState()->getCompoundTag("states"))); - $this->states[$stringId] ??= $this->stateToArray($blockState->state->getBlockState()->getCompoundTag("states")); + $cstate = $blockState->state->getBlockState()->getCompoundTag("states"); + if($cstate === null || $cstate->count() === 0){ + $session->sendMessage(TF::RED . "Block has no states"); + return; + } + $this->states[$stringId] ??= $this->stateToArray($cstate); $array = &$this->states[$stringId]; #var_dump(__LINE__, $this->states); #var_dump($this->getCurrentState($stringId)); @@ -187,4 +207,7 @@ private function stateToArray(CompoundTag $cstate) : array{ } //TODO add rightClickAir and leftClickAir to Tool + public function jsonSerialize() : array{ + return $this->toItem(Loader::getInstance()->getLanguage())->jsonSerialize(); + } } \ No newline at end of file From 68e1a28a6a9260cabc35a590f6742ef8381fb402 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Fri, 5 Aug 2022 22:40:06 +0200 Subject: [PATCH 11/24] Added WIP blockstate rotation code - Inform user about crashed tasks - Fix empty rotation data on async threads (hack, TODO store globabally/shared) - Use libblockstate's replaceBlockStateValue method for rotate/flip/debug stick - Change blockstates in replace/flip - Added API::entryToState() and API::stateToEntry() - Added API::rotateBlockState() to allow rotating on async and main thread - removed old var_dump()'s - Require libblockstate 0.1.0 to support rotation/flip --- .poggit.yml | 2 +- src/xenialdan/MagicWE2/API.php | 50 ++++++++++++++++++- src/xenialdan/MagicWE2/EventListener.php | 2 +- src/xenialdan/MagicWE2/Loader.php | 32 ++---------- .../commands/clipboard/RotateCommand.php | 3 +- .../MagicWE2/helper/SessionHelper.php | 7 ++- .../MagicWE2/session/UserSession.php | 3 +- .../task/AsyncClipboardActionTask.php | 30 ++++++----- src/xenialdan/MagicWE2/task/MWEAsyncTask.php | 9 ++-- .../MagicWE2/task/action/RotateAction.php | 9 ++-- src/xenialdan/MagicWE2/tool/Debug.php | 38 +++++--------- 11 files changed, 99 insertions(+), 86 deletions(-) diff --git a/.poggit.yml b/.poggit.yml index dc74bb1..4b49441 100644 --- a/.poggit.yml +++ b/.poggit.yml @@ -28,7 +28,7 @@ projects: version: ^0.1.7 branch: libblockstate - src: thebigsmilexd/libblockstate/libblockstate - version: ^0.0.1 + version: ^0.1.0 branch: master - src: Ifera/scorefactory/ScoreFactory version: ^3.1.0 diff --git a/src/xenialdan/MagicWE2/API.php b/src/xenialdan/MagicWE2/API.php index e8fc4d5..48a7d44 100644 --- a/src/xenialdan/MagicWE2/API.php +++ b/src/xenialdan/MagicWE2/API.php @@ -12,6 +12,7 @@ use pocketmine\block\BlockFactory; use pocketmine\math\Vector3; use pocketmine\nbt\tag\CompoundTag; +use pocketmine\nbt\UnexpectedTagTypeException; use pocketmine\player\Player; use pocketmine\Server; use pocketmine\utils\AssumptionFailedError; @@ -20,6 +21,9 @@ use pocketmine\world\Position; use RuntimeException; use xenialdan\libblockstate\BlockEntry; +use xenialdan\libblockstate\BlockState; +use xenialdan\libblockstate\BlockStatesParser; +use xenialdan\libblockstate\exception\BlockQueryParsingFailedException; use xenialdan\libstructure\format\MCStructure; use xenialdan\MagicWE2\clipboard\Clipboard; use xenialdan\MagicWE2\clipboard\SingleClipboard; @@ -44,6 +48,7 @@ use xenialdan\MagicWE2\task\AsyncPasteTask; use xenialdan\MagicWE2\task\AsyncReplaceTask; use xenialdan\MagicWE2\tool\Brush; +use function str_replace; class API { @@ -82,6 +87,7 @@ class API //TODO Split into separate Class (SchematicStorage?) /** @var Clipboard[] */ private static array $schematics = [];//TODO + public static array $rotationData = []; /** * @param Selection $selection @@ -579,6 +585,7 @@ private static function rotateClipboard(SingleClipboard $structure, int $rotatio if($rotation % 90 !== 0){ throw new InvalidArgumentException("Rotation must be divisible by 90"); } + $rotation += 180;//FIXME THIS IS A DUMB HACK BECAUSE ROTATIONS ARE FLIPPED $rotation = self::positiveModulo($rotation, 360); if($rotation === 0) return $structure; @@ -592,6 +599,8 @@ private static function rotateClipboard(SingleClipboard $structure, int $rotatio /** @var BlockEntry $entry */ foreach($structure->iterateEntries($x, $y, $z) as $entry){ //TODO set entry to rotated blockstate + $state = self::entryToState($entry); + $stateRotated = self::rotateBlockState($state, $rotation); $newV3 = match ($rotation)//TODO figure out how to avoid new Vector3 objects { @@ -600,7 +609,7 @@ private static function rotateClipboard(SingleClipboard $structure, int $rotatio RotateAction::ROTATE_270 => new Vector3($structure->selection->getSizeZ() - $z - 1, $y, $x), default => new Vector3($x, $y, $z) }; - $newClipboard->addEntry($newV3->getFloorX(), $newV3->getFloorY(), $newV3->getFloorZ(), $entry); + $newClipboard->addEntry($newV3->getFloorX(), $newV3->getFloorY(), $newV3->getFloorZ(), new BlockEntry($stateRotated->getFullId())); //TODO move origin of structure } return $newClipboard; @@ -615,4 +624,43 @@ public static function decodeJsonResource(string $filename) : array{ return $array; } + public static function entryToState(BlockEntry $entry) : BlockState{ + /** @var BlockStatesParser $parser */ + $parser = BlockStatesParser::getInstance(); + return $parser->getFullId($entry->fullId); + } + + public static function stateToEntry(BlockState $state) : BlockEntry{ + return new BlockEntry($state->getFullId()); + } + + /** + * @throws InvalidArgumentException When rotation is invalid (not divisible by 90) + * @throws UnexpectedTagTypeException + * @throws BlockQueryParsingFailedException When no such blockstate could be found + */ + private static function rotateBlockState(BlockState $state, int $rotation) : BlockState{ + $data = self::getRotationData($state, $rotation); + if(empty($data)) return $state; + + #$newState = clone $state;//TODO check if needed + $newState = $state; + return $newState->replaceBlockStateValues($data); + } + + public static function getRotationData(BlockState $blockState, int $rotation) : array{ + if($rotation !== RotateAction::ROTATE_90 && $rotation !== RotateAction::ROTATE_180 && $rotation !== RotateAction::ROTATE_270) throw new InvalidArgumentException("Invalid rotation $rotation given"); + + $id = str_replace("minecraft:", "", $blockState->state->getId()); + $meta = $blockState->state->getMeta(); + + if(!isset(API::$rotationData[$id . ":" . $meta])) return []; + + return API::$rotationData[$id . ":" . $meta][(string) $rotation] ?? []; + } + + public static function setRotationData(array $json){ + self::$rotationData = $json; + } + } \ No newline at end of file diff --git a/src/xenialdan/MagicWE2/EventListener.php b/src/xenialdan/MagicWE2/EventListener.php index d10728f..161cd19 100644 --- a/src/xenialdan/MagicWE2/EventListener.php +++ b/src/xenialdan/MagicWE2/EventListener.php @@ -260,7 +260,7 @@ private function onRightClickBlock(PlayerInteractEvent $event) : void{ if(!$session instanceof UserSession) return; $session->debug ??= Debug::fromItem($item); $session->debug->useSecondary($session, $event->getBlock()); - var_dump($session->debug->toItem($session->getLanguage())->getNamedTag()); + #var_dump($session->debug->toItem($session->getLanguage())->getNamedTag()); } break; } diff --git a/src/xenialdan/MagicWE2/Loader.php b/src/xenialdan/MagicWE2/Loader.php index 0584a98..ad5e5fc 100644 --- a/src/xenialdan/MagicWE2/Loader.php +++ b/src/xenialdan/MagicWE2/Loader.php @@ -8,10 +8,10 @@ use jackmd\scorefactory\ScoreFactory; use jojoe77777\FormAPI\FormAPI; use JsonException; +use JsonSchema\Exception\ResourceNotFoundException; use muqsit\invmenu\InvMenuHandler; use pocketmine\block\Block; use pocketmine\data\bedrock\EnchantmentIdMap; -use pocketmine\entity\InvalidSkinException; use pocketmine\item\enchantment\Enchantment; use pocketmine\item\enchantment\ItemFlags; use pocketmine\lang\Language; @@ -23,10 +23,6 @@ use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\TextFormat as TF; use RuntimeException; -use wfcore\lib\exception\GeometryNotFoundException; -use wfcore\lib\exception\GeometryParsingException; -use wfcore\lib\exception\SplitIDException; -use wfcore\lib\exception\TextureNotFoundException; use xenialdan\apibossbar\DiverseBossBar; use xenialdan\libblockstate\BlockStatesParser; use xenialdan\libstructure\PacketListener; @@ -99,8 +95,6 @@ class Loader extends PluginBase{ /** @var string[] Donator names */ public array $donators = []; public string $donatorData = ""; - private static string $rotPath; - private static string $doorRotPath; #BossBar public DiverseBossBar $wailaBossBar; public static ?string $scoreboardAPI; @@ -125,35 +119,21 @@ public static function getShapeRegistry() : ShapeRegistry{ throw new ShapeRegistryException("Shape registry is not initialized"); } - public static function getRotFlipPath() : string{ - return self::$rotPath; - #return self::getInstance()->getFile() . "resources" . DIRECTORY_SEPARATOR . "rotation_flip_data.json"; - } - - public static function getDoorRotFlipPath() : string{ - return self::$doorRotPath; - #return self::getInstance()->getFile() . "resources" . DIRECTORY_SEPARATOR . "door_data.json"; - } - public static function hasScoreboard() : bool{ return self::$scoreboardAPI !== null; } /** * @throws AssumptionFailedError - * @throws InvalidArgumentException * @throws JsonException * @throws PluginException * @throws RuntimeException - * @throws InvalidSkinException - * @throws GeometryNotFoundException - * @throws GeometryParsingException - * @throws SplitIDException - * @throws TextureNotFoundException + * @throws ResourceNotFoundException */ public function onLoad() : void{ self::$instance = $this; self::$ench = new Enchantment("", 0, ItemFlags::AXE, ItemFlags::NONE, 1); + /** @var EnchantmentIdMap $enchantmapinstance */ $enchantmapinstance = EnchantmentIdMap::getInstance(); $enchantmapinstance->register(self::FAKE_ENCH_ID, self::$ench); self::$shapeRegistry = new ShapeRegistry(); @@ -162,12 +142,10 @@ public function onLoad() : void{ #$this->saveResource("rotation_flip_data.json", true); $this->saveResource("blockstate_alias_map.json", true); - self::$rotPath = $this->getFile() . "resources" . DIRECTORY_SEPARATOR . "rotation_flip_data.json"; - self::$doorRotPath = $this->getFile() . "resources" . DIRECTORY_SEPARATOR . "door_data.json"; + API::setRotationData(API::decodeJsonResource("rotation_flip_data.json")); + #$this->doorRotationData = API::decodeJsonResource("door_data.json"); /** @var BlockStatesParser $blockstateparserInstance */ $blockstateparserInstance = BlockStatesParser::getInstance(); - #$blockstateparserInstance::$rotPath = $this->getFile() . "resources" . DIRECTORY_SEPARATOR . "rotation_flip_data.json"; - #$blockstateparserInstance::$doorRotPath = $this->getFile() . "resources" . DIRECTORY_SEPARATOR . "door_data.json"; $fileGetContents = file_get_contents($this->getDataFolder() . "blockstate_alias_map.json"); if($fileGetContents === false){ diff --git a/src/xenialdan/MagicWE2/commands/clipboard/RotateCommand.php b/src/xenialdan/MagicWE2/commands/clipboard/RotateCommand.php index ac07d92..d02379d 100644 --- a/src/xenialdan/MagicWE2/commands/clipboard/RotateCommand.php +++ b/src/xenialdan/MagicWE2/commands/clipboard/RotateCommand.php @@ -66,9 +66,10 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo throw new SessionException($lang->translateString('error.noclipboard')); } $action = new RotateAction($angle/*, $aroundOrigin*/);//TODO reenable origin support if error fixed: does not rotate. Let's see if PHPStan find it for me! + #$action->rotationData = API::$rotationData; #$offset = $selection->getShape()->getMinVec3()->subtract($session->getPlayer()->asVector3()->floor())->floor(); #$action->setClipboardVector($offset); - var_dump($action); + #var_dump($action); Server::getInstance()->getAsyncPool()->submitTask( new AsyncClipboardActionTask( $session->getUUID(), diff --git a/src/xenialdan/MagicWE2/helper/SessionHelper.php b/src/xenialdan/MagicWE2/helper/SessionHelper.php index d4d4729..e0ed422 100644 --- a/src/xenialdan/MagicWE2/helper/SessionHelper.php +++ b/src/xenialdan/MagicWE2/helper/SessionHelper.php @@ -33,7 +33,6 @@ use function array_filter; use function array_values; use function count; -use function var_dump; class SessionHelper{ /** @var array */ @@ -247,13 +246,13 @@ public static function loadUserSession(Player $player) : ?UserSession{ } $session->setOutlineEnabled($data["outlineEnabled"]); $debugData = $data["debug"] ?? null; - var_dump($debugData); + #var_dump($debugData); if(!is_null($debugData)){ $debugStick = Item::jsonDeserialize($debugData); - var_dump($debugStick); + #var_dump($debugStick); if(!$debugStick instanceof Stick) Loader::getInstance()->getLogger()->info("Debug stick data could not be loaded, ignoring"); else $session->debug = Debug::fromItem($debugStick); - var_dump($session->debug->toItem($session->getLanguage())->getNamedTag()); + #var_dump($session->debug->toItem($session->getLanguage())->getNamedTag()); } //TODO clipboard }catch(Exception $e){ diff --git a/src/xenialdan/MagicWE2/session/UserSession.php b/src/xenialdan/MagicWE2/session/UserSession.php index 7efe9a2..0daa8ac 100644 --- a/src/xenialdan/MagicWE2/session/UserSession.php +++ b/src/xenialdan/MagicWE2/session/UserSession.php @@ -23,7 +23,6 @@ use xenialdan\MagicWE2\session\data\PaletteCollection; use xenialdan\MagicWE2\tool\Debug; use function mkdir; -use function var_dump; class UserSession extends Session implements JsonSerializable //TODO use JsonMapper { @@ -284,7 +283,7 @@ public function jsonSerialize(): array "language" => $this->getLanguage()->getLang(), ]; if($this->debug !== null) $return["debug"] = $this->debug->jsonSerialize(); - var_dump($return); + #var_dump($return); return $return; } diff --git a/src/xenialdan/MagicWE2/task/AsyncClipboardActionTask.php b/src/xenialdan/MagicWE2/task/AsyncClipboardActionTask.php index 000c7d7..b1dd1a8 100644 --- a/src/xenialdan/MagicWE2/task/AsyncClipboardActionTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncClipboardActionTask.php @@ -8,7 +8,7 @@ use pocketmine\utils\TextFormat as TF; use Ramsey\Uuid\Uuid; use Ramsey\Uuid\UuidInterface; -use xenialdan\libblockstate\BlockStatesParser; +use xenialdan\MagicWE2\API; use xenialdan\MagicWE2\clipboard\SingleClipboard; use xenialdan\MagicWE2\exception\SessionException; use xenialdan\MagicWE2\helper\Progress; @@ -17,8 +17,10 @@ use xenialdan\MagicWE2\selection\Selection; use xenialdan\MagicWE2\session\UserSession; use xenialdan\MagicWE2\task\action\ClipboardAction; +use function count; use function igbinary_serialize; use function igbinary_unserialize; +use function var_dump; class AsyncClipboardActionTask extends MWEAsyncTask { @@ -26,9 +28,7 @@ class AsyncClipboardActionTask extends MWEAsyncTask private string $selection; private ClipboardAction $action; private string $clipboard; - - private string $rotPath; - private string $doorRotPath; + private array $rotationData; /** * AsyncClipboardActionTask constructor. @@ -37,26 +37,25 @@ class AsyncClipboardActionTask extends MWEAsyncTask * @param ClipboardAction $action * @param SingleClipboard $clipboard */ - public function __construct(UuidInterface $sessionUUID, Selection $selection, ClipboardAction $action, SingleClipboard $clipboard) - { + public function __construct(UuidInterface $sessionUUID, Selection $selection, ClipboardAction $action, SingleClipboard $clipboard){ $this->start = microtime(true); $this->sessionUUID = $sessionUUID->toString(); $this->selection = igbinary_serialize($selection);//TODO check if needed, $clipboard already holds the selection $this->clipboard = igbinary_serialize($clipboard);//TODO check if this even needs to be serialized $this->action = $action; - $this->rotPath = Loader::getRotFlipPath(); - $this->doorRotPath = Loader::getDoorRotFlipPath(); + $this->rotationData = API::$rotationData; + var_dump(__CLASS__ . " " . __FUNCTION__ . " " . __LINE__ . " " . __FILE__, count($this->rotationData)); - try { + try{ $session = SessionHelper::getSessionByUUID($sessionUUID); - if ($session instanceof UserSession) { + if($session instanceof UserSession){ $player = $session->getPlayer(); /** @var Player $player */ $session->getBossBar()->showTo([$player]); $session->getBossBar()->setTitle("Running {$action::getName()} clipboard action");//TODO better string } - } catch (SessionException $e) { + }catch(SessionException $e){ Loader::getInstance()->getLogger()->logException($e); } } @@ -67,11 +66,10 @@ public function __construct(UuidInterface $sessionUUID, Selection $selection, Cl * @return void * @throws Exception */ - public function onRun(): void - { + public function onRun(): void{ $this->publishProgress(new Progress(0, "Preparing {$this->action::getName()}")); - BlockStatesParser::$doorRotPath = $this->doorRotPath; - BlockStatesParser::$rotPath = $this->rotPath; + + var_dump(__CLASS__ . " " . __FUNCTION__ . " " . __LINE__ . " " . __FILE__, count($this->rotationData)); /** @var Selection $selection */ $selection = igbinary_unserialize($this->selection/*, ['allowed_classes' => [Selection::class]]*/);//TODO test pm4 @@ -80,7 +78,7 @@ public function onRun(): void $clipboard->selection = $selection;//TODO test. Needed to add this so that //paste works after //cut2 $messages = []; /** @var Progress $progress */ - foreach ($this->action->execute($this->sessionUUID, $selection, $changed, $clipboard, $messages) as $progress) { + foreach($this->action->execute($this->sessionUUID, $selection, $changed, $clipboard, $messages) as $progress){ $this->publishProgress($progress); } //TODO $clipboard->selection shape might change when using rotate. Fix this, so //paste chunks are correct diff --git a/src/xenialdan/MagicWE2/task/MWEAsyncTask.php b/src/xenialdan/MagicWE2/task/MWEAsyncTask.php index a0d51f3..44f8415 100644 --- a/src/xenialdan/MagicWE2/task/MWEAsyncTask.php +++ b/src/xenialdan/MagicWE2/task/MWEAsyncTask.php @@ -84,12 +84,15 @@ protected static function singleDataToBlock(array $data): Block * @param array $hackedBlockData * @return Block[] */ - public static function multipleDataToBlocks(array $hackedBlockData): array - { + public static function multipleDataToBlocks(array $hackedBlockData) : array{ $a = []; - foreach ($hackedBlockData as $datum) { + foreach($hackedBlockData as $datum){ $a[] = self::singleDataToBlock($datum); } return $a; } + + public function onError() : void{ + if($this->isCrashed()) SessionHelper::getSessionByUUID(Uuid::fromString($this->sessionUUID))->sendMessage("An error occurred while executing this task: Task crashed. Check console for details."); + } } \ No newline at end of file diff --git a/src/xenialdan/MagicWE2/task/action/RotateAction.php b/src/xenialdan/MagicWE2/task/action/RotateAction.php index 0fdeded..146f660 100644 --- a/src/xenialdan/MagicWE2/task/action/RotateAction.php +++ b/src/xenialdan/MagicWE2/task/action/RotateAction.php @@ -18,20 +18,18 @@ class RotateAction extends ClipboardAction public const ROTATE_90 = 90; public const ROTATE_180 = 180; public const ROTATE_270 = 270; - /** @var bool */ public bool $addClipboard = true; - /** @var string */ public string $completionString = '{%name} succeed, took {%took}, rotated {%changed} blocks out of {%total}'; - /** @var int */ private int $rotation; - /** @var bool */ public bool $aroundOrigin = true; + public array $rotationData = []; public function __construct(int $rotation, bool $aroundOrigin = true) { if ($rotation !== self::ROTATE_90 && $rotation !== self::ROTATE_180 && $rotation !== self::ROTATE_270) throw new InvalidArgumentException("Invalid rotation $rotation given"); $this->rotation = $rotation; $this->addClipboard = $aroundOrigin; + $this->rotationData = API::$rotationData; } public static function getName(): string @@ -58,6 +56,9 @@ public function execute(string $sessionUUID, Selection $selection, ?int &$change // /** @var BlockStatesParser $blockStatesParser */ // $blockStatesParser = BlockStatesParser::getInstance(); + #var_dump(__CLASS__ . " ". __FUNCTION__ . " " . __LINE__ . " " . __FILE__, count($this->rotationData), API::$rotationData); + API::setRotationData($this->rotationData); + #var_dump(__CLASS__ . " ". __FUNCTION__ . " " . __LINE__ . " " . __FILE__, count($this->rotationData), API::$rotationData); $clipboard = API::rotate($clipboard, $this->rotation); yield new Progress($changed / $count, "$changed/$count"); diff --git a/src/xenialdan/MagicWE2/tool/Debug.php b/src/xenialdan/MagicWE2/tool/Debug.php index be18a89..b1f6021 100644 --- a/src/xenialdan/MagicWE2/tool/Debug.php +++ b/src/xenialdan/MagicWE2/tool/Debug.php @@ -13,10 +13,7 @@ use pocketmine\item\VanillaItems; use pocketmine\lang\Language; use pocketmine\nbt\NoSuchTagException; -use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\CompoundTag; -use pocketmine\nbt\tag\IntTag; -use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\UnexpectedTagTypeException; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\TextFormat as TF; @@ -30,7 +27,6 @@ use function array_key_exists; use function current; use function key; -use function var_dump; class Debug extends WETool implements JsonSerializable{ // tag:{DebugProperty:{"minecraft:jungle_leaves":"waterlogged","minecraft:waxed_cut_copper_stairs":"half","minecraft:stripped_jungle_log":"axis"}} @@ -90,11 +86,11 @@ public function toItem(Language $lang) : Item{ foreach($this->states as $blockIdentifier => $state){ $compound->setString($blockIdentifier, (string) key($state));//TODO } - var_dump($compound); + #var_dump($compound); $item->getNamedTag()->setTag(API::TAG_MAGIC_WE_DEBUG, CompoundTag::create()); $item->getNamedTag()->setTag(API::TAG_MAGIC_WE, CompoundTag::create()); $item->getNamedTag()->setTag(self::TAG_DEBUG_PROPERTY, $compound); - var_dump($item->getNamedTag()); + #var_dump($item->getNamedTag()); return $item; } @@ -131,42 +127,32 @@ public function useSecondary(UserSession $session, Block $block){ #var_dump($this->states, $stringId); #var_dump(Loader::getInstance()->getPossibleBlockstates($stringId)); - $current = $this->getCurrentState($stringId); + $stateName = $this->getCurrentState($stringId); #var_dump($current); - if($current === null){ + if($stateName === null){ $session->sendMessage(TF::RED . "States uninitialized, left click the block first"); return; } //$possibleBlockstates = Loader::getInstance()->getPossibleBlockstates($stringId); - $blockStateTag = $blockState->state->getBlockState()->getCompoundTag("states")->getTag($current); + $blockStateTag = $blockState->state->getBlockState()->getCompoundTag("states")->getTag($stateName); #var_dump(__LINE__, $blockStateTag); - $possibleBlockstates = $this->states[$stringId][$current]; + $possibleBlockstates = $this->states[$stringId][$stateName]; #var_dump(__LINE__, $possibleBlockstates, current($possibleBlockstates)); ArrayUtils::setPointerToValue($possibleBlockstates, $blockStateTag->getValue()); #var_dump(__LINE__, $possibleBlockstates, current($possibleBlockstates)); //TODO add sneaking to reverse $session->getPlayer()->isSneaking() ? ArrayUtils::regressWrap($possibleBlockstates) : ArrayUtils::advanceWrap($possibleBlockstates); - $next = current($possibleBlockstates); + $newValue = current($possibleBlockstates); #var_dump($next); - $newBS = clone $blockState->state->getBlockState(); - match (true) { - $blockStateTag instanceof StringTag => $newBS->getCompoundTag("states")->setString($current, (string) $next), - $blockStateTag instanceof IntTag => $newBS->getCompoundTag("states")->setInt($current, (int) $next), - $blockStateTag instanceof ByteTag => $newBS->getCompoundTag("states")->setByte($current, (int) $next), - default => throw new UnexpectedTagTypeException("Unexpected tag type") - }; - #var_dump($blockStateTag); try{ - $newBlock = $blockStatesParser->getFromCompound($newBS); - }catch(BlockQueryParsingFailedException $e){ - $session->getPlayer()->sendMessage(TF::RED . "Error occurred whilst changing $current to " . $next); - Loader::getInstance()->getLogger()->logException($e); - return; + $newBlockState = $blockState->replaceBlockStateValue($stateName, $newValue); + $block->getPosition()->getWorld()->setBlock($block->getPosition(), $newBlockState->getBlock()); + $session->getPlayer()->sendMessage(TF::GREEN . "State changed to " . $newValue); + }catch(UnexpectedTagTypeException | BlockQueryParsingFailedException $e){ + $session->sendMessage(TF::RED . "Error occurred whilst changing $stateName to " . $newValue . ": " . $e->getMessage()); } - $block->getPosition()->getWorld()->setBlock($block->getPosition(), $newBlock->getBlock()); - $session->getPlayer()->sendMessage(TF::GREEN . "State changed to " . $next); } public function usePrimary(UserSession $session, Block $block){ From c64bdc3abe34c4dbfecc2d3f01d9b085bf4a4f1c Mon Sep 17 00:00:00 2001 From: XenialDan Date: Mon, 29 Aug 2022 09:36:33 +0200 Subject: [PATCH 12/24] Fix crash whilst parsing BlocksArgument No idea why usersession would be null.. but it happened, so here is a fix. --- .../MagicWE2/commands/args/BlocksArgument.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/xenialdan/MagicWE2/commands/args/BlocksArgument.php b/src/xenialdan/MagicWE2/commands/args/BlocksArgument.php index 8a014e6..1594b57 100644 --- a/src/xenialdan/MagicWE2/commands/args/BlocksArgument.php +++ b/src/xenialdan/MagicWE2/commands/args/BlocksArgument.php @@ -34,19 +34,21 @@ public function canParse(string $testString, CommandSender $sender) : bool{ } /** - * @param string $argument + * @param string $argument * @param CommandSender $sender * * @return BlockPalette * @throws SessionException */ - public function parse(string $argument, CommandSender $sender): BlockPalette - { - try { + public function parse(string $argument, CommandSender $sender) : BlockPalette{ + try{ return BlockPalette::fromString($argument); - } catch (BlockQueryAlreadyParsedException | InvalidArgumentExceptionAlias $error) { - if ($sender instanceof Player) - SessionHelper::getUserSession($sender)->sendMessage('error.command-error'); + }catch(BlockQueryAlreadyParsedException | InvalidArgumentExceptionAlias $error){ + if($sender instanceof Player){ + SessionHelper::getUserSession($sender)?->sendMessage('error.command-error'); + }else{ + $sender->sendMessage(Loader::getInstance()->getLanguage()->translateString('error.command-error')); + } $sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage()); } return BlockPalette::CREATE(); From e83b57541dfe3ae59d6bec5109c79a00682917bf Mon Sep 17 00:00:00 2001 From: XenialDan Date: Wed, 31 Aug 2022 02:43:34 +0200 Subject: [PATCH 13/24] Make the help command actually useful (display command usage) --- src/xenialdan/MagicWE2/commands/HelpCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xenialdan/MagicWE2/commands/HelpCommand.php b/src/xenialdan/MagicWE2/commands/HelpCommand.php index bba2406..34fd099 100644 --- a/src/xenialdan/MagicWE2/commands/HelpCommand.php +++ b/src/xenialdan/MagicWE2/commands/HelpCommand.php @@ -67,7 +67,7 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo } $message .= TF::RESET . TF::LIGHT_PURPLE . " [" . implode(",", $aliases) . "]"; } - $message .= TF::RESET . TF::WHITE . " " . ($command->getDescription() instanceof Translatable ? $lang->translate($command->getDescription()) : $command->getDescription()) . TF::EOL . " » " . ($command->getDescription() instanceof Translatable ? $lang->translate($command->getDescription()) : $command->getDescription()); + $message .= TF::RESET . TF::WHITE . " " . ($command->getDescription() instanceof Translatable ? $lang->translate($command->getDescription()) : $command->getDescription()) . TF::EOL . " - " . ($command->getUsage() instanceof Translatable ? $lang->translate($command->getUsage()) : $command->getUsage()); $sender->sendMessage($message); } } catch (Exception $error) { From 397d9a2edab29920aeae52435a89ad71ad45faee Mon Sep 17 00:00:00 2001 From: XenialDan Date: Wed, 31 Aug 2022 03:45:15 +0200 Subject: [PATCH 14/24] Add blockstate rotation to schematics, use replaceBlockStateValues(), use libstructure 0.2.0 --- .poggit.yml | 6 +++--- src/xenialdan/MagicWE2/API.php | 10 ++++++---- src/xenialdan/MagicWE2/helper/StructureStore.php | 3 +-- src/xenialdan/MagicWE2/tool/Debug.php | 2 +- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/.poggit.yml b/.poggit.yml index 4b49441..0cd4d27 100644 --- a/.poggit.yml +++ b/.poggit.yml @@ -25,10 +25,10 @@ projects: version: ^4.3.4 branch: "4.0" - src: thebigsmilexd/libstructure/libstructure - version: ^0.1.7 - branch: libblockstate + version: ^0.2.0 + branch: feature/filter-palette - src: thebigsmilexd/libblockstate/libblockstate - version: ^0.1.0 + version: ^0.1.2 branch: master - src: Ifera/scorefactory/ScoreFactory version: ^3.1.0 diff --git a/src/xenialdan/MagicWE2/API.php b/src/xenialdan/MagicWE2/API.php index 48a7d44..d0c390c 100644 --- a/src/xenialdan/MagicWE2/API.php +++ b/src/xenialdan/MagicWE2/API.php @@ -558,13 +558,15 @@ private static function rotateSchematic(Schematic $structure, int $rotation) : S /** @var Block $block */ foreach($structure->blocks() as $block){ //TODO set block to rotated blockstate + $state = self::entryToState(BlockEntry::fromBlock($block)); + $stateRotated = self::rotateBlockState($state, $rotation); $blocks[] = match ($rotation) { //TODO check if the new positions are calculated correctly - RotateAction::ROTATE_90 => self::setComponents($block, $structure->getLength() - $block->getPosition()->getFloorZ() - 1, $block->getPosition()->getFloorY(), $block->getPosition()->getFloorX()), - RotateAction::ROTATE_180 => self::setComponents($block, $structure->getWidth() - $block->getPosition()->getFloorX() - 1, $block->getPosition()->getFloorY(), $structure->getLength() - $block->getPosition()->getFloorZ() - 1), - RotateAction::ROTATE_270 => self::setComponents($block, $block->getPosition()->getFloorZ(), $block->getPosition()->getFloorY(), $structure->getWidth() - $block->getPosition()->getFloorX() - 1), - default => $block + RotateAction::ROTATE_90 => self::setComponents($stateRotated->getBlock(), $structure->getLength() - $block->getPosition()->getFloorZ() - 1, $block->getPosition()->getFloorY(), $block->getPosition()->getFloorX()), + RotateAction::ROTATE_180 => self::setComponents($stateRotated->getBlock(), $structure->getWidth() - $block->getPosition()->getFloorX() - 1, $block->getPosition()->getFloorY(), $structure->getLength() - $block->getPosition()->getFloorZ() - 1), + RotateAction::ROTATE_270 => self::setComponents($stateRotated->getBlock(), $block->getPosition()->getFloorZ(), $block->getPosition()->getFloorY(), $structure->getWidth() - $block->getPosition()->getFloorX() - 1), + default => $stateRotated->getBlock() }; //TODO move origin of structure } diff --git a/src/xenialdan/MagicWE2/helper/StructureStore.php b/src/xenialdan/MagicWE2/helper/StructureStore.php index 8bd081e..3026333 100644 --- a/src/xenialdan/MagicWE2/helper/StructureStore.php +++ b/src/xenialdan/MagicWE2/helper/StructureStore.php @@ -53,8 +53,7 @@ public function loadStructure(string $filename, bool $override = true): MCStruct $id = pathinfo($filename, PATHINFO_FILENAME); if (!$override && array_key_exists($id, $this->structures)) throw new InvalidArgumentException("Can not override $id"); $path = Loader::getInstance()->getDataFolder() . 'assets' . DIRECTORY_SEPARATOR . $id . '.mcstructure'; - $structure = new MCStructure(); - $structure->parse($path); + $structure = MCStructure::read($path)->parse(); $this->structures[$id] = $structure; return $this->structures[$id]; } diff --git a/src/xenialdan/MagicWE2/tool/Debug.php b/src/xenialdan/MagicWE2/tool/Debug.php index b1f6021..3c5a2ae 100644 --- a/src/xenialdan/MagicWE2/tool/Debug.php +++ b/src/xenialdan/MagicWE2/tool/Debug.php @@ -147,7 +147,7 @@ public function useSecondary(UserSession $session, Block $block){ $newValue = current($possibleBlockstates); #var_dump($next); try{ - $newBlockState = $blockState->replaceBlockStateValue($stateName, $newValue); + $newBlockState = $blockState->replaceBlockStateValues([$stateName => $newValue]); $block->getPosition()->getWorld()->setBlock($block->getPosition(), $newBlockState->getBlock()); $session->getPlayer()->sendMessage(TF::GREEN . "State changed to " . $newValue); }catch(UnexpectedTagTypeException | BlockQueryParsingFailedException $e){ From ec157de76acb06f37505bd73cc20eef3ab8555eb Mon Sep 17 00:00:00 2001 From: XenialDan Date: Mon, 3 Oct 2022 06:46:42 +0200 Subject: [PATCH 15/24] Fix fill, copy and paste tasks STEP 1 Fixed void chunks, place offset works again Removed fast chunk render hack Replace leftover AsyncChunkManager with AsyncWorld --- resources/lang/eng.ini | 1 + src/xenialdan/MagicWE2/API.php | 12 ++-- .../MagicWE2/clipboard/Clipboard.php | 17 ----- .../MagicWE2/helper/AsyncChunkManager.php | 24 ------- src/xenialdan/MagicWE2/helper/AsyncWorld.php | 33 +++++++-- .../MagicWE2/selection/Selection.php | 36 +++++----- .../MagicWE2/selection/shape/Cone.php | 8 ++- .../MagicWE2/selection/shape/Cube.php | 8 ++- .../MagicWE2/selection/shape/Cuboid.php | 14 ++-- .../MagicWE2/selection/shape/Custom.php | 8 ++- .../MagicWE2/selection/shape/Cylinder.php | 8 ++- .../MagicWE2/selection/shape/Ellipsoid.php | 8 ++- .../MagicWE2/selection/shape/Pyramid.php | 4 +- .../MagicWE2/selection/shape/Sphere.php | 8 ++- src/xenialdan/MagicWE2/task/AsyncCopyTask.php | 13 ++-- src/xenialdan/MagicWE2/task/AsyncFillTask.php | 67 ++++--------------- .../MagicWE2/task/AsyncPasteTask.php | 67 ++++++++++++++----- .../MagicWE2/task/AsyncRevertTask.php | 19 +++--- .../MagicWE2/task/action/CountAction.php | 2 +- src/xenialdan/MagicWE2/tool/Flood.php | 34 +++------- 20 files changed, 181 insertions(+), 210 deletions(-) delete mode 100644 src/xenialdan/MagicWE2/helper/AsyncChunkManager.php diff --git a/resources/lang/eng.ini b/resources/lang/eng.ini index d3264f4..7073031 100644 --- a/resources/lang/eng.ini +++ b/resources/lang/eng.ini @@ -57,6 +57,7 @@ session.language.set = "Successfully set language to {%0}" session.language.notfound = "Language {%0} not found, resetting to default" ; task task.copy.success = "Async Copy succeed, took {%0}, copied {%1} blocks out of {%2}." +task.paste.success = "Async Paste succeed, took {%0}, pasted {%1} blocks out of {%2}." task.count.success = "Async analysing succeed, took {%0}" task.count.result = "{%0} blocks found in a total of {%1} blocks" task.fill.success = "Async Fill succeed, took {%0}, {%1} blocks out of {%2} changed." diff --git a/src/xenialdan/MagicWE2/API.php b/src/xenialdan/MagicWE2/API.php index d0c390c..611f5b5 100644 --- a/src/xenialdan/MagicWE2/API.php +++ b/src/xenialdan/MagicWE2/API.php @@ -199,18 +199,18 @@ public static function pasteAsync(SingleClipboard $clipboard, Session $session, } #$c = $clipboard->getCenter(); #$clipboard->setCenter($target->asVector3());//TODO check - if ($session instanceof UserSession) { + if($session instanceof UserSession){ $player = $session->getPlayer(); /** @var Player $player */ $session->getBossBar()->showTo([$player]); } // $start = clone $target->asVector3()->floor()->addVector($clipboard->position)->floor();//start pos of paste//TODO if using rotate, this fails // $end = $start->addVector($clipboard->selection->getShape()->getMaxVec3()->subtractVector($clipboard->selection->getShape()->getMinVec3()));//add size - $shape = $clipboard->selection->getShape(); - $shape->offset($shape->getPasteVector()->subtractVector($target->asVector3())); - $shape->setPasteVector($target->asVector3()->floor());//needed - $clipboard->selection->setShape($shape);//TODO probably need to update selection - Server::getInstance()->getAsyncPool()->submitTask(new AsyncPasteTask($session->getUUID(), $clipboard)); +// $shape = $clipboard->selection->getShape(); +// $shape->offset($shape->getPasteVector()->subtractVector($target->asVector3())); +// $shape->setPasteVector($target->asVector3()->floor());//needed +// $clipboard->selection->setShape($shape);//TODO probably need to update selection + Server::getInstance()->getAsyncPool()->submitTask(new AsyncPasteTask($session->getUUID(), $clipboard, $target->floor())); } catch (Exception $e) { $session->sendMessage($e->getMessage()); Loader::getInstance()->getLogger()->logException($e); diff --git a/src/xenialdan/MagicWE2/clipboard/Clipboard.php b/src/xenialdan/MagicWE2/clipboard/Clipboard.php index a2a77a3..54b351c 100644 --- a/src/xenialdan/MagicWE2/clipboard/Clipboard.php +++ b/src/xenialdan/MagicWE2/clipboard/Clipboard.php @@ -6,11 +6,9 @@ use Exception; use pocketmine\Server; -use pocketmine\world\format\Chunk; use pocketmine\world\World; use Serializable; use xenialdan\MagicWE2\exception\SelectionException; -use xenialdan\MagicWE2\helper\AsyncChunkManager; abstract class Clipboard implements Serializable { @@ -29,21 +27,6 @@ abstract class Clipboard implements Serializable public ?int $worldId = null; public string $customName = ""; - /** - * Creates a chunk manager used for async editing - * @param Chunk[] $chunks - * @return AsyncChunkManager - */ - public static function getChunkManager(array $chunks): AsyncChunkManager - { - $manager = new AsyncChunkManager(World::Y_MIN, World::Y_MAX); - foreach ($chunks as $hash => $chunk) { - World::getXZ($hash, $x, $z); - $manager->setChunk($x, $z, $chunk); - } - return $manager; - } - /** * @return World * @throws Exception diff --git a/src/xenialdan/MagicWE2/helper/AsyncChunkManager.php b/src/xenialdan/MagicWE2/helper/AsyncChunkManager.php deleted file mode 100644 index 4285bfd..0000000 --- a/src/xenialdan/MagicWE2/helper/AsyncChunkManager.php +++ /dev/null @@ -1,24 +0,0 @@ -getBlockAt($x, $y, $z)->getFullId(); - } - - /** - * @return Chunk[] - */ - public function getChunks(): array - { - return $this->chunks; - } -} \ No newline at end of file diff --git a/src/xenialdan/MagicWE2/helper/AsyncWorld.php b/src/xenialdan/MagicWE2/helper/AsyncWorld.php index 1a59b92..6d7c183 100644 --- a/src/xenialdan/MagicWE2/helper/AsyncWorld.php +++ b/src/xenialdan/MagicWE2/helper/AsyncWorld.php @@ -5,13 +5,17 @@ namespace xenialdan\MagicWE2\helper; use pocketmine\world\format\Chunk; +use pocketmine\world\format\io\FastChunkSerializer; use pocketmine\world\SimpleChunkManager; use pocketmine\world\World; use RuntimeException; +use Serializable; use xenialdan\MagicWE2\exception\SelectionException; use xenialdan\MagicWE2\selection\Selection; +use function igbinary_serialize; +use function igbinary_unserialize; -class AsyncWorld extends SimpleChunkManager{ +class AsyncWorld extends SimpleChunkManager implements Serializable{ // /** @var CompoundTag[] *///TODO maybe CacheableNbt // protected array $tiles = []; @@ -21,7 +25,7 @@ class AsyncWorld extends SimpleChunkManager{ */ public function __construct(Selection $selection){ parent::__construct(World::Y_MIN, World::Y_MAX); - $this->copyChunks($selection); +// $this->copyChunks($selection); } /** @@ -35,7 +39,7 @@ public function getChunks() : array{ * @throws SelectionException|RuntimeException */ public function copyChunks(Selection $selection) : void{ - if(!$selection->isValid()) return; +// if(!$selection->isValid()) return; $this->cleanChunks(); $shape = $selection->getShape(); @@ -57,11 +61,28 @@ public function copyChunks(Selection $selection) : void{ } } - public function getBlockFullIdAt(int $x, int $y, int $z): int - { - if ($this->isInWorld($x, $y, $z) && ($chunk = $this->getChunk($x >> Chunk::COORD_BIT_SIZE, $z >> Chunk::COORD_BIT_SIZE)) !== null) { + public function getBlockFullIdAt(int $x, int $y, int $z) : int{ + if($this->isInWorld($x, $y, $z) && ($chunk = $this->getChunk($x >> Chunk::COORD_BIT_SIZE, $z >> Chunk::COORD_BIT_SIZE)) !== null){ return $chunk->getFullBlock($x & Chunk::COORD_MASK, $y, $z & Chunk::COORD_MASK); } return 0;//TODO idk } + + public function serialize(){ + $chunks = []; + foreach($this->getChunks() as $hash => $chunk){ + $chunks[$hash] = FastChunkSerializer::serializeTerrain($chunk); + } + return igbinary_serialize([$this->getMinY(), $this->getMaxY(), $chunks]); + } + + public function unserialize(string $data){ + [$minY, $maxY, $chunks] = igbinary_unserialize($data); + parent::__construct($minY, $maxY);//TODO test + foreach($chunks as $hash => $chunk){ + World::getXZ($hash, $x, $z); + $chunk = FastChunkSerializer::deserializeTerrain($chunk); + $this->setChunk($x, $z, $chunk); + } + } } \ No newline at end of file diff --git a/src/xenialdan/MagicWE2/selection/Selection.php b/src/xenialdan/MagicWE2/selection/Selection.php index e0642b2..090d0ae 100644 --- a/src/xenialdan/MagicWE2/selection/Selection.php +++ b/src/xenialdan/MagicWE2/selection/Selection.php @@ -57,8 +57,6 @@ public function __construct(UuidInterface $sessionUUID, World $world, ?Vector3 $ }catch(RuntimeException $e){ Loader::getInstance()->getLogger()->logException($e); } - - $this->iterator = new SubChunkIterator(new AsyncWorld($this)); } public function free() : void{ @@ -92,9 +90,9 @@ public function setWorld(World $world) : void{ }catch(RuntimeException $e){ Loader::getInstance()->getLogger()->logException($e); } - $this->free(); - $manager = $this->getIterator()->getManager(); - if($manager instanceof AsyncWorld) $manager->copyChunks($this); +// $this->free(); +// $manager = $this->getIterator()->getManager(); +// if($manager instanceof AsyncWorld) $manager->copyChunks($this); } /** @@ -132,9 +130,9 @@ public function setPos1(Position $position) : void{ }catch(RuntimeException $e){ Loader::getInstance()->getLogger()->logException($e); } - $this->free(); - $manager = $this->getIterator()->getManager(); - if($manager instanceof AsyncWorld) $manager->copyChunks($this); +// $this->free(); +// $manager = $this->getIterator()->getManager(); +// if($manager instanceof AsyncWorld) $manager->copyChunks($this); } }catch(SessionException){ //TODO log? kick? @@ -176,9 +174,9 @@ public function setPos2(Position $position) : void{ }catch(RuntimeException $e){ Loader::getInstance()->getLogger()->logException($e); } - $this->free(); - $manager = $this->getIterator()->getManager(); - if($manager instanceof AsyncWorld) $manager->copyChunks($this); +// $this->free(); +// $manager = $this->getIterator()->getManager(); +// if($manager instanceof AsyncWorld) $manager->copyChunks($this); } }catch(SessionException | SelectionException | RuntimeException $e){//TODO log? kick? Loader::getInstance()->getLogger()->logException($e); @@ -199,9 +197,9 @@ public function setShape(Shape $shape) : void{ $this->shape = $shape; try{ (new MWESelectionChangeEvent($this, MWESelectionChangeEvent::TYPE_SHAPE))->call();//might cause duplicated call - $this->free(); - $manager = $this->getIterator()->getManager(); - if($manager instanceof AsyncWorld) $manager->copyChunks($this); +// $this->free(); +// $manager = $this->getIterator()->getManager(); +// if($manager instanceof AsyncWorld) $manager->copyChunks($this); }catch(RuntimeException | SelectionException $e){ Loader::getInstance()->getLogger()->debug($e); } @@ -249,8 +247,10 @@ public function getUUID() : UuidInterface{ return $this->uuid; } - public function getIterator() : SubChunkIterator{ - return $this->iterator; + public function getIterator(bool $copyChunks = true) : SubChunkIterator{ + $manager = new AsyncWorld($this); + if($copyChunks) $manager->copyChunks($this); + return new SubChunkIterator($manager); } /** @@ -267,7 +267,7 @@ public function serialize() : string{ $this->uuid, $this->sessionUUID, $this->shape, - $this->iterator, +// $this->iterator, ]); } @@ -290,7 +290,7 @@ public function unserialize(string $data){ $this->uuid, $this->sessionUUID, $this->shape, - $this->iterator +// $this->iterator ] = unserialize($data/*, ['allowed_classes' => [__CLASS__, Vector3::class,UuidInterface::class,Shape::class]]*/);//TODO test pm4 } diff --git a/src/xenialdan/MagicWE2/selection/shape/Cone.php b/src/xenialdan/MagicWE2/selection/shape/Cone.php index 4bce5c9..cbf1d8b 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Cone.php +++ b/src/xenialdan/MagicWE2/selection/shape/Cone.php @@ -49,7 +49,7 @@ public function rotate(int $rotation) : self{ /** * Returns the blocks by their actual position * - * @param AsyncWorld $manager The world or AsyncChunkManager + * @param AsyncWorld $manager The world or AsyncWorld * @param BlockPalette $filterblocks If not empty, applying a filter on the block list * * @return Block[]|Generator @@ -91,8 +91,10 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Gen /** * Returns a flat layer of all included x z positions in selection - * @param AsyncWorld $manager The world or AsyncChunkManager - * @param int $flags + * + * @param AsyncWorld $manager The world or AsyncWorld + * @param int $flags + * * @return Generator */ public function getLayer(AsyncWorld $manager, int $flags = API::FLAG_BASE): Generator{ diff --git a/src/xenialdan/MagicWE2/selection/shape/Cube.php b/src/xenialdan/MagicWE2/selection/shape/Cube.php index 988943c..fcfcd63 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Cube.php +++ b/src/xenialdan/MagicWE2/selection/shape/Cube.php @@ -36,7 +36,7 @@ public function rotate(int $rotation) : self{ /** * Returns the blocks by their actual position * - * @param AsyncWorld $manager The world or AsyncChunkManager + * @param AsyncWorld $manager The world or AsyncWorld * @param BlockPalette $filterblocks If not empty, applying a filter on the block list * * @return Block[]|Generator @@ -69,8 +69,10 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Gen /** * Returns a flat layer of all included x z positions in selection - * @param AsyncWorld $manager The world or AsyncChunkManager - * @param int $flags + * + * @param AsyncWorld $manager The world or AsyncWorld + * @param int $flags + * * @return Generator */ public function getLayer(AsyncWorld $manager, int $flags = API::FLAG_BASE): Generator diff --git a/src/xenialdan/MagicWE2/selection/shape/Cuboid.php b/src/xenialdan/MagicWE2/selection/shape/Cuboid.php index 574e3ed..d91c8bc 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Cuboid.php +++ b/src/xenialdan/MagicWE2/selection/shape/Cuboid.php @@ -12,9 +12,10 @@ use xenialdan\MagicWE2\API; use xenialdan\MagicWE2\helper\AsyncWorld; use xenialdan\MagicWE2\helper\BlockPalette; +use function array_keys; +use function var_dump; -class Cuboid extends Shape -{ +class Cuboid extends Shape{ public int $width = 5; public int $height = 5; public int $depth = 5; @@ -62,7 +63,7 @@ public function rotate(int $rotation) : self{ /** * Returns the blocks by their actual position * - * @param AsyncWorld $manager The world or AsyncChunkManager + * @param AsyncWorld $manager The world or AsyncWorld * @param BlockPalette $filterblocks If not empty, applying a filter on the block list * * @return Block[]|Generator @@ -71,6 +72,7 @@ public function rotate(int $rotation) : self{ */ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Generator { + var_dump(array_keys($manager->getChunks())); for ($x = (int)floor($this->getMinVec3()->x); $x <= floor($this->getMaxVec3()->x); $x++) { for ($y = (int)floor($this->getMinVec3()->y); $y <= floor($this->getMaxVec3()->y); $y++) { for ($z = (int)floor($this->getMinVec3()->z); $z <= floor($this->getMaxVec3()->z); $z++) { @@ -96,8 +98,10 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Gen /** * Returns a flat layer of all included x z positions in selection - * @param AsyncWorld $manager The world or AsyncChunkManager - * @param int $flags + * + * @param AsyncWorld $manager The world or AsyncWorld + * @param int $flags + * * @return Generator */ public function getLayer(AsyncWorld $manager, int $flags = API::FLAG_BASE): Generator diff --git a/src/xenialdan/MagicWE2/selection/shape/Custom.php b/src/xenialdan/MagicWE2/selection/shape/Custom.php index 84129ad..d938a9c 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Custom.php +++ b/src/xenialdan/MagicWE2/selection/shape/Custom.php @@ -45,7 +45,7 @@ public function rotate(int $rotation) : self{ /** * Returns the blocks by their actual position * - * @param AsyncWorld $manager The world or AsyncChunkManager + * @param AsyncWorld $manager The world or AsyncWorld * @param BlockPalette $filterblocks If not empty, applying a filter on the block list * * @return Block[]|Generator @@ -62,8 +62,10 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Gen /** * Returns a flat layer of all included x z positions in selection - * @param AsyncWorld $manager The world or AsyncChunkManager - * @param int $flags + * + * @param AsyncWorld $manager The world or AsyncWorld + * @param int $flags + * * @return Generator */ public function getLayer(AsyncWorld $manager, int $flags = API::FLAG_BASE): Generator diff --git a/src/xenialdan/MagicWE2/selection/shape/Cylinder.php b/src/xenialdan/MagicWE2/selection/shape/Cylinder.php index 147047f..106a400 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Cylinder.php +++ b/src/xenialdan/MagicWE2/selection/shape/Cylinder.php @@ -45,7 +45,7 @@ public function rotate(int $rotation) : self{ /** * Returns the blocks by their actual position * - * @param AsyncWorld $manager The world or AsyncChunkManager + * @param AsyncWorld $manager The world or AsyncWorld * @param BlockPalette $filterblocks If not empty, applying a filter on the block list * * @return Block[]|Generator @@ -81,8 +81,10 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Gen /** * Returns a flat layer of all included x z positions in selection - * @param AsyncWorld $manager The world or AsyncChunkManager - * @param int $flags + * + * @param AsyncWorld $manager The world or AsyncWorld + * @param int $flags + * * @return Generator */ public function getLayer(AsyncWorld $manager, int $flags = API::FLAG_BASE): Generator{ diff --git a/src/xenialdan/MagicWE2/selection/shape/Ellipsoid.php b/src/xenialdan/MagicWE2/selection/shape/Ellipsoid.php index 2bc450e..92d04d1 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Ellipsoid.php +++ b/src/xenialdan/MagicWE2/selection/shape/Ellipsoid.php @@ -56,7 +56,7 @@ public function rotate(int $rotation) : self{ /** * Returns the blocks by their actual position * - * @param AsyncWorld $manager The world or AsyncChunkManager + * @param AsyncWorld $manager The world or AsyncWorld * @param BlockPalette $filterblocks If not empty, applying a filter on the block list * * @return Block[]|Generator @@ -107,8 +107,10 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Gen /** * Returns a flat layer of all included x z positions in selection - * @param AsyncWorld $manager The world or AsyncChunkManager - * @param int $flags + * + * @param AsyncWorld $manager The world or AsyncWorld + * @param int $flags + * * @return Generator */ public function getLayer(AsyncWorld $manager, int $flags = API::FLAG_BASE): Generator{ diff --git a/src/xenialdan/MagicWE2/selection/shape/Pyramid.php b/src/xenialdan/MagicWE2/selection/shape/Pyramid.php index ade548b..29836c2 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Pyramid.php +++ b/src/xenialdan/MagicWE2/selection/shape/Pyramid.php @@ -59,7 +59,7 @@ public function rotate(int $rotation) : self{ /** * Returns the blocks by their actual position * - * @param AsyncWorld $manager The world or AsyncChunkManager + * @param AsyncWorld $manager The world or AsyncWorld * @param BlockPalette $filterblocks If not empty, applying a filter on the block list * * @return Block[]|Generator @@ -106,7 +106,7 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Gen /** * Returns a flat layer of all included x z positions in selection * - * @param AsyncWorld $manager The world or AsyncChunkManager + * @param AsyncWorld $manager The world or AsyncWorld * @param int $flags * * @return Generator diff --git a/src/xenialdan/MagicWE2/selection/shape/Sphere.php b/src/xenialdan/MagicWE2/selection/shape/Sphere.php index be28e4e..12e715b 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Sphere.php +++ b/src/xenialdan/MagicWE2/selection/shape/Sphere.php @@ -41,7 +41,7 @@ public function rotate(int $rotation) : self{ /** * Returns the blocks by their actual position * - * @param AsyncWorld $manager The world or AsyncChunkManager + * @param AsyncWorld $manager The world or AsyncWorld * @param BlockPalette $filterblocks If not empty, applying a filter on the block list * * @return Block[]|Generator @@ -76,8 +76,10 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks) : Gen /** * Returns a flat layer of all included x z positions in selection - * @param AsyncWorld $manager The world or AsyncChunkManager - * @param int $flags + * + * @param AsyncWorld $manager The world or AsyncWorld + * @param int $flags + * * @return Generator */ public function getLayer(AsyncWorld $manager, int $flags = API::FLAG_BASE): Generator{ diff --git a/src/xenialdan/MagicWE2/task/AsyncCopyTask.php b/src/xenialdan/MagicWE2/task/AsyncCopyTask.php index aa4384c..c691c35 100644 --- a/src/xenialdan/MagicWE2/task/AsyncCopyTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncCopyTask.php @@ -12,6 +12,7 @@ use xenialdan\libblockstate\BlockEntry; use xenialdan\MagicWE2\clipboard\SingleClipboard; use xenialdan\MagicWE2\exception\SessionException; +use xenialdan\MagicWE2\helper\AsyncWorld; use xenialdan\MagicWE2\helper\BlockPalette; use xenialdan\MagicWE2\helper\SessionHelper; use xenialdan\MagicWE2\Loader; @@ -25,6 +26,7 @@ class AsyncCopyTask extends MWEAsyncTask private string $selection; private Vector3 $offset; + private AsyncWorld $manager; /** * AsyncCopyTask constructor. @@ -39,6 +41,7 @@ public function __construct(UuidInterface $sessionUUID, Selection $selection, Ve $this->sessionUUID = $sessionUUID->toString(); $this->selection = igbinary_serialize($selection); $this->offset = $offset->asVector3()->floor(); + $this->manager = $selection->getIterator()->getManager(); } /** @@ -59,7 +62,8 @@ public function onRun(): void $clipboard->selection = $selection; #$clipboard->setCenter(unserialize($this->offset)); $totalCount = $selection->getShape()->getTotalCount(); - $copied = $this->copyBlocks($selection, $clipboard); + $manager = $this->manager; + $copied = $this->copyBlocks($selection, $clipboard, $manager); #$clipboard->setShape($selection->getShape()); #$clipboard->chunks = $manager->getChunks(); $this->setResult(compact("clipboard", "copied", "totalCount")); @@ -71,17 +75,14 @@ public function onRun(): void * @return int * @throws Exception */ - private function copyBlocks(Selection $selection, SingleClipboard $clipboard): int - { - $iterator = $selection->getIterator(); - $manager = $iterator->getManager(); + private function copyBlocks(Selection $selection, SingleClipboard &$clipboard, AsyncWorld &$manager) : int{ $blockCount = $selection->getShape()->getTotalCount(); $i = 0; $lastprogress = 0; $this->publishProgress([0, "Running, copied $i blocks out of $blockCount"]); $min = $selection->getShape()->getMinVec3(); /** @var Block $block */ - foreach ($selection->getShape()->getBlocks($manager, BlockPalette::CREATE()) as $block) { + foreach($selection->getShape()->getBlocks($manager, BlockPalette::CREATE()) as $block){ #var_dump("copy chunk X: " . ($block->getX() >> 4) . " Y: " . ($block->getY() >> 4)); $newv3 = $block->getPosition()->subtractVector($min)->floor(); /** @noinspection PhpInternalEntityUsedInspection */ diff --git a/src/xenialdan/MagicWE2/task/AsyncFillTask.php b/src/xenialdan/MagicWE2/task/AsyncFillTask.php index c4ba10c..d0ec7a5 100644 --- a/src/xenialdan/MagicWE2/task/AsyncFillTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncFillTask.php @@ -7,12 +7,6 @@ use InvalidArgumentException; use MultipleIterator; use pocketmine\block\Block; -use pocketmine\block\VanillaBlocks; -use pocketmine\math\Vector3; -use pocketmine\network\mcpe\convert\RuntimeBlockMapping; -use pocketmine\network\mcpe\protocol\types\BlockPosition; -use pocketmine\network\mcpe\protocol\UpdateBlockPacket; -use pocketmine\scheduler\ClosureTask; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\TextFormat as TF; use pocketmine\world\format\Chunk; @@ -24,6 +18,7 @@ use xenialdan\MagicWE2\API; use xenialdan\MagicWE2\clipboard\RevertClipboard; use xenialdan\MagicWE2\exception\SessionException; +use xenialdan\MagicWE2\helper\AsyncWorld; use xenialdan\MagicWE2\helper\BlockPalette; use xenialdan\MagicWE2\helper\SessionHelper; use xenialdan\MagicWE2\Loader; @@ -37,6 +32,7 @@ class AsyncFillTask extends MWEAsyncTask private string $selection; //private string $newBlocks; private BlockPalette $newBlocks; + private AsyncWorld $manager; /** * AsyncFillTask constructor. @@ -52,6 +48,7 @@ public function __construct(UuidInterface $sessionUUID, Selection $selection, Bl $this->selection = igbinary_serialize($selection); //$this->newBlocks = BlockPalette::encode($newBlocks); $this->newBlocks = $newBlocks;//TODO check if serializes + $this->manager = $selection->getIterator()->getManager(); } /** @@ -60,8 +57,7 @@ public function __construct(UuidInterface $sessionUUID, Selection $selection, Bl * @return void * @throws Exception */ - public function onRun(): void - { + public function onRun(): void{ $this->publishProgress([0, "Start"]); /** @var Selection $selection */ @@ -70,10 +66,11 @@ public function onRun(): void ///** @var Block[] $newBlocks */ //$newBlocks = BlockPalette::decode($this->newBlocks);//TODO test pm4 //$oldBlocks = iterator_to_array($this->execute($selection, $manager, $newBlocks, $changed)); - $oldBlocks = iterator_to_array($this->execute($selection, $this->newBlocks, $changed)); + $manager = $this->manager; + $oldBlocks = iterator_to_array($this->execute($selection, $this->newBlocks, $changed, $manager)); - $resultChunks = $selection->getIterator()->getManager()->getChunks(); - $resultChunks = array_filter($resultChunks, static function (Chunk $chunk) { + $resultChunks = $manager->getChunks(); + $resultChunks = array_filter($resultChunks, static function(Chunk $chunk){ return $chunk->isTerrainDirty(); }); #$this->setResult(compact("resultChunks", "oldBlocks", "changed")); @@ -85,16 +82,16 @@ public function onRun(): void } /** - * @param Selection $selection + * @param Selection $selection * @param BlockPalette $newBlocks - * @param null|int $changed + * @param null|int $changed + * @param AsyncWorld $manager + * * @return Generator * @throws InvalidArgumentException * @phpstan-return Generator */ - private function execute(Selection $selection, BlockPalette $newBlocks, ?int &$changed): Generator - { - $manager = $selection->getIterator()->getManager(); + private function execute(Selection $selection, BlockPalette $newBlocks, ?int &$changed, AsyncWorld &$manager) : Generator{ $blockCount = $selection->getShape()->getTotalCount(); $lastchunkx = $lastchunkz = null; $lastprogress = 0; @@ -181,48 +178,10 @@ public function onCompletion(): void $undoChunks = $selection->getIterator()->getManager()->getChunks(); $totalCount = $selection->getShape()->getTotalCount(); $world = $selection->getWorld(); - //Awesome instant-render-changes hack - $renderHack = []; foreach($resultChunks as $hash => $chunk){ World::getXZ($hash, $x, $z); $world->setChunk($x, $z, $chunk); - for($y = World::Y_MIN; $y < World::Y_MAX; $y += Chunk::EDGE_LENGTH){//TODO check if this should be 255 or World::Y_MAX - $vector3 = new Vector3($x * 16, 0, $z * 16); - $renderHack[] = $vector3; - //$pk = UpdateBlockPacket::create($blockPosition, $fullId,0b1111, UpdateBlockPacket::DATA_LAYER_NORMAL); - /*Loader::getInstance()->getScheduler()->scheduleDelayedTask(new ClosureTask(function () use ($pk,$vector3,$world):void{ - $world->broadcastPacketToViewers($vector3,$pk); - }),5);*/ - } } - $hack1 = []; - foreach($renderHack as $value) - $hack1[] = UpdateBlockPacket::create( - BlockPosition::fromVector3($value), - RuntimeBlockMapping::getInstance()->toRuntimeId(VanillaBlocks::AIR()->getFullId()), - UpdateBlockPacket::FLAG_NETWORK, - UpdateBlockPacket::DATA_LAYER_NORMAL - ); - $hack2 = $world->createBlockUpdatePackets($renderHack); - //Awesome instant-render-changes hack - Loader::getInstance()->getScheduler()->scheduleDelayedTask(new ClosureTask(function() use ($hack1, $world) : void{ - $world->getServer()->broadcastPackets($world->getPlayers(), $hack1); - }), 1); - Loader::getInstance()->getScheduler()->scheduleDelayedTask(new ClosureTask(function() use ($hack2, $world) : void{ - $world->getServer()->broadcastPackets($world->getPlayers(), $hack2); - }), 2); - /*Loader::getInstance()->getScheduler()->scheduleDelayedTask(new ClosureTask(function () use ($renderHack,$world):void{ - $world->getServer()->broadcastPackets($world->getPlayers(),$world->createBlockUpdatePackets($renderHack)); - }),1); - Loader::getInstance()->getScheduler()->scheduleDelayedTask(new ClosureTask(function () use ($renderHack,$world):void{ - $world->getServer()->broadcastPackets($world->getPlayers(),$world->createBlockUpdatePackets($renderHack)); - }),5); - Loader::getInstance()->getScheduler()->scheduleDelayedTask(new ClosureTask(function () use ($renderHack,$world):void{ - $world->getServer()->broadcastPackets($world->getPlayers(),$world->createBlockUpdatePackets($renderHack)); - }),10); - Loader::getInstance()->getScheduler()->scheduleDelayedTask(new ClosureTask(function () use ($renderHack,$world):void{ - $world->getServer()->broadcastPackets($world->getPlayers(),$world->createBlockUpdatePackets($renderHack)); - }),15);*/ if(!is_null($session)){ $session->sendMessage(TF::GREEN . $session->getLanguage()->translateString('task.fill.success', [$this->generateTookString(), $changed, $totalCount])); $session->addRevert(new RevertClipboard($selection->worldId, $undoChunks, $oldBlocks)); diff --git a/src/xenialdan/MagicWE2/task/AsyncPasteTask.php b/src/xenialdan/MagicWE2/task/AsyncPasteTask.php index eda85e1..d2f545e 100644 --- a/src/xenialdan/MagicWE2/task/AsyncPasteTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncPasteTask.php @@ -5,9 +5,11 @@ use Exception; use Generator; use InvalidArgumentException; +use pocketmine\data\bedrock\BiomeIds; use pocketmine\math\Vector3; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\TextFormat as TF; +use pocketmine\world\format\BiomeArray; use pocketmine\world\format\Chunk; use pocketmine\world\Position; use pocketmine\world\World; @@ -18,16 +20,19 @@ use xenialdan\MagicWE2\clipboard\RevertClipboard; use xenialdan\MagicWE2\clipboard\SingleClipboard; use xenialdan\MagicWE2\exception\SessionException; +use xenialdan\MagicWE2\helper\AsyncWorld; use xenialdan\MagicWE2\helper\SessionHelper; use xenialdan\MagicWE2\Loader; use xenialdan\MagicWE2\session\UserSession; use function igbinary_serialize; use function igbinary_unserialize; +use function var_dump; class AsyncPasteTask extends MWEAsyncTask { private string $clipboard; private Vector3 $offset; + private AsyncWorld $manager; /** * AsyncPasteTask constructor. @@ -35,13 +40,31 @@ class AsyncPasteTask extends MWEAsyncTask * @param SingleClipboard $clipboard * @throws Exception */ - public function __construct(UuidInterface $sessionUUID, SingleClipboard $clipboard) - { + public function __construct(UuidInterface $sessionUUID, SingleClipboard $clipboard, Vector3 $pasteVector){ $this->start = microtime(true); - $this->offset = $clipboard->selection->getShape()->getPasteVector()->addVector($clipboard->position)->floor(); - #var_dump("paste", $selection->getShape()->getPasteVector(), "cb position", $clipboard->position, "offset", $this->offset, $clipboard); + /* + backup + $this->offset = $pasteVector->addVector($clipboard->position); + var_dump("paste", $clipboard->selection->getShape()->getPasteVector(), "cb position", $clipboard->position, "offset", $this->offset); + $clipboard->selection->getShape()->setPasteVector($clipboard->selection->getShape()->getPasteVector()->addVector($clipboard->position)); + var_dump("new paste", $clipboard->selection->getShape()->getPasteVector()); + */ + $this->offset = $pasteVector->addVector($clipboard->position); + var_dump("paste", $clipboard->selection->getShape()->getPasteVector(), "cb position", $clipboard->position, "offset", $this->offset, "aabb", $clipboard->selection->getShape()->getAABB()); + var_dump("new paste vec", $pasteVector); + var_dump("orig paste", $clipboard->selection->getShape()->getPasteVector()); + var_dump("pasteV minus offset", $clipboard->selection->getShape()->getPasteVector()->subtractVector($this->offset)); + var_dump("old minus new pos", $clipboard->selection->getShape()->getPasteVector()->subtractVector($pasteVector)); + $clipboard->selection->getShape()->setPasteVector($this->offset->add($clipboard->selection->getSizeX() / 2, $clipboard->selection->getSizeY() / 2, $clipboard->selection->getSizeZ() / 2)); + var_dump("new paste", $clipboard->selection->getShape()->getPasteVector()); $this->sessionUUID = $sessionUUID->toString(); $this->clipboard = igbinary_serialize($clipboard); + $this->manager = $clipboard->selection->getIterator()->getManager(); + var_dump(__METHOD__ . __LINE__, count($this->manager->getChunks())); + foreach($this->manager->getChunks() as $hash => $chunk){ + World::getXZ($hash, $x, $z); + var_dump(__METHOD__ . __LINE__, $hash, $x, $z); + } } /** @@ -62,13 +85,13 @@ public function onRun(): void /** @var SingleClipboard $clipboard */ $clipboard = igbinary_unserialize($this->clipboard/*, ['allowed_classes' => [SingleClipboard::class]]*/);//TODO test pm4 - $oldBlocks = iterator_to_array($this->execute($clipboard, $changed)); + $manager = $this->manager; + $oldBlocks = iterator_to_array($this->execute($clipboard, $changed, $manager)); - $manager = $clipboard->selection->getIterator()->getManager(); $resultChunks = $manager->getChunks(); - $resultChunks = array_filter($resultChunks, static function (Chunk $chunk) { - return $chunk->isTerrainDirty(); - }); +// $resultChunks = array_filter($resultChunks, static function (Chunk $chunk) { +// return $chunk->isTerrainDirty(); +// }); $this->setResult(compact("resultChunks", "oldBlocks", "changed")); } @@ -79,9 +102,8 @@ public function onRun(): void * @throws InvalidArgumentException * @phpstan-return Generator */ - private function execute(SingleClipboard $clipboard, ?int &$changed): Generator - { - $manager = $clipboard->selection->getIterator()->getManager(); + private function execute(SingleClipboard $clipboard, ?int &$changed, AsyncWorld &$manager) : Generator{ + var_dump("MANAGER CHUNK COUNT", count($manager->getChunks())); $blockCount = $clipboard->getTotalCount(); $x = $y = $z = null; $lastprogress = 0; @@ -89,7 +111,7 @@ private function execute(SingleClipboard $clipboard, ?int &$changed): Generator $changed = 0; $this->publishProgress([0, "Running, changed $changed blocks out of $blockCount"]); /** @var BlockEntry $entry */ - foreach ($clipboard->iterateEntries($x, $y, $z) as $entry) { + foreach($clipboard->iterateEntries($x, $y, $z) as $entry){ #var_dump("at cb xyz $x $y $z: $entry"); $x += $this->offset->getFloorX(); $y += $this->offset->getFloorY(); @@ -103,13 +125,21 @@ private function execute(SingleClipboard $clipboard, ?int &$changed): Generator #$new->position(($pos = Position::fromObject(new Vector3($x, $y, $z)))->getWorld(), $pos->getX(), $pos->getY(), $pos->getZ()); #$old->position(($pos = Position::fromObject(new Vector3($x, $y, $z)))->getWorld(), $pos->getX(), $pos->getY(), $pos->getZ()); #var_dump("old", $old, "new", $new); - yield self::singleBlockToData(API::setComponents($manager->getBlockAt($x, $y, $z), (int)$x, (int)$y, (int)$z)); + yield self::singleBlockToData(API::setComponents($manager->getBlockAt($x, $y, $z), (int) $x, (int) $y, (int) $z)); + + var_dump(__METHOD__ . __LINE__, World::chunkHash($x, $z), $x, $z); + if($manager->getChunk($x >> 4, $z >> 4) === null){ + $manager->setChunk($x >> 4, $z >> 4, new Chunk([], BiomeArray::fill(BiomeIds::OCEAN), false)); + } +// var_dump("ToPlace", $entry->toBlock()); +// var_dump("Before setBlockAt", API::setComponents($manager->getBlockAt($x, $y, $z), (int)$x, (int)$y, (int)$z)); $manager->setBlockAt($x, $y, $z, $new); +// var_dump("After setBlockAt", API::setComponents($manager->getBlockAt($x, $y, $z), (int)$x, (int)$y, (int)$z)); $changed++; /// $i++; $progress = floor($i / $blockCount * 100); - if ($lastprogress < $progress) {//this prevents spamming packets + if($lastprogress < $progress){//this prevents spamming packets $this->publishProgress([$progress, "Running, changed $changed blocks out of $blockCount"]); $lastprogress = $progress; } @@ -139,14 +169,15 @@ public function onCompletion(): void /** @var SingleClipboard $clipboard */ $clipboard = igbinary_unserialize($this->clipboard/*, ['allowed_classes' => [Selection::class]]*/);//TODO test pm4 $selection = $clipboard->selection; - $undoChunks = $selection->getIterator()->getManager()->getChunks(); + $undoChunks = $selection->getIterator()->getManager()->getChunks();//? $totalCount = $selection->getShape()->getTotalCount(); $world = $selection->getWorld(); - foreach ($resultChunks as $hash => $chunk) { + foreach($resultChunks as $hash => $chunk){ World::getXZ($hash, $x, $z); $world->setChunk($x, $z, $chunk); + var_dump("setChunk", $x, $z, $hash); } - if (!is_null($session)) { + if(!is_null($session)){ $session->sendMessage(TF::GREEN . $session->getLanguage()->translateString('task.paste.success', [$this->generateTookString(), $changed, $totalCount])); $session->addRevert(new RevertClipboard($selection->worldId, $undoChunks, $oldBlocks)); } diff --git a/src/xenialdan/MagicWE2/task/AsyncRevertTask.php b/src/xenialdan/MagicWE2/task/AsyncRevertTask.php index ddf5798..bb04986 100644 --- a/src/xenialdan/MagicWE2/task/AsyncRevertTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncRevertTask.php @@ -13,7 +13,7 @@ use Ramsey\Uuid\UuidInterface; use xenialdan\MagicWE2\clipboard\RevertClipboard; use xenialdan\MagicWE2\exception\SessionException; -use xenialdan\MagicWE2\helper\AsyncChunkManager; +use xenialdan\MagicWE2\helper\AsyncWorld; use xenialdan\MagicWE2\helper\SessionHelper; use xenialdan\MagicWE2\Loader; use xenialdan\MagicWE2\session\UserSession; @@ -43,6 +43,7 @@ public function __construct(UuidInterface $sessionUUID, RevertClipboard $clipboa $this->start = microtime(true); $this->clipboard = igbinary_serialize($clipboard); $this->type = $type; + //TODO AsyncWorld $manager } /** @@ -58,6 +59,7 @@ public function onRun(): void $clipboard = igbinary_unserialize($this->clipboard/*, ['allowed_classes' => [RevertClipboard::class]]*/);//TODO test pm4 $totalCount = count($clipboard->blocksAfter); +// $manager = $clipboard::getChunkManager($clipboard->chunks); $manager = $clipboard::getChunkManager($clipboard->chunks); $oldBlocks = []; if ($this->type === self::TYPE_UNDO) @@ -69,19 +71,19 @@ public function onRun(): void } /** - * @param AsyncChunkManager $manager + * @param AsyncWorld $manager * @param RevertClipboard $clipboard + * * @return Generator * @throws InvalidArgumentException * @phpstan-return Generator */ - private function undoChunks(AsyncChunkManager $manager, RevertClipboard $clipboard): Generator - { + private function undoChunks(AsyncWorld $manager, RevertClipboard $clipboard) : Generator{ $count = count($clipboard->blocksAfter); $changed = 0; $this->publishProgress([0, "Reverted $changed blocks out of $count"]); //$block is "data" array - foreach ($clipboard->blocksAfter as $block) { + foreach($clipboard->blocksAfter as $block){ yield $block; $block = self::singleDataToBlock($block);//turn data into real block $manager->setBlockAt($block->getPosition()->getFloorX(), $block->getPosition()->getFloorY(), $block->getPosition()->getFloorZ(), $block); @@ -91,19 +93,18 @@ private function undoChunks(AsyncChunkManager $manager, RevertClipboard $clipboa } /** - * @param AsyncChunkManager $manager + * @param AsyncWorld $manager * @param RevertClipboard $clipboard * @return Generator * @throws InvalidArgumentException * @phpstan-return Generator */ - private function redoChunks(AsyncChunkManager $manager, RevertClipboard $clipboard): Generator - { + private function redoChunks(AsyncWorld $manager, RevertClipboard $clipboard) : Generator{ $count = count($clipboard->blocksAfter); $changed = 0; $this->publishProgress([0, "Redone $changed blocks out of $count"]); //$block is "data" array - foreach ($clipboard->blocksAfter as $block) { + foreach($clipboard->blocksAfter as $block){ yield $block; $block = self::singleDataToBlock($block);//turn data into real block $manager->setBlockAt($block->getPosition()->getFloorX(), $block->getPosition()->getFloorY(), $block->getPosition()->getFloorZ(), $block); diff --git a/src/xenialdan/MagicWE2/task/action/CountAction.php b/src/xenialdan/MagicWE2/task/action/CountAction.php index 22083ff..fd6b081 100644 --- a/src/xenialdan/MagicWE2/task/action/CountAction.php +++ b/src/xenialdan/MagicWE2/task/action/CountAction.php @@ -42,7 +42,7 @@ public static function getName(): string */ public function execute(string $sessionUUID, Selection $selection, ?int &$changed, BlockPalette $newBlocks, BlockPalette $blockFilter, SingleClipboard $oldBlocksSingleClipboard, array &$messages = []): Generator { - $manager = $selection->getIterator()->getManager(); + $manager = $selection->getIterator(true)->getManager(); $changed = 0; #$oldBlocks = []; $count = $selection->getShape()->getTotalCount(); diff --git a/src/xenialdan/MagicWE2/tool/Flood.php b/src/xenialdan/MagicWE2/tool/Flood.php index ab15981..2e55b41 100644 --- a/src/xenialdan/MagicWE2/tool/Flood.php +++ b/src/xenialdan/MagicWE2/tool/Flood.php @@ -8,10 +8,8 @@ use pocketmine\math\Facing; use pocketmine\math\Vector2; use pocketmine\math\Vector3; -use pocketmine\world\format\Chunk; use pocketmine\world\format\io\FastChunkSerializer; use pocketmine\world\World; -use xenialdan\MagicWE2\helper\AsyncChunkManager; use xenialdan\MagicWE2\helper\AsyncWorld; use xenialdan\MagicWE2\helper\BlockPalette; @@ -35,8 +33,10 @@ public function __construct(int $limit) /** * Returns the blocks by their actual position - * @param AsyncWorld $manager The world or AsyncChunkManager + * + * @param AsyncWorld $manager The world or AsyncWorld * @param BlockPalette $filterblocks If not empty, applying a filter on the block list + * * @return Generator * @throws InvalidArgumentException */ @@ -54,7 +54,7 @@ public function getBlocks(AsyncWorld $manager, BlockPalette $filterblocks): Gene /** * Returns a flat layer of all included x z positions in selection - * @param AsyncWorld $manager The world or AsyncChunkManager + * @param AsyncWorld $manager The world or AsyncWorld * @return Generator * @throws InvalidArgumentException */ @@ -112,12 +112,11 @@ public function getTotalCount(): int } /** - * @param World|AsyncChunkManager $chunkManager + * @param World|AsyncWorld $chunkManager * @return array * @throws InvalidArgumentException */ - public function getTouchedChunks(AsyncChunkManager|World $chunkManager): array - { + public function getTouchedChunks(AsyncWorld|World $chunkManager) : array{ $this->validateChunkManager($chunkManager); $maxRadius = sqrt($this->limit / M_PI); $v2center = new Vector2($this->getCenter()->x, $this->getCenter()->z); @@ -153,9 +152,8 @@ public function getName(): string * @param mixed $manager * @throws InvalidArgumentException */ - public function validateChunkManager(mixed $manager): void - { - if (!$manager instanceof World && !$manager instanceof AsyncChunkManager) throw new InvalidArgumentException(get_class($manager) . " is not an instance of World or AsyncChunkManager"); + public function validateChunkManager(mixed $manager): void{ + if(!$manager instanceof World && !$manager instanceof AsyncWorld) throw new InvalidArgumentException(get_class($manager) . " is not an instance of World or AsyncWorld"); } private function getCenter(): Vector3 @@ -163,20 +161,4 @@ private function getCenter(): Vector3 //UGLY HACK TO IGNORE ERRORS FOR NOW return new Vector3(0, 0, 0); } - - /** - * Creates a chunk manager used for async editing - * @param Chunk[] $chunks - * @phpstan-param array $chunks - * @return AsyncChunkManager - */ - public static function getChunkManager(array $chunks): AsyncChunkManager - { - $manager = new AsyncChunkManager(World::Y_MIN, World::Y_MAX);//TODO replace AsyncChunkManager with AsyncWorld - foreach($chunks as $hash => $chunk){ - World::getXZ($hash, $x, $z); - $manager->setChunk($x, $z, $chunk); - } - return $manager; - } } \ No newline at end of file From f5f6d2e4bff36fdc314e0958a08af18162a24d43 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Mon, 3 Oct 2022 07:21:06 +0200 Subject: [PATCH 16/24] Rotate is working correctly now --- src/xenialdan/MagicWE2/API.php | 8 +++---- .../MagicWE2/task/AsyncPasteTask.php | 23 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/xenialdan/MagicWE2/API.php b/src/xenialdan/MagicWE2/API.php index 611f5b5..9a1cbd6 100644 --- a/src/xenialdan/MagicWE2/API.php +++ b/src/xenialdan/MagicWE2/API.php @@ -587,14 +587,13 @@ private static function rotateClipboard(SingleClipboard $structure, int $rotatio if($rotation % 90 !== 0){ throw new InvalidArgumentException("Rotation must be divisible by 90"); } - $rotation += 180;//FIXME THIS IS A DUMB HACK BECAUSE ROTATIONS ARE FLIPPED $rotation = self::positiveModulo($rotation, 360); if($rotation === 0) return $structure; //width is x axis, length is z axis $newClipboard = new SingleClipboard($structure->position); $newClipboard->selection = $structure->selection; - $newClipboard->selection->free();//TODO check if this is necessary +// $newClipboard->selection->free();//TODO check if this is necessary $newClipboard->selection->shape = $structure->selection->getShape()->rotate($rotation); //$x = $y = $z = null; @@ -606,9 +605,9 @@ private static function rotateClipboard(SingleClipboard $structure, int $rotatio $newV3 = match ($rotation)//TODO figure out how to avoid new Vector3 objects { - RotateAction::ROTATE_90 => new Vector3($z, $y, $structure->selection->getSizeX() - $x - 1), + RotateAction::ROTATE_90 => new Vector3($structure->selection->getSizeZ() - $z - 1, $y, $x), RotateAction::ROTATE_180 => new Vector3($structure->selection->getSizeX() - $x - 1, $y, $structure->selection->getSizeZ() - $z - 1),//TODO is this flip instead of rotate? - RotateAction::ROTATE_270 => new Vector3($structure->selection->getSizeZ() - $z - 1, $y, $x), + RotateAction::ROTATE_270 => new Vector3($z, $y, $structure->selection->getSizeX() - $x - 1), default => new Vector3($x, $y, $z) }; $newClipboard->addEntry($newV3->getFloorX(), $newV3->getFloorY(), $newV3->getFloorZ(), new BlockEntry($stateRotated->getFullId())); @@ -647,6 +646,7 @@ private static function rotateBlockState(BlockState $state, int $rotation) : Blo #$newState = clone $state;//TODO check if needed $newState = $state; + return $newState->replaceBlockStateValues($data); } diff --git a/src/xenialdan/MagicWE2/task/AsyncPasteTask.php b/src/xenialdan/MagicWE2/task/AsyncPasteTask.php index d2f545e..09615bb 100644 --- a/src/xenialdan/MagicWE2/task/AsyncPasteTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncPasteTask.php @@ -26,7 +26,6 @@ use xenialdan\MagicWE2\session\UserSession; use function igbinary_serialize; use function igbinary_unserialize; -use function var_dump; class AsyncPasteTask extends MWEAsyncTask { @@ -50,20 +49,20 @@ public function __construct(UuidInterface $sessionUUID, SingleClipboard $clipboa var_dump("new paste", $clipboard->selection->getShape()->getPasteVector()); */ $this->offset = $pasteVector->addVector($clipboard->position); - var_dump("paste", $clipboard->selection->getShape()->getPasteVector(), "cb position", $clipboard->position, "offset", $this->offset, "aabb", $clipboard->selection->getShape()->getAABB()); - var_dump("new paste vec", $pasteVector); - var_dump("orig paste", $clipboard->selection->getShape()->getPasteVector()); - var_dump("pasteV minus offset", $clipboard->selection->getShape()->getPasteVector()->subtractVector($this->offset)); - var_dump("old minus new pos", $clipboard->selection->getShape()->getPasteVector()->subtractVector($pasteVector)); +// var_dump("paste", $clipboard->selection->getShape()->getPasteVector(), "cb position", $clipboard->position, "offset", $this->offset, "aabb", $clipboard->selection->getShape()->getAABB()); +// var_dump("new paste vec", $pasteVector); +// var_dump("orig paste", $clipboard->selection->getShape()->getPasteVector()); +// var_dump("pasteV minus offset", $clipboard->selection->getShape()->getPasteVector()->subtractVector($this->offset)); +// var_dump("old minus new pos", $clipboard->selection->getShape()->getPasteVector()->subtractVector($pasteVector)); $clipboard->selection->getShape()->setPasteVector($this->offset->add($clipboard->selection->getSizeX() / 2, $clipboard->selection->getSizeY() / 2, $clipboard->selection->getSizeZ() / 2)); - var_dump("new paste", $clipboard->selection->getShape()->getPasteVector()); +// var_dump("new paste", $clipboard->selection->getShape()->getPasteVector()); $this->sessionUUID = $sessionUUID->toString(); $this->clipboard = igbinary_serialize($clipboard); $this->manager = $clipboard->selection->getIterator()->getManager(); - var_dump(__METHOD__ . __LINE__, count($this->manager->getChunks())); +// var_dump(__METHOD__ . __LINE__, count($this->manager->getChunks())); foreach($this->manager->getChunks() as $hash => $chunk){ World::getXZ($hash, $x, $z); - var_dump(__METHOD__ . __LINE__, $hash, $x, $z); +// var_dump(__METHOD__ . __LINE__, $hash, $x, $z); } } @@ -103,7 +102,7 @@ public function onRun(): void * @phpstan-return Generator */ private function execute(SingleClipboard $clipboard, ?int &$changed, AsyncWorld &$manager) : Generator{ - var_dump("MANAGER CHUNK COUNT", count($manager->getChunks())); +// var_dump("MANAGER CHUNK COUNT", count($manager->getChunks())); $blockCount = $clipboard->getTotalCount(); $x = $y = $z = null; $lastprogress = 0; @@ -127,7 +126,7 @@ private function execute(SingleClipboard $clipboard, ?int &$changed, AsyncWorld #var_dump("old", $old, "new", $new); yield self::singleBlockToData(API::setComponents($manager->getBlockAt($x, $y, $z), (int) $x, (int) $y, (int) $z)); - var_dump(__METHOD__ . __LINE__, World::chunkHash($x, $z), $x, $z); +// var_dump(__METHOD__ . __LINE__, World::chunkHash($x, $z), $x, $z); if($manager->getChunk($x >> 4, $z >> 4) === null){ $manager->setChunk($x >> 4, $z >> 4, new Chunk([], BiomeArray::fill(BiomeIds::OCEAN), false)); } @@ -175,7 +174,7 @@ public function onCompletion(): void foreach($resultChunks as $hash => $chunk){ World::getXZ($hash, $x, $z); $world->setChunk($x, $z, $chunk); - var_dump("setChunk", $x, $z, $hash); +// var_dump("setChunk", $x, $z, $hash); } if(!is_null($session)){ $session->sendMessage(TF::GREEN . $session->getLanguage()->translateString('task.paste.success', [$this->generateTookString(), $changed, $totalCount])); From 4ba93d1efa9c13838602be35f4c5bb02ba09318a Mon Sep 17 00:00:00 2001 From: XenialDan Date: Tue, 4 Oct 2022 04:07:53 +0200 Subject: [PATCH 17/24] Cleanup (tests, comments and debugs); Catch and skip blockstate rotation on error --- src/xenialdan/MagicWE2/API.php | 77 +++++++++++-------- src/xenialdan/MagicWE2/helper/AsyncWorld.php | 22 +++--- .../MagicWE2/selection/Selection.php | 7 +- .../MagicWE2/task/AsyncPasteTask.php | 54 +++---------- .../MagicWE2/task/action/RotateAction.php | 11 +-- 5 files changed, 71 insertions(+), 100 deletions(-) diff --git a/src/xenialdan/MagicWE2/API.php b/src/xenialdan/MagicWE2/API.php index 9a1cbd6..aa31c86 100644 --- a/src/xenialdan/MagicWE2/API.php +++ b/src/xenialdan/MagicWE2/API.php @@ -11,6 +11,7 @@ use pocketmine\block\Block; use pocketmine\block\BlockFactory; use pocketmine\math\Vector3; +use pocketmine\nbt\NoSuchTagException; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\UnexpectedTagTypeException; use pocketmine\player\Player; @@ -30,6 +31,7 @@ use xenialdan\MagicWE2\exception\BlockQueryAlreadyParsedException; use xenialdan\MagicWE2\exception\CalculationException; use xenialdan\MagicWE2\exception\LimitExceededException; +use xenialdan\MagicWE2\exception\SelectionException; use xenialdan\MagicWE2\helper\BlockPalette; use xenialdan\MagicWE2\selection\Selection; use xenialdan\MagicWE2\selection\shape\Cuboid; @@ -529,23 +531,24 @@ public static function positiveModulo(int $i, int $n) : int{ } /** - * @throws InvalidArgumentException + * @throws InvalidArgumentException|SelectionException */ - public static function rotate(Schematic|MCStructure|SingleClipboard $structure, int $rotation) : Schematic|MCStructure|SingleClipboard{ + public static function rotate(Schematic|MCStructure|SingleClipboard $structure, int $rotation, array &$errors = []) : Schematic|MCStructure|SingleClipboard{ $rotation = self::positiveModulo($rotation, 360); if($rotation % 90 !== 0){ throw new InvalidArgumentException("Rotation must be divisible by 90"); } - if($structure instanceof Schematic) return self::rotateSchematic($structure, $rotation); - elseif($structure instanceof MCStructure) return self::rotateStructure($structure, $rotation);//TODO add support for creating new structures to libstructures - elseif($structure instanceof SingleClipboard) return self::rotateClipboard($structure, $rotation); + $errors = []; + if($structure instanceof Schematic) return self::rotateSchematic($structure, $rotation, $errors); + elseif($structure instanceof MCStructure) return self::rotateStructure($structure, $rotation, $errors);//TODO add support for creating new structures to libstructures + elseif($structure instanceof SingleClipboard) return self::rotateClipboard($structure, $rotation, $errors); throw new InvalidArgumentException("Invalid structure"); } /** * @throws InvalidArgumentException */ - private static function rotateSchematic(Schematic $structure, int $rotation) : Schematic{ + private static function rotateSchematic(Schematic $structure, int $rotation, array &$errors = []) : Schematic{ if($rotation % 90 !== 0){ throw new InvalidArgumentException("Rotation must be divisible by 90"); } @@ -559,31 +562,37 @@ private static function rotateSchematic(Schematic $structure, int $rotation) : S foreach($structure->blocks() as $block){ //TODO set block to rotated blockstate $state = self::entryToState(BlockEntry::fromBlock($block)); - $stateRotated = self::rotateBlockState($state, $rotation); - - $blocks[] = match ($rotation) { - //TODO check if the new positions are calculated correctly - RotateAction::ROTATE_90 => self::setComponents($stateRotated->getBlock(), $structure->getLength() - $block->getPosition()->getFloorZ() - 1, $block->getPosition()->getFloorY(), $block->getPosition()->getFloorX()), - RotateAction::ROTATE_180 => self::setComponents($stateRotated->getBlock(), $structure->getWidth() - $block->getPosition()->getFloorX() - 1, $block->getPosition()->getFloorY(), $structure->getLength() - $block->getPosition()->getFloorZ() - 1), - RotateAction::ROTATE_270 => self::setComponents($stateRotated->getBlock(), $block->getPosition()->getFloorZ(), $block->getPosition()->getFloorY(), $structure->getWidth() - $block->getPosition()->getFloorX() - 1), - default => $stateRotated->getBlock() - }; - //TODO move origin of structure + try{ + $stateRotated = self::rotateBlockState($state, $rotation); + $blocks[] = match ($rotation) { + //TODO check if the new positions are calculated correctly + RotateAction::ROTATE_90 => self::setComponents($stateRotated->getBlock(), $structure->getLength() - $block->getPosition()->getFloorZ() - 1, $block->getPosition()->getFloorY(), $block->getPosition()->getFloorX()), + RotateAction::ROTATE_180 => self::setComponents($stateRotated->getBlock(), $structure->getWidth() - $block->getPosition()->getFloorX() - 1, $block->getPosition()->getFloorY(), $structure->getLength() - $block->getPosition()->getFloorZ() - 1), + RotateAction::ROTATE_270 => self::setComponents($stateRotated->getBlock(), $block->getPosition()->getFloorZ(), $block->getPosition()->getFloorY(), $structure->getWidth() - $block->getPosition()->getFloorX() - 1), + default => $stateRotated->getBlock() + }; + }catch(BlockQueryParsingFailedException | NoSuchTagException | UnexpectedTagTypeException $e){ + $errors[] = $e->getMessage();//TODO implement error printing, for now silently continue + continue; + } } + //TODO move origin of structure $newSchematic = new Schematic(); $newSchematic->setBlockArray($blocks); return $newSchematic; } - private static function rotateStructure(MCStructure $structure, int $rotation) : MCStructure{ + private static function rotateStructure(MCStructure $structure, int $rotation, array &$errors = []) : MCStructure{ //TODO this is not yet implemented due to lack of support for creating new MCStructures in libstructure return $structure; } /** - * @throws InvalidArgumentException + * @param array $errors Exceptions thrown whilst rotating the blockstates + * + * @throws InvalidArgumentException|SelectionException */ - private static function rotateClipboard(SingleClipboard $structure, int $rotation) : SingleClipboard{ + private static function rotateClipboard(SingleClipboard $structure, int $rotation, array &$errors = []) : SingleClipboard{ if($rotation % 90 !== 0){ throw new InvalidArgumentException("Rotation must be divisible by 90"); } @@ -601,17 +610,22 @@ private static function rotateClipboard(SingleClipboard $structure, int $rotatio foreach($structure->iterateEntries($x, $y, $z) as $entry){ //TODO set entry to rotated blockstate $state = self::entryToState($entry); - $stateRotated = self::rotateBlockState($state, $rotation); - - $newV3 = match ($rotation)//TODO figure out how to avoid new Vector3 objects - { - RotateAction::ROTATE_90 => new Vector3($structure->selection->getSizeZ() - $z - 1, $y, $x), - RotateAction::ROTATE_180 => new Vector3($structure->selection->getSizeX() - $x - 1, $y, $structure->selection->getSizeZ() - $z - 1),//TODO is this flip instead of rotate? - RotateAction::ROTATE_270 => new Vector3($z, $y, $structure->selection->getSizeX() - $x - 1), - default => new Vector3($x, $y, $z) - }; - $newClipboard->addEntry($newV3->getFloorX(), $newV3->getFloorY(), $newV3->getFloorZ(), new BlockEntry($stateRotated->getFullId())); - //TODO move origin of structure + try{ + $stateRotated = self::rotateBlockState($state, $rotation); + + $newV3 = match ($rotation)//TODO figure out how to avoid new Vector3 objects + { + RotateAction::ROTATE_90 => new Vector3($structure->selection->getSizeZ() - $z - 1, $y, $x), + RotateAction::ROTATE_180 => new Vector3($structure->selection->getSizeX() - $x - 1, $y, $structure->selection->getSizeZ() - $z - 1),//TODO is this flip instead of rotate? + RotateAction::ROTATE_270 => new Vector3($z, $y, $structure->selection->getSizeX() - $x - 1), + default => new Vector3($x, $y, $z) + }; + //TODO move origin of structure + $newClipboard->addEntry($newV3->getFloorX(), $newV3->getFloorY(), $newV3->getFloorZ(), new BlockEntry($stateRotated->getFullId())); + }catch(BlockQueryParsingFailedException | NoSuchTagException | UnexpectedTagTypeException $e){ + $errors[] = $e->getMessage();//TODO implement error printing, for now silently continue + continue; + } } return $newClipboard; } @@ -637,7 +651,7 @@ public static function stateToEntry(BlockState $state) : BlockEntry{ /** * @throws InvalidArgumentException When rotation is invalid (not divisible by 90) - * @throws UnexpectedTagTypeException + * @throws UnexpectedTagTypeException|NoSuchTagException * @throws BlockQueryParsingFailedException When no such blockstate could be found */ private static function rotateBlockState(BlockState $state, int $rotation) : BlockState{ @@ -650,6 +664,7 @@ private static function rotateBlockState(BlockState $state, int $rotation) : Blo return $newState->replaceBlockStateValues($data); } + /** @throws InvalidArgumentException */ public static function getRotationData(BlockState $blockState, int $rotation) : array{ if($rotation !== RotateAction::ROTATE_90 && $rotation !== RotateAction::ROTATE_180 && $rotation !== RotateAction::ROTATE_270) throw new InvalidArgumentException("Invalid rotation $rotation given"); diff --git a/src/xenialdan/MagicWE2/helper/AsyncWorld.php b/src/xenialdan/MagicWE2/helper/AsyncWorld.php index 6d7c183..6c6110b 100644 --- a/src/xenialdan/MagicWE2/helper/AsyncWorld.php +++ b/src/xenialdan/MagicWE2/helper/AsyncWorld.php @@ -19,13 +19,8 @@ class AsyncWorld extends SimpleChunkManager implements Serializable{ // /** @var CompoundTag[] *///TODO maybe CacheableNbt // protected array $tiles = []; - /** - * @throws SelectionException - * @throws RuntimeException - */ - public function __construct(Selection $selection){ + public function __construct(){ parent::__construct(World::Y_MIN, World::Y_MAX); -// $this->copyChunks($selection); } /** @@ -36,6 +31,7 @@ public function getChunks() : array{ } /** + * May not be called from async task * @throws SelectionException|RuntimeException */ public function copyChunks(Selection $selection) : void{ @@ -45,14 +41,14 @@ public function copyChunks(Selection $selection) : void{ $shape = $selection->getShape(); $aabb = $shape->getAABB(); $world = $selection->getWorld(); - $maxX = $aabb->maxX >> 4; - $minX = $aabb->minX >> 4; - $maxZ = $aabb->maxZ >> 4; - $minZ = $aabb->minZ >> 4; - for ($x = $minX; $x <= $maxX; $x++) { - for ($z = $minZ; $z <= $maxZ; $z++) { + $maxX = $aabb->maxX >> Chunk::COORD_BIT_SIZE; + $minX = $aabb->minX >> Chunk::COORD_BIT_SIZE; + $maxZ = $aabb->maxZ >> Chunk::COORD_BIT_SIZE; + $minZ = $aabb->minZ >> Chunk::COORD_BIT_SIZE; + for($x = $minX; $x <= $maxX; $x++){ + for($z = $minZ; $z <= $maxZ; $z++){ $chunk = $world->getChunk($x, $z); - if ($chunk === null) { + if($chunk === null){ continue; } $this->setChunk($x, $z, $chunk); diff --git a/src/xenialdan/MagicWE2/selection/Selection.php b/src/xenialdan/MagicWE2/selection/Selection.php index 090d0ae..856e76c 100644 --- a/src/xenialdan/MagicWE2/selection/Selection.php +++ b/src/xenialdan/MagicWE2/selection/Selection.php @@ -26,7 +26,6 @@ use xenialdan\MagicWE2\selection\shape\Cuboid; use xenialdan\MagicWE2\selection\shape\Shape; use xenialdan\MagicWE2\session\Session; -use function var_dump; /** * Class Selection @@ -193,7 +192,7 @@ public function getShape() : Shape{ } public function setShape(Shape $shape) : void{ - var_dump($shape); +// var_dump($shape); $this->shape = $shape; try{ (new MWESelectionChangeEvent($this, MWESelectionChangeEvent::TYPE_SHAPE))->call();//might cause duplicated call @@ -215,7 +214,7 @@ public function setShape(Shape $shape) : void{ */ public function isValid() : bool{ try{ - var_dump("World: " . $this->getWorld()->getId() . " Pos1: " . $this->pos1 . " Pos2: " . $this->pos2 . " Shape: " . $this->shape?->serialize()); +// var_dump("World: " . $this->getWorld()->getId() . " Pos1: " . $this->pos1 . " Pos2: " . $this->pos2 . " Shape: " . $this->shape?->serialize()); //$this->getShape(); $this->getWorld(); $this->getPos1(); @@ -248,7 +247,7 @@ public function getUUID() : UuidInterface{ } public function getIterator(bool $copyChunks = true) : SubChunkIterator{ - $manager = new AsyncWorld($this); + $manager = new AsyncWorld(); if($copyChunks) $manager->copyChunks($this); return new SubChunkIterator($manager); } diff --git a/src/xenialdan/MagicWE2/task/AsyncPasteTask.php b/src/xenialdan/MagicWE2/task/AsyncPasteTask.php index 09615bb..49259b2 100644 --- a/src/xenialdan/MagicWE2/task/AsyncPasteTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncPasteTask.php @@ -41,29 +41,12 @@ class AsyncPasteTask extends MWEAsyncTask */ public function __construct(UuidInterface $sessionUUID, SingleClipboard $clipboard, Vector3 $pasteVector){ $this->start = microtime(true); - /* - backup $this->offset = $pasteVector->addVector($clipboard->position); - var_dump("paste", $clipboard->selection->getShape()->getPasteVector(), "cb position", $clipboard->position, "offset", $this->offset); - $clipboard->selection->getShape()->setPasteVector($clipboard->selection->getShape()->getPasteVector()->addVector($clipboard->position)); - var_dump("new paste", $clipboard->selection->getShape()->getPasteVector()); - */ - $this->offset = $pasteVector->addVector($clipboard->position); -// var_dump("paste", $clipboard->selection->getShape()->getPasteVector(), "cb position", $clipboard->position, "offset", $this->offset, "aabb", $clipboard->selection->getShape()->getAABB()); -// var_dump("new paste vec", $pasteVector); -// var_dump("orig paste", $clipboard->selection->getShape()->getPasteVector()); -// var_dump("pasteV minus offset", $clipboard->selection->getShape()->getPasteVector()->subtractVector($this->offset)); -// var_dump("old minus new pos", $clipboard->selection->getShape()->getPasteVector()->subtractVector($pasteVector)); + //FIXME Sometimes not all "paste chunks" are set for some shapes or sizes. Figure out why. Maybe ceil/floor? $clipboard->selection->getShape()->setPasteVector($this->offset->add($clipboard->selection->getSizeX() / 2, $clipboard->selection->getSizeY() / 2, $clipboard->selection->getSizeZ() / 2)); -// var_dump("new paste", $clipboard->selection->getShape()->getPasteVector()); $this->sessionUUID = $sessionUUID->toString(); $this->clipboard = igbinary_serialize($clipboard); $this->manager = $clipboard->selection->getIterator()->getManager(); -// var_dump(__METHOD__ . __LINE__, count($this->manager->getChunks())); - foreach($this->manager->getChunks() as $hash => $chunk){ - World::getXZ($hash, $x, $z); -// var_dump(__METHOD__ . __LINE__, $hash, $x, $z); - } } /** @@ -76,13 +59,8 @@ public function onRun(): void { $this->publishProgress([0, "Start"]); -// $touchedChunks = array_map(static function ($chunk) {//todo add hash as key -// return FastChunkSerializer::deserializeTerrain($chunk); -// }, igbinary_unserialize($this->touchedChunks/*, ['allowed_classes' => false]*/));//TODO test pm4 -// unset($touchedChunks); - /** @var SingleClipboard $clipboard */ - $clipboard = igbinary_unserialize($this->clipboard/*, ['allowed_classes' => [SingleClipboard::class]]*/);//TODO test pm4 + $clipboard = igbinary_unserialize($this->clipboard); $manager = $this->manager; $oldBlocks = iterator_to_array($this->execute($clipboard, $changed, $manager)); @@ -96,48 +74,37 @@ public function onRun(): void /** * @param SingleClipboard $clipboard - * @param null|int $changed + * @param null|int $changed + * @param AsyncWorld $manager + * * @return Generator - * @throws InvalidArgumentException * @phpstan-return Generator + * @throws InvalidArgumentException */ private function execute(SingleClipboard $clipboard, ?int &$changed, AsyncWorld &$manager) : Generator{ -// var_dump("MANAGER CHUNK COUNT", count($manager->getChunks())); $blockCount = $clipboard->getTotalCount(); $x = $y = $z = null; $lastprogress = 0; - $i = 0; $changed = 0; $this->publishProgress([0, "Running, changed $changed blocks out of $blockCount"]); /** @var BlockEntry $entry */ foreach($clipboard->iterateEntries($x, $y, $z) as $entry){ - #var_dump("at cb xyz $x $y $z: $entry"); $x += $this->offset->getFloorX(); $y += $this->offset->getFloorY(); $z += $this->offset->getFloorZ(); - #var_dump("add offset xyz $x $y $z"); /*if (API::hasFlag($this->flags, API::FLAG_POSITION_RELATIVE)){ $rel = $block->subtract($selection->shape->getPasteVector()); $block = API::setComponents($block,$rel->x,$rel->y,$rel->z);//TODO COPY TO ALL TASKS }*/ $new = $entry->toBlock(); - #$new->position(($pos = Position::fromObject(new Vector3($x, $y, $z)))->getWorld(), $pos->getX(), $pos->getY(), $pos->getZ()); - #$old->position(($pos = Position::fromObject(new Vector3($x, $y, $z)))->getWorld(), $pos->getX(), $pos->getY(), $pos->getZ()); - #var_dump("old", $old, "new", $new); yield self::singleBlockToData(API::setComponents($manager->getBlockAt($x, $y, $z), (int) $x, (int) $y, (int) $z)); -// var_dump(__METHOD__ . __LINE__, World::chunkHash($x, $z), $x, $z); if($manager->getChunk($x >> 4, $z >> 4) === null){ $manager->setChunk($x >> 4, $z >> 4, new Chunk([], BiomeArray::fill(BiomeIds::OCEAN), false)); } -// var_dump("ToPlace", $entry->toBlock()); -// var_dump("Before setBlockAt", API::setComponents($manager->getBlockAt($x, $y, $z), (int)$x, (int)$y, (int)$z)); $manager->setBlockAt($x, $y, $z, $new); -// var_dump("After setBlockAt", API::setComponents($manager->getBlockAt($x, $y, $z), (int)$x, (int)$y, (int)$z)); $changed++; - /// - $i++; - $progress = floor($i / $blockCount * 100); + $progress = floor($changed / $blockCount * 100); if($lastprogress < $progress){//this prevents spamming packets $this->publishProgress([$progress, "Running, changed $changed blocks out of $blockCount"]); $lastprogress = $progress; @@ -162,19 +129,18 @@ public function onCompletion(): void $resultChunks = $result["resultChunks"]; // $undoChunks = array_map(static function ($chunk) { // return FastChunkSerializer::deserializeTerrain($chunk); -// }, igbinary_unserialize($this->touchedChunks/*, ['allowed_classes' => false]*/));//TODO test pm4 +// }, igbinary_unserialize($this->touchedChunks)); $oldBlocks = $result["oldBlocks"];//already data array $changed = $result["changed"]; /** @var SingleClipboard $clipboard */ - $clipboard = igbinary_unserialize($this->clipboard/*, ['allowed_classes' => [Selection::class]]*/);//TODO test pm4 + $clipboard = igbinary_unserialize($this->clipboard); $selection = $clipboard->selection; - $undoChunks = $selection->getIterator()->getManager()->getChunks();//? + $undoChunks = $selection->getIterator()->getManager()->getChunks();//Should be unmodified $totalCount = $selection->getShape()->getTotalCount(); $world = $selection->getWorld(); foreach($resultChunks as $hash => $chunk){ World::getXZ($hash, $x, $z); $world->setChunk($x, $z, $chunk); -// var_dump("setChunk", $x, $z, $hash); } if(!is_null($session)){ $session->sendMessage(TF::GREEN . $session->getLanguage()->translateString('task.paste.success', [$this->generateTookString(), $changed, $totalCount])); diff --git a/src/xenialdan/MagicWE2/task/action/RotateAction.php b/src/xenialdan/MagicWE2/task/action/RotateAction.php index 146f660..8e6d65b 100644 --- a/src/xenialdan/MagicWE2/task/action/RotateAction.php +++ b/src/xenialdan/MagicWE2/task/action/RotateAction.php @@ -47,19 +47,14 @@ public static function getName(): string * @throws Exception */ public function execute(string $sessionUUID, Selection $selection, ?int &$changed, SingleClipboard &$clipboard, array &$messages = []) : Generator{ - //TODO modify position. For now, just flip the blocks around their own axis + //TODO modify clipboard position / add relative rotation. For now, just rotate the blocks around their center $changed = 0; - #$oldBlocks = []; $count = $clipboard->getTotalCount(); yield new Progress(0, ""); BlockFactory::getInstance(); -// /** @var BlockStatesParser $blockStatesParser */ -// $blockStatesParser = BlockStatesParser::getInstance(); - - #var_dump(__CLASS__ . " ". __FUNCTION__ . " " . __LINE__ . " " . __FILE__, count($this->rotationData), API::$rotationData); API::setRotationData($this->rotationData); - #var_dump(__CLASS__ . " ". __FUNCTION__ . " " . __LINE__ . " " . __FILE__, count($this->rotationData), API::$rotationData); - $clipboard = API::rotate($clipboard, $this->rotation); + $errors = []; + $clipboard = API::rotate($clipboard, $this->rotation, $errors); yield new Progress($changed / $count, "$changed/$count"); } From 2f98a828a78475785a8b160544a40e0c198af5aa Mon Sep 17 00:00:00 2001 From: XenialDan Date: Wed, 5 Oct 2022 07:34:39 +0200 Subject: [PATCH 18/24] Fix async edits with other tasks, partially fix undo --- src/xenialdan/MagicWE2/API.php | 16 ++- src/xenialdan/MagicWE2/helper/AsyncWorld.php | 10 ++ src/xenialdan/MagicWE2/session/Session.php | 13 +- .../MagicWE2/task/AsyncActionTask.php | 10 +- src/xenialdan/MagicWE2/task/AsyncCopyTask.php | 1 - .../MagicWE2/task/AsyncCountTask.php | 123 ------------------ src/xenialdan/MagicWE2/task/AsyncFillTask.php | 1 - .../MagicWE2/task/AsyncPasteAssetTask.php | 2 +- .../MagicWE2/task/AsyncPasteTask.php | 1 - .../MagicWE2/task/AsyncReplaceTask.php | 14 +- .../MagicWE2/task/AsyncRevertTask.php | 58 +++++---- src/xenialdan/MagicWE2/task/MWEAsyncTask.php | 2 + .../MagicWE2/task/action/CountAction.php | 14 +- .../MagicWE2/task/action/CutAction.php | 14 +- .../MagicWE2/task/action/SetBiomeAction.php | 16 +-- .../MagicWE2/task/action/SetBlockAction.php | 16 +-- .../MagicWE2/task/action/TaskAction.php | 25 ++-- .../MagicWE2/task/action/TestAction.php | 14 +- .../MagicWE2/task/action/ThawAction.php | 14 +- 19 files changed, 112 insertions(+), 252 deletions(-) delete mode 100644 src/xenialdan/MagicWE2/task/AsyncCountTask.php diff --git a/src/xenialdan/MagicWE2/API.php b/src/xenialdan/MagicWE2/API.php index aa31c86..838a786 100644 --- a/src/xenialdan/MagicWE2/API.php +++ b/src/xenialdan/MagicWE2/API.php @@ -39,12 +39,12 @@ use xenialdan\MagicWE2\session\data\Asset; use xenialdan\MagicWE2\session\Session; use xenialdan\MagicWE2\session\UserSession; +use xenialdan\MagicWE2\task\action\CountAction; use xenialdan\MagicWE2\task\action\RotateAction; use xenialdan\MagicWE2\task\action\SetBiomeAction; use xenialdan\MagicWE2\task\action\TaskAction; use xenialdan\MagicWE2\task\AsyncActionTask; use xenialdan\MagicWE2\task\AsyncCopyTask; -use xenialdan\MagicWE2\task\AsyncCountTask; use xenialdan\MagicWE2\task\AsyncFillTask; use xenialdan\MagicWE2\task\AsyncPasteAssetTask; use xenialdan\MagicWE2\task\AsyncPasteTask; @@ -229,12 +229,20 @@ public static function pasteAsync(SingleClipboard $clipboard, Session $session, * @return bool */ public static function countAsync(Selection $selection, Session $session, BlockPalette $filterBlocks, int $flags = self::FLAG_BASE): bool{ - try { + try{ $limit = Loader::getInstance()->getConfig()->get("limit", -1); - if ($limit !== -1 && $selection->getShape()->getTotalCount() > $limit) { + if($limit !== -1 && $selection->getShape()->getTotalCount() > $limit){ throw new LimitExceededException("You are trying to count too many blocks at once. Reduce the selection or raise the limit"); } - Server::getInstance()->getAsyncPool()->submitTask(new AsyncCountTask($session->getUUID(), $selection, $filterBlocks)); + Server::getInstance()->getAsyncPool()->submitTask( + new AsyncActionTask( + $session->getUUID(), + $selection, + new CountAction(), + BlockPalette::CREATE(), + $filterBlocks + ) + ); } catch (Exception $e) { $session->sendMessage($e->getMessage()); Loader::getInstance()->getLogger()->logException($e); diff --git a/src/xenialdan/MagicWE2/helper/AsyncWorld.php b/src/xenialdan/MagicWE2/helper/AsyncWorld.php index 6c6110b..55b16b6 100644 --- a/src/xenialdan/MagicWE2/helper/AsyncWorld.php +++ b/src/xenialdan/MagicWE2/helper/AsyncWorld.php @@ -10,6 +10,7 @@ use pocketmine\world\World; use RuntimeException; use Serializable; +use xenialdan\MagicWE2\clipboard\RevertClipboard; use xenialdan\MagicWE2\exception\SelectionException; use xenialdan\MagicWE2\selection\Selection; use function igbinary_serialize; @@ -23,6 +24,15 @@ public function __construct(){ parent::__construct(World::Y_MIN, World::Y_MAX); } + public static function fromRevertClipboard(RevertClipboard $clipboard) : self{ + $world = new self(); + foreach($clipboard->chunks as $hash => $chunk){ + World::getXZ($hash, $x, $z); + $world->setChunk($x, $z, $clipboard->getWorld()->getChunk($x, $z)); + } + return $world; + } + /** * @return Chunk[] */ diff --git a/src/xenialdan/MagicWE2/session/Session.php b/src/xenialdan/MagicWE2/session/Session.php index 9ac0003..c8cd989 100644 --- a/src/xenialdan/MagicWE2/session/Session.php +++ b/src/xenialdan/MagicWE2/session/Session.php @@ -9,7 +9,6 @@ use pocketmine\lang\Language; use pocketmine\Server; use pocketmine\utils\TextFormat as TF; -use pocketmine\world\World; use Ramsey\Uuid\UuidInterface; use RuntimeException; use SplDoublyLinkedList; @@ -219,17 +218,17 @@ public function addRevert(RevertClipboard $revertClipboard): void */ public function undo(): void { - if ($this->undoHistory->count() === 0) { + if($this->undoHistory->count() === 0){ $this->sendMessage(TF::RED . $this->getLanguage()->translateString('session.undo.none')); return; } /** @var RevertClipboard $revertClipboard */ $revertClipboard = $this->undoHistory->pop(); - $world = $revertClipboard->getWorld(); - foreach ($revertClipboard->chunks as $hash => $chunk) { - World::getXZ($hash, $x, $z); - $revertClipboard->chunks[$hash] = $world->getChunk($x, $z); - } +// $world = $revertClipboard->getWorld(); +// foreach ($revertClipboard->chunks as $hash => $chunk) { +// World::getXZ($hash, $x, $z); +// $revertClipboard->chunks[$hash] = $world->getChunk($x, $z); +// } Server::getInstance()->getAsyncPool()->submitTask(new AsyncRevertTask($this->getUUID(), $revertClipboard, AsyncRevertTask::TYPE_UNDO)); $this->sendMessage(TF::GREEN . $this->getLanguage()->translateString('session.undo.left', [count($this->undoHistory)])); } diff --git a/src/xenialdan/MagicWE2/task/AsyncActionTask.php b/src/xenialdan/MagicWE2/task/AsyncActionTask.php index 5f19f9d..5c30fd9 100644 --- a/src/xenialdan/MagicWE2/task/AsyncActionTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncActionTask.php @@ -56,6 +56,7 @@ public function __construct(UuidInterface $sessionUUID, Selection $selection, Ta $this->action = $action; $this->newBlocks = $newBlocks; $this->blockFilter = $blockFilter; + $this->manager = $selection->getIterator()->getManager(); try { $session = SessionHelper::getSessionByUUID($sessionUUID); @@ -76,12 +77,12 @@ public function __construct(UuidInterface $sessionUUID, Selection $selection, Ta * @return void * @throws Exception */ - public function onRun(): void - { + public function onRun(): void{ $this->publishProgress(new Progress(0, "Preparing {$this->action::getName()}")); /** @var Selection $selection */ - $selection = igbinary_unserialize($this->selection/*, ['allowed_classes' => [Selection::class]]*/);//TODO test pm4 + $selection = igbinary_unserialize($this->selection); + $manager = $this->manager; $oldBlocks = new SingleClipboard($this->action->clipboardVector ?? new Vector3(0, 0, 0));//TODO Test if null V3 is ok //TODO test if the vector works $oldBlocks->selection = $selection;//TODO test. Needed to add this so that //paste works after //cut2 @@ -89,11 +90,10 @@ public function onRun(): void $messages = []; //$error = false; /** @var Progress $progress */ - foreach ($this->action->execute($this->sessionUUID, $selection, $changed, $this->newBlocks, $this->blockFilter, $oldBlocks, $messages) as $progress) { + foreach($this->action->execute($this->sessionUUID, $selection, $manager, $changed, $this->newBlocks, $this->blockFilter, $oldBlocks, $messages) as $progress){ $this->publishProgress($progress); } - $manager = $selection->getIterator()->getManager(); $resultChunks = $manager->getChunks(); $resultChunks = array_filter($resultChunks, static function (Chunk $chunk) { return $chunk->isTerrainDirty(); diff --git a/src/xenialdan/MagicWE2/task/AsyncCopyTask.php b/src/xenialdan/MagicWE2/task/AsyncCopyTask.php index c691c35..563d4aa 100644 --- a/src/xenialdan/MagicWE2/task/AsyncCopyTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncCopyTask.php @@ -26,7 +26,6 @@ class AsyncCopyTask extends MWEAsyncTask private string $selection; private Vector3 $offset; - private AsyncWorld $manager; /** * AsyncCopyTask constructor. diff --git a/src/xenialdan/MagicWE2/task/AsyncCountTask.php b/src/xenialdan/MagicWE2/task/AsyncCountTask.php deleted file mode 100644 index 0e23ac1..0000000 --- a/src/xenialdan/MagicWE2/task/AsyncCountTask.php +++ /dev/null @@ -1,123 +0,0 @@ -start = microtime(true); - $this->sessionUUID = $sessionUUID->toString(); - $this->selection = igbinary_serialize($selection); - $this->filterblocks = $filterblocks; - } - - /** - * Actions to execute when run - * - * @return void - * @throws Exception - */ - public function onRun(): void - { - $this->publishProgress([0, "Start"]); - /** @var Selection $selection */ - $selection = igbinary_unserialize($this->selection/*, ['allowed_classes' => [Selection::class]]*/);//TODO test pm4 - $totalCount = $selection->getShape()->getTotalCount(); - $counts = $this->countBlocks($selection, $this->filterblocks); - $this->setResult(compact("counts", "totalCount")); - } - - /** - * @param Selection $selection - * @param BlockPalette $filterblocks - * @return array - * @throws Exception - */ - private function countBlocks(Selection $selection, BlockPalette $filterblocks): array - { - $manager = $selection->getIterator()->getManager(); - $blockCount = $selection->getShape()->getTotalCount(); - $changed = 0; - $this->publishProgress([0, "Running, counting $changed blocks out of $blockCount"]); - $lastchunkx = $lastchunkz = null; - $lastprogress = 0; - $counts = []; - /** @var Block $block */ - foreach ($selection->getShape()->getBlocks($manager, $filterblocks) as $block) { - if (is_null($lastchunkx) || ($block->getPosition()->x >> 4 !== $lastchunkx && $block->getPosition()->z >> 4 !== $lastchunkz)) { - $lastchunkx = $block->getPosition()->x >> 4; - $lastchunkz = $block->getPosition()->z >> 4; - if (is_null($manager->getChunk($block->getPosition()->x >> 4, $block->getPosition()->z >> 4))) { - #print PHP_EOL . "Not found: " . strval($block->x >> 4) . ":" . strval($block->z >> 4) . PHP_EOL; - continue; - } - } - BlockFactory::getInstance(); - $block1 = $manager->getBlockAt($block->getPosition()->getFloorX(), $block->getPosition()->getFloorY(), $block->getPosition()->getFloorZ()); - $tostring = $block1->getName() . " " . $block1->getId() . ":" . $block1->getMeta(); - if (!array_key_exists($tostring, $counts)) $counts[$tostring] = 0; - $counts[$tostring]++; - $changed++; - $progress = floor($changed / $blockCount * 100); - if ($lastprogress < $progress) {//this prevents spamming packets - $this->publishProgress([$progress, "Running, counting $changed blocks out of $blockCount"]); - $lastprogress = $progress; - } - } - return $counts; - } - - /** - * @throws AssumptionFailedError - */ - public function onCompletion(): void - { - try { - $session = SessionHelper::getSessionByUUID(Uuid::fromString($this->sessionUUID)); - if ($session instanceof UserSession) $session->getBossBar()->hideFromAll(); - $result = $this->getResult(); - $counts = $result["counts"]; - $totalCount = $result["totalCount"]; - $session->sendMessage(TF::GREEN . $session->getLanguage()->translateString('task.count.success', [$this->generateTookString()])); - $session->sendMessage(TF::DARK_AQUA . $session->getLanguage()->translateString('task.count.result', [count($counts), $totalCount])); - uasort($counts, static function ($a, $b) { - if ($a === $b) return 0; - return ($a > $b) ? -1 : 1; - }); - foreach ($counts as $block => $count) { - $session->sendMessage(TF::AQUA . $count . "x | " . round($count / $totalCount * 100) . "% | " . $block); - } - } catch (SessionException $e) { - Loader::getInstance()->getLogger()->logException($e); - } - } -} \ No newline at end of file diff --git a/src/xenialdan/MagicWE2/task/AsyncFillTask.php b/src/xenialdan/MagicWE2/task/AsyncFillTask.php index d0ec7a5..7f15ca6 100644 --- a/src/xenialdan/MagicWE2/task/AsyncFillTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncFillTask.php @@ -32,7 +32,6 @@ class AsyncFillTask extends MWEAsyncTask private string $selection; //private string $newBlocks; private BlockPalette $newBlocks; - private AsyncWorld $manager; /** * AsyncFillTask constructor. diff --git a/src/xenialdan/MagicWE2/task/AsyncPasteAssetTask.php b/src/xenialdan/MagicWE2/task/AsyncPasteAssetTask.php index e9aeb2b..c818c6c 100644 --- a/src/xenialdan/MagicWE2/task/AsyncPasteAssetTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncPasteAssetTask.php @@ -53,7 +53,7 @@ public function __construct(UuidInterface $sessionUUID, Vector3 $target, Selecti $this->target = $target; #var_dump("paste", $selection->getShape()->getPasteVector(), "cb position", $clipboard->position, "offset", $this->offset, $clipboard); $this->sessionUUID = $sessionUUID->toString(); - + $this->manager = $selection->getIterator()->getManager(); $this->selection = igbinary_serialize($selection); $this->asset = igbinary_serialize($asset); } diff --git a/src/xenialdan/MagicWE2/task/AsyncPasteTask.php b/src/xenialdan/MagicWE2/task/AsyncPasteTask.php index 49259b2..c176342 100644 --- a/src/xenialdan/MagicWE2/task/AsyncPasteTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncPasteTask.php @@ -31,7 +31,6 @@ class AsyncPasteTask extends MWEAsyncTask { private string $clipboard; private Vector3 $offset; - private AsyncWorld $manager; /** * AsyncPasteTask constructor. diff --git a/src/xenialdan/MagicWE2/task/AsyncReplaceTask.php b/src/xenialdan/MagicWE2/task/AsyncReplaceTask.php index 4e0593e..29fb300 100644 --- a/src/xenialdan/MagicWE2/task/AsyncReplaceTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncReplaceTask.php @@ -16,6 +16,7 @@ use xenialdan\MagicWE2\API; use xenialdan\MagicWE2\clipboard\RevertClipboard; use xenialdan\MagicWE2\exception\SessionException; +use xenialdan\MagicWE2\helper\AsyncWorld; use xenialdan\MagicWE2\helper\BlockPalette; use xenialdan\MagicWE2\helper\SessionHelper; use xenialdan\MagicWE2\Loader; @@ -42,6 +43,7 @@ public function __construct(UuidInterface $sessionUUID, Selection $selection, Bl { $this->start = microtime(true); $this->sessionUUID = $sessionUUID->toString(); + $this->manager = $selection->getIterator()->getManager(); $this->selection = igbinary_serialize($selection); $this->searchBlocks = $searchBlocks; $this->replaceBlocks = $replaceBlocks; @@ -62,7 +64,7 @@ public function onRun(): void $manager = $selection->getIterator()->getManager(); - $oldBlocks = iterator_to_array($this->execute($selection, $this->searchBlocks, $this->replaceBlocks, $changed)); + $oldBlocks = iterator_to_array($this->execute($manager, $selection, $this->searchBlocks, $this->replaceBlocks, $changed)); $resultChunks = $manager->getChunks(); $resultChunks = array_filter($resultChunks, static function (Chunk $chunk) { @@ -72,16 +74,16 @@ public function onRun(): void } /** - * @param Selection $selection + * @param AsyncWorld $manager + * @param Selection $selection * @param BlockPalette $searchBlocks * @param BlockPalette $replaceBlocks - * @param null|int $changed + * @param null|int $changed + * * @return Generator * @throws InvalidArgumentException */ - private function execute(Selection $selection, BlockPalette $searchBlocks, BlockPalette $replaceBlocks, ?int &$changed): Generator - { - $manager = $selection->getIterator()->getManager(); + private function execute(AsyncWorld &$manager, Selection $selection, BlockPalette $searchBlocks, BlockPalette $replaceBlocks, ?int &$changed) : Generator{ $blockCount = $selection->getShape()->getTotalCount(); $lastchunkx = $lastchunkz = null; $lastprogress = 0; diff --git a/src/xenialdan/MagicWE2/task/AsyncRevertTask.php b/src/xenialdan/MagicWE2/task/AsyncRevertTask.php index bb04986..a637fde 100644 --- a/src/xenialdan/MagicWE2/task/AsyncRevertTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncRevertTask.php @@ -17,11 +17,13 @@ use xenialdan\MagicWE2\helper\SessionHelper; use xenialdan\MagicWE2\Loader; use xenialdan\MagicWE2\session\UserSession; +use function count; use function igbinary_serialize; use function igbinary_unserialize; +use function iterator_to_array; +use function var_dump; -class AsyncRevertTask extends MWEAsyncTask -{ +class AsyncRevertTask extends MWEAsyncTask{ public const TYPE_UNDO = 0; public const TYPE_REDO = 1; @@ -43,7 +45,7 @@ public function __construct(UuidInterface $sessionUUID, RevertClipboard $clipboa $this->start = microtime(true); $this->clipboard = igbinary_serialize($clipboard); $this->type = $type; - //TODO AsyncWorld $manager + $this->manager = AsyncWorld::fromRevertClipboard($clipboard); } /** @@ -52,22 +54,23 @@ public function __construct(UuidInterface $sessionUUID, RevertClipboard $clipboa * @return void * @throws Exception */ - public function onRun(): void - { + public function onRun(): void{ $this->publishProgress([0, "Start"]); /** @var RevertClipboard $clipboard */ $clipboard = igbinary_unserialize($this->clipboard/*, ['allowed_classes' => [RevertClipboard::class]]*/);//TODO test pm4 - $totalCount = count($clipboard->blocksAfter); -// $manager = $clipboard::getChunkManager($clipboard->chunks); - $manager = $clipboard::getChunkManager($clipboard->chunks); - $oldBlocks = []; - if ($this->type === self::TYPE_UNDO) - $oldBlocks = iterator_to_array($this->undoChunks($manager, $clipboard)); - if ($this->type === self::TYPE_REDO) - $oldBlocks = iterator_to_array($this->redoChunks($manager, $clipboard)); + $manager = $this->manager; +// $oldBlocks = []; +// if ($this->type === self::TYPE_UNDO) +// $oldBlocks = iterator_to_array($this->undoChunks($manager, $clipboard)); +// if ($this->type === self::TYPE_REDO) +// $oldBlocks = iterator_to_array($this->redoChunks($manager, $clipboard)); + if($this->type === self::TYPE_UNDO) + iterator_to_array($this->undoChunks($manager, $clipboard)); + if($this->type === self::TYPE_REDO) + iterator_to_array($this->redoChunks($manager, $clipboard)); $chunks = $manager->getChunks(); - $this->setResult(compact("chunks", "oldBlocks", "totalCount")); + $this->setResult($chunks); } /** @@ -78,7 +81,7 @@ public function onRun(): void * @throws InvalidArgumentException * @phpstan-return Generator */ - private function undoChunks(AsyncWorld $manager, RevertClipboard $clipboard) : Generator{ + private function undoChunks(AsyncWorld &$manager, RevertClipboard $clipboard) : Generator{ $count = count($clipboard->blocksAfter); $changed = 0; $this->publishProgress([0, "Reverted $changed blocks out of $count"]); @@ -86,6 +89,8 @@ private function undoChunks(AsyncWorld $manager, RevertClipboard $clipboard) : G foreach($clipboard->blocksAfter as $block){ yield $block; $block = self::singleDataToBlock($block);//turn data into real block + var_dump("HAD " . $manager->getBlockAt($block->getPosition()->x, $block->getPosition()->y, $block->getPosition()->z)->getId()); + var_dump("SET " . $block); $manager->setBlockAt($block->getPosition()->getFloorX(), $block->getPosition()->getFloorY(), $block->getPosition()->getFloorZ(), $block); $changed++; $this->publishProgress([$changed / $count, "Reverted $changed blocks out of $count"]); @@ -99,7 +104,7 @@ private function undoChunks(AsyncWorld $manager, RevertClipboard $clipboard) : G * @throws InvalidArgumentException * @phpstan-return Generator */ - private function redoChunks(AsyncWorld $manager, RevertClipboard $clipboard) : Generator{ + private function redoChunks(AsyncWorld &$manager, RevertClipboard $clipboard) : Generator{ $count = count($clipboard->blocksAfter); $changed = 0; $this->publishProgress([0, "Redone $changed blocks out of $count"]); @@ -107,6 +112,8 @@ private function redoChunks(AsyncWorld $manager, RevertClipboard $clipboard) : G foreach($clipboard->blocksAfter as $block){ yield $block; $block = self::singleDataToBlock($block);//turn data into real block + var_dump("HAD " . $manager->getBlockAt($block->getPosition()->x, $block->getPosition()->y, $block->getPosition()->z)->getId()); + var_dump("SET " . $block); $manager->setBlockAt($block->getPosition()->getFloorX(), $block->getPosition()->getFloorY(), $block->getPosition()->getFloorZ(), $block); $changed++; $this->publishProgress([$changed / $count, "Redone $changed blocks out of $count"]); @@ -118,27 +125,26 @@ private function redoChunks(AsyncWorld $manager, RevertClipboard $clipboard) : G */ public function onCompletion(): void { - try { + try{ $session = SessionHelper::getSessionByUUID(Uuid::fromString($this->sessionUUID)); - if ($session instanceof UserSession) $session->getBossBar()->hideFromAll(); - } catch (SessionException $e) { + if($session instanceof UserSession) $session->getBossBar()->hideFromAll(); + }catch(SessionException $e){ Loader::getInstance()->getLogger()->logException($e); $session = null; } $result = $this->getResult(); /** @var RevertClipboard $clipboard */ $clipboard = igbinary_unserialize($this->clipboard/*, ['allowed_classes' => [RevertClipboard::class]]*/);//TODO test pm4 - $clipboard->chunks = $result["chunks"]; - $totalCount = $result["totalCount"]; - $changed = count($result["oldBlocks"]); - $clipboard->blocksAfter = $result["oldBlocks"];//already is a array of data + $clipboard->chunks = $result; + $totalCount = $changed = count($clipboard->blocksAfter); +// $clipboard->blocksAfter = $result["oldBlocks"];//already is a array of data //commented out because we don't modify the array anymore $world = $clipboard->getWorld(); - foreach ($clipboard->chunks as $hash => $chunk) { + foreach($clipboard->chunks as $hash => $chunk){ World::getXZ($hash, $x, $z); $world->setChunk($x, $z, $chunk); } - if (!is_null($session)) { - switch ($this->type) { + if(!is_null($session)){ + switch($this->type){ case self::TYPE_UNDO: { $session->sendMessage(TF::GREEN . $session->getLanguage()->translateString('task.revert.undo.success', [$this->generateTookString(), $changed, $totalCount])); diff --git a/src/xenialdan/MagicWE2/task/MWEAsyncTask.php b/src/xenialdan/MagicWE2/task/MWEAsyncTask.php index 44f8415..1c81fa3 100644 --- a/src/xenialdan/MagicWE2/task/MWEAsyncTask.php +++ b/src/xenialdan/MagicWE2/task/MWEAsyncTask.php @@ -8,6 +8,7 @@ use pocketmine\world\Position; use Ramsey\Uuid\Uuid; use xenialdan\MagicWE2\exception\SessionException; +use xenialdan\MagicWE2\helper\AsyncWorld; use xenialdan\MagicWE2\helper\Progress; use xenialdan\MagicWE2\helper\SessionHelper; use xenialdan\MagicWE2\session\UserSession; @@ -16,6 +17,7 @@ abstract class MWEAsyncTask extends AsyncTask { public string $sessionUUID; public float $start; + public AsyncWorld $manager; public function onProgressUpdate($progress): void { diff --git a/src/xenialdan/MagicWE2/task/action/CountAction.php b/src/xenialdan/MagicWE2/task/action/CountAction.php index fd6b081..e2dfa39 100644 --- a/src/xenialdan/MagicWE2/task/action/CountAction.php +++ b/src/xenialdan/MagicWE2/task/action/CountAction.php @@ -9,6 +9,7 @@ use pocketmine\block\BlockFactory; use pocketmine\utils\TextFormat as TF; use xenialdan\MagicWE2\clipboard\SingleClipboard; +use xenialdan\MagicWE2\helper\AsyncWorld; use xenialdan\MagicWE2\helper\BlockPalette; use xenialdan\MagicWE2\helper\Progress; use xenialdan\MagicWE2\selection\Selection; @@ -30,26 +31,19 @@ public static function getName(): string } /** - * @param string $sessionUUID - * @param Selection $selection - * @param null|int $changed - * @param BlockPalette $newBlocks - * @param BlockPalette $blockFilter * @param SingleClipboard $oldBlocksSingleClipboard blocks before the change * @param string[] $messages - * @return Generator + * * @throws Exception */ - public function execute(string $sessionUUID, Selection $selection, ?int &$changed, BlockPalette $newBlocks, BlockPalette $blockFilter, SingleClipboard $oldBlocksSingleClipboard, array &$messages = []): Generator - { - $manager = $selection->getIterator(true)->getManager(); + public function execute(string $sessionUUID, Selection $selection, AsyncWorld &$manager, ?int &$changed, BlockPalette $newBlocks, BlockPalette $blockFilter, SingleClipboard $oldBlocksSingleClipboard, array &$messages = []) : Generator{ $changed = 0; #$oldBlocks = []; $count = $selection->getShape()->getTotalCount(); $lastProgress = new Progress(0, ""); $counts = []; BlockFactory::getInstance(); - foreach ($selection->getShape()->getBlocks($manager, $newBlocks) as $block) { + foreach($selection->getShape()->getBlocks($manager, $newBlocks) as $block){ $block1 = $manager->getBlockAt($block->getPosition()->getFloorX(), $block->getPosition()->getFloorY(), $block->getPosition()->getFloorZ()); $tostring = $block1->getName() . " " . $block1->getId() . ":" . $block1->getMeta(); if (!array_key_exists($tostring, $counts)) $counts[$tostring] = 0; diff --git a/src/xenialdan/MagicWE2/task/action/CutAction.php b/src/xenialdan/MagicWE2/task/action/CutAction.php index a15a10a..ac421a4 100644 --- a/src/xenialdan/MagicWE2/task/action/CutAction.php +++ b/src/xenialdan/MagicWE2/task/action/CutAction.php @@ -9,6 +9,7 @@ use pocketmine\block\Block; use xenialdan\libblockstate\BlockEntry; use xenialdan\MagicWE2\clipboard\SingleClipboard; +use xenialdan\MagicWE2\helper\AsyncWorld; use xenialdan\MagicWE2\helper\BlockPalette; use xenialdan\MagicWE2\helper\Progress; use xenialdan\MagicWE2\selection\Selection; @@ -32,26 +33,19 @@ public static function getName(): string } /** - * @param string $sessionUUID - * @param Selection $selection - * @param null|int $changed - * @param BlockPalette $newBlocks - * @param BlockPalette $blockFilter * @param SingleClipboard $oldBlocksSingleClipboard blocks before the change * @param string[] $messages - * @return Generator + * * @throws InvalidArgumentException */ - public function execute(string $sessionUUID, Selection $selection, ?int &$changed, BlockPalette $newBlocks, BlockPalette $blockFilter, SingleClipboard $oldBlocksSingleClipboard, array &$messages = []): Generator - { - $manager = $selection->getIterator()->getManager(); + public function execute(string $sessionUUID, Selection $selection, AsyncWorld &$manager, ?int &$changed, BlockPalette $newBlocks, BlockPalette $blockFilter, SingleClipboard $oldBlocksSingleClipboard, array &$messages = []) : Generator{ $changed = 0; $i = 0; #$oldBlocks = []; $count = $selection->getShape()->getTotalCount(); $lastProgress = new Progress(0, ""); $min = $selection->getShape()->getMinVec3(); - foreach ($selection->getShape()->getBlocks($manager, $blockFilter) as $block) {//TODO Merged iterator + foreach($selection->getShape()->getBlocks($manager, $blockFilter) as $block){//TODO Merged iterator /** @var Block $new */ $new = $newBlocks->blocks()->current();//TODO Merged iterator if ($new->getId() === $block->getId() && $new->getMeta() === $block->getMeta()) continue;//skip same blocks diff --git a/src/xenialdan/MagicWE2/task/action/SetBiomeAction.php b/src/xenialdan/MagicWE2/task/action/SetBiomeAction.php index 4a40580..d6e61d5 100644 --- a/src/xenialdan/MagicWE2/task/action/SetBiomeAction.php +++ b/src/xenialdan/MagicWE2/task/action/SetBiomeAction.php @@ -8,6 +8,7 @@ use Generator; use pocketmine\math\Vector2; use xenialdan\MagicWE2\clipboard\SingleClipboard; +use xenialdan\MagicWE2\helper\AsyncWorld; use xenialdan\MagicWE2\helper\BlockPalette; use xenialdan\MagicWE2\helper\Progress; use xenialdan\MagicWE2\selection\Selection; @@ -30,26 +31,19 @@ public static function getName(): string } /** - * @param string $sessionUUID - * @param Selection $selection - * @param null|int $changed - * @param BlockPalette $newBlocks - * @param BlockPalette $blockFilter * @param SingleClipboard $oldBlocksSingleClipboard blocks before the change * @param string[] $messages - * @return Generator + * * @throws Exception */ - public function execute(string $sessionUUID, Selection $selection, ?int &$changed, BlockPalette $newBlocks, BlockPalette $blockFilter, SingleClipboard $oldBlocksSingleClipboard, array &$messages = []): Generator - { - $manager = $selection->getIterator()->getManager(); + public function execute(string $sessionUUID, Selection $selection, AsyncWorld &$manager, ?int &$changed, BlockPalette $newBlocks, BlockPalette $blockFilter, SingleClipboard $oldBlocksSingleClipboard, array &$messages = []) : Generator{ $changed = 0; #$oldBlocks = []; $count = null; $lastProgress = new Progress(0, ""); /** @var Vector2 $vec2 */ - foreach (($all = $selection->getShape()->getLayer($manager)) as $vec2) { - if (is_null($count)) $count = count(iterator_to_array($all)); + foreach(($all = $selection->getShape()->getLayer($manager)) as $vec2){ + if(is_null($count)) $count = count(iterator_to_array($all)); $manager->getChunk($vec2->x >> 4, $vec2->y >> 4)->setBiomeId(abs($vec2->x % 16), abs($vec2->y % 16), $this->biomeId); $changed++; $progress = new Progress($changed / $count, "Changed Biome for $changed/$count blocks"); diff --git a/src/xenialdan/MagicWE2/task/action/SetBlockAction.php b/src/xenialdan/MagicWE2/task/action/SetBlockAction.php index 8b04097..982e6a3 100644 --- a/src/xenialdan/MagicWE2/task/action/SetBlockAction.php +++ b/src/xenialdan/MagicWE2/task/action/SetBlockAction.php @@ -9,6 +9,7 @@ use pocketmine\block\Block; use xenialdan\libblockstate\BlockEntry; use xenialdan\MagicWE2\clipboard\SingleClipboard; +use xenialdan\MagicWE2\helper\AsyncWorld; use xenialdan\MagicWE2\helper\BlockPalette; use xenialdan\MagicWE2\helper\Progress; use xenialdan\MagicWE2\selection\Selection; @@ -26,28 +27,21 @@ public static function getName(): string } /** - * @param string $sessionUUID - * @param Selection $selection - * @param null|int $changed - * @param BlockPalette $newBlocks - * @param BlockPalette $blockFilter * @param SingleClipboard $oldBlocksSingleClipboard blocks before the change * @param string[] $messages - * @return Generator + * * @throws InvalidArgumentException */ - public function execute(string $sessionUUID, Selection $selection, ?int &$changed, BlockPalette $newBlocks, BlockPalette $blockFilter, SingleClipboard $oldBlocksSingleClipboard, array &$messages = []): Generator - { - $manager = $selection->getIterator()->getManager(); + public function execute(string $sessionUUID, Selection $selection, AsyncWorld &$manager, ?int &$changed, BlockPalette $newBlocks, BlockPalette $blockFilter, SingleClipboard $oldBlocksSingleClipboard, array &$messages = []) : Generator{ $changed = 0; $i = 0; #$oldBlocks = []; $count = $selection->getShape()->getTotalCount(); $lastProgress = new Progress(0, ""); - foreach ($selection->getShape()->getBlocks($manager, $blockFilter) as $block) {//TODO merge iterator + foreach($selection->getShape()->getBlocks($manager, $blockFilter) as $block){//TODO merge iterator /** @var Block $new */ $new = $newBlocks->blocks()->current();//TODO merge iterator - if ($new->getId() === $block->getId() && $new->getMeta() === $block->getMeta()) continue;//skip same blocks + if($new->getId() === $block->getId() && $new->getMeta() === $block->getMeta()) continue;//skip same blocks #$oldBlocks[] = API::setComponents($manager->getBlockAt($block->getPosition()->getFloorX(), $block->getPosition()->getFloorY(), $block->getPosition()->getFloorZ()),$block->x, $block->y, $block->z); $oldBlocksSingleClipboard->addEntry($block->getPosition()->getFloorX(), $block->getPosition()->getFloorY(), $block->getPosition()->getFloorZ(), BlockEntry::fromBlock($block)); $manager->setBlockAt($block->getPosition()->getFloorX(), $block->getPosition()->getFloorY(), $block->getPosition()->getFloorZ(), $new); diff --git a/src/xenialdan/MagicWE2/task/action/TaskAction.php b/src/xenialdan/MagicWE2/task/action/TaskAction.php index 6497779..92aa6ce 100644 --- a/src/xenialdan/MagicWE2/task/action/TaskAction.php +++ b/src/xenialdan/MagicWE2/task/action/TaskAction.php @@ -7,42 +7,37 @@ use Generator; use pocketmine\math\Vector3; use xenialdan\MagicWE2\clipboard\SingleClipboard; +use xenialdan\MagicWE2\helper\AsyncWorld; use xenialdan\MagicWE2\helper\BlockPalette; use xenialdan\MagicWE2\selection\Selection; abstract class TaskAction { - /** @var string */ public string $prefix = ""; - /** @var bool */ public bool $addRevert = true; - /** @var string */ public string $completionString = '{%name} succeed, took {%took}, {%changed} blocks out of {%total} changed.'; - /** @var bool */ public bool $addClipboard = false; - /** @var null|Vector3 */ public ?Vector3 $clipboardVector = null; //TODO add $flags and define available flags in child classes //public $flags //protected const AVAILABLE_FLAGS = [];(can be overwritten), access with static::AVAILABLE_FLAGS /** - * @param string $sessionUUID - * @param Selection $selection - * @param null|int $changed - * @param BlockPalette $newBlocks - * @param BlockPalette $blockFilter + * @param string $sessionUUID + * @param Selection $selection + * @param AsyncWorld $manager + * @param null|int $changed + * @param BlockPalette $newBlocks + * @param BlockPalette $blockFilter * @param SingleClipboard $oldBlocksSingleClipboard blocks before the change - * @param string[] $messages + * @param string[] $messages + * * @return Generator */ - abstract public function execute(string $sessionUUID, Selection $selection, ?int &$changed, BlockPalette $newBlocks, BlockPalette $blockFilter, SingleClipboard $oldBlocksSingleClipboard, array &$messages = []): Generator; + abstract public function execute(string $sessionUUID, Selection $selection, AsyncWorld &$manager, ?int &$changed, BlockPalette $newBlocks, BlockPalette $blockFilter, SingleClipboard $oldBlocksSingleClipboard, array &$messages = []) : Generator; abstract public static function getName(): string; - /** - * @param Vector3|null $clipboardVector - */ public function setClipboardVector(?Vector3 $clipboardVector): void { if ($clipboardVector instanceof Vector3) $clipboardVector = $clipboardVector->asVector3()->floor(); diff --git a/src/xenialdan/MagicWE2/task/action/TestAction.php b/src/xenialdan/MagicWE2/task/action/TestAction.php index 3d71dc8..22fd64b 100644 --- a/src/xenialdan/MagicWE2/task/action/TestAction.php +++ b/src/xenialdan/MagicWE2/task/action/TestAction.php @@ -8,6 +8,7 @@ use Generator; use pocketmine\block\BlockFactory; use xenialdan\MagicWE2\clipboard\SingleClipboard; +use xenialdan\MagicWE2\helper\AsyncWorld; use xenialdan\MagicWE2\helper\BlockPalette; use xenialdan\MagicWE2\helper\Progress; use xenialdan\MagicWE2\selection\Selection; @@ -29,25 +30,18 @@ public static function getName(): string } /** - * @param string $sessionUUID - * @param Selection $selection - * @param null|int $changed - * @param BlockPalette $newBlocks - * @param BlockPalette $blockFilter * @param SingleClipboard $oldBlocksSingleClipboard blocks before the change * @param string[] $messages - * @return Generator + * * @throws Exception */ - public function execute(string $sessionUUID, Selection $selection, ?int &$changed, BlockPalette $newBlocks, BlockPalette $blockFilter, SingleClipboard $oldBlocksSingleClipboard, array &$messages = []): Generator - { - $manager = $selection->getIterator()->getManager(); + public function execute(string $sessionUUID, Selection $selection, AsyncWorld &$manager, ?int &$changed, BlockPalette $newBlocks, BlockPalette $blockFilter, SingleClipboard $oldBlocksSingleClipboard, array &$messages = []) : Generator{ $changed = 0; #$oldBlocks = []; $count = $selection->getShape()->getTotalCount(); $lastProgress = new Progress(0, ""); BlockFactory::getInstance(); - foreach ($selection->getShape()->getBlocks($manager, $blockFilter) as $block) { + foreach($selection->getShape()->getBlocks($manager, $blockFilter) as $block){ $changed++; $messages[] = $block->getPosition()->asVector3()->__toString() . " " . $block->getName(); $progress = new Progress($changed / $count, "$changed/$count"); diff --git a/src/xenialdan/MagicWE2/task/action/ThawAction.php b/src/xenialdan/MagicWE2/task/action/ThawAction.php index 0a1dd55..9a67bb2 100644 --- a/src/xenialdan/MagicWE2/task/action/ThawAction.php +++ b/src/xenialdan/MagicWE2/task/action/ThawAction.php @@ -9,6 +9,7 @@ use pocketmine\block\VanillaBlocks; use xenialdan\libblockstate\BlockEntry; use xenialdan\MagicWE2\clipboard\SingleClipboard; +use xenialdan\MagicWE2\helper\AsyncWorld; use xenialdan\MagicWE2\helper\BlockPalette; use xenialdan\MagicWE2\helper\Progress; use xenialdan\MagicWE2\selection\Selection; @@ -26,19 +27,12 @@ public static function getName(): string } /** - * @param string $sessionUUID - * @param Selection $selection - * @param null|int $changed - * @param BlockPalette $newBlocks - * @param BlockPalette $blockFilter * @param SingleClipboard $oldBlocksSingleClipboard blocks before the change * @param string[] $messages - * @return Generator + * * @throws InvalidArgumentException */ - public function execute(string $sessionUUID, Selection $selection, ?int &$changed, BlockPalette $newBlocks, BlockPalette $blockFilter, SingleClipboard $oldBlocksSingleClipboard, array &$messages = []): Generator - { - $manager = $selection->getIterator()->getManager(); + public function execute(string $sessionUUID, Selection $selection, AsyncWorld &$manager, ?int &$changed, BlockPalette $newBlocks, BlockPalette $blockFilter, SingleClipboard $oldBlocksSingleClipboard, array &$messages = []) : Generator{ $changed = 0; $i = 0; #$oldBlocks = []; @@ -47,7 +41,7 @@ public function execute(string $sessionUUID, Selection $selection, ?int &$change $blockFilterA = [VanillaBlocks::SNOW_LAYER(), VanillaBlocks::SNOW(), VanillaBlocks::ICE()]; $newBlocksA = [VanillaBlocks::AIR(), VanillaBlocks::AIR(), VanillaBlocks::WATER()]; - foreach ($blockFilterA as $ib => $blockF) { + foreach($blockFilterA as $ib => $blockF){ foreach ($selection->getShape()->getBlocks($manager, BlockPalette::CREATE()) as $block) {//TODO merged generator iterating blocks and newblocks $new = clone $newBlocksA[$ib]; #$oldBlocks[] = API::setComponents($manager->getBlockAt($block->getPosition()->getFloorX(), $block->getPosition()->getFloorY(), $block->getPosition()->getFloorZ()),$block->x, $block->y, $block->z); From 8e08010164a27cc995043f73cdb254632f971864 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Wed, 5 Oct 2022 07:53:05 +0200 Subject: [PATCH 19/24] Fix //undo with //cut2 --- src/xenialdan/MagicWE2/task/AsyncActionTask.php | 3 ++- src/xenialdan/MagicWE2/task/AsyncRevertTask.php | 4 ++++ src/xenialdan/MagicWE2/task/action/CutAction.php | 10 ++++++---- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/xenialdan/MagicWE2/task/AsyncActionTask.php b/src/xenialdan/MagicWE2/task/AsyncActionTask.php index 5c30fd9..05d9195 100644 --- a/src/xenialdan/MagicWE2/task/AsyncActionTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncActionTask.php @@ -131,11 +131,12 @@ public function onCompletion(): void $changed = $result["changed"]; /** @var Selection $selection */ $selection = igbinary_unserialize($this->selection/*, ['allowed_classes' => [Selection::class]]*/);//TODO test pm4 - $undoChunks = $selection->getIterator()->getManager()->getChunks(); + $undoChunks = []; $totalCount = $selection->getShape()->getTotalCount(); $world = $selection->getWorld(); foreach ($resultChunks as $hash => $chunk) { World::getXZ($hash, $x, $z); + $undoChunks[$hash] = $world->getChunk($x, $z); $world->setChunk($x, $z, $chunk); } if (!is_null($session)) { diff --git a/src/xenialdan/MagicWE2/task/AsyncRevertTask.php b/src/xenialdan/MagicWE2/task/AsyncRevertTask.php index a637fde..666c2f8 100644 --- a/src/xenialdan/MagicWE2/task/AsyncRevertTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncRevertTask.php @@ -46,6 +46,10 @@ public function __construct(UuidInterface $sessionUUID, RevertClipboard $clipboa $this->clipboard = igbinary_serialize($clipboard); $this->type = $type; $this->manager = AsyncWorld::fromRevertClipboard($clipboard); + foreach($clipboard->chunks as $hash => $chunk){ + World::getXZ($hash, $x, $z); + var_dump("Chunk $hash at $x, $z"); + } } /** diff --git a/src/xenialdan/MagicWE2/task/action/CutAction.php b/src/xenialdan/MagicWE2/task/action/CutAction.php index ac421a4..b28251c 100644 --- a/src/xenialdan/MagicWE2/task/action/CutAction.php +++ b/src/xenialdan/MagicWE2/task/action/CutAction.php @@ -48,18 +48,20 @@ public function execute(string $sessionUUID, Selection $selection, AsyncWorld &$ foreach($selection->getShape()->getBlocks($manager, $blockFilter) as $block){//TODO Merged iterator /** @var Block $new */ $new = $newBlocks->blocks()->current();//TODO Merged iterator - if ($new->getId() === $block->getId() && $new->getMeta() === $block->getMeta()) continue;//skip same blocks + /** @noinspection PhpInternalEntityUsedInspection */ + if($new->getFullId() === $block->getFullId()) continue;//skip same blocks #$oldBlocks[] = API::setComponents($manager->getBlockAt($block->getPosition()->getFloorX(), $block->getPosition()->getFloorY(), $block->getPosition()->getFloorZ()),$block->x, $block->y, $block->z); - $newv3 = $block->getPosition()->subtractVector($min)->floor();//TODO check if only used for clipboard + #$newv3 = $block->getPosition()->subtractVector($min)->floor();//TODO check if only used for clipboard + $newv3 = $block->getPosition()->asVector3(); $oldBlocksSingleClipboard->addEntry($newv3->getFloorX(), $newv3->getFloorY(), $newv3->getFloorZ(), BlockEntry::fromBlock($block)); $manager->setBlockAt($block->getPosition()->getFloorX(), $block->getPosition()->getFloorY(), $block->getPosition()->getFloorZ(), $new); /** @noinspection PhpInternalEntityUsedInspection */ - if ($manager->getBlockFullIdAt($block->getPosition()->getFloorX(), $block->getPosition()->getFloorY(), $block->getPosition()->getFloorZ()) !== $block->getFullId()) { + if($manager->getBlockFullIdAt($block->getPosition()->getFloorX(), $block->getPosition()->getFloorY(), $block->getPosition()->getFloorZ()) !== $block->getFullId()){ $changed++; } $i++; $progress = new Progress($i / $count, "Changed $changed blocks out of $count"); - if (floor($progress->progress * 100) > floor($lastProgress->progress * 100)) { + if(floor($progress->progress * 100) > floor($lastProgress->progress * 100)){ yield $progress; $lastProgress = $progress; } From 64e4fad489b2a8c880d72f492f3ad18c939e3fd4 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Wed, 5 Oct 2022 09:14:22 +0200 Subject: [PATCH 20/24] Fixed undo and redo --- .../MagicWE2/task/AsyncRevertTask.php | 52 +++++++++---------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/src/xenialdan/MagicWE2/task/AsyncRevertTask.php b/src/xenialdan/MagicWE2/task/AsyncRevertTask.php index 666c2f8..cc746c5 100644 --- a/src/xenialdan/MagicWE2/task/AsyncRevertTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncRevertTask.php @@ -5,6 +5,7 @@ use Exception; use Generator; use InvalidArgumentException; +use pocketmine\Server; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\TextFormat as TF; use pocketmine\world\Position; @@ -21,7 +22,6 @@ use function igbinary_serialize; use function igbinary_unserialize; use function iterator_to_array; -use function var_dump; class AsyncRevertTask extends MWEAsyncTask{ @@ -35,20 +35,23 @@ class AsyncRevertTask extends MWEAsyncTask{ /** * AsyncRevertTask constructor. - * @param UuidInterface $sessionUUID + * + * @param UuidInterface $sessionUUID * @param RevertClipboard $clipboard - * @param int $type The type of clipboard pasting. + * @param int $type The type of clipboard pasting. */ - public function __construct(UuidInterface $sessionUUID, RevertClipboard $clipboard, int $type = self::TYPE_UNDO) - { + public function __construct(UuidInterface $sessionUUID, RevertClipboard $clipboard, int $type = self::TYPE_UNDO){ $this->sessionUUID = $sessionUUID->toString(); $this->start = microtime(true); $this->clipboard = igbinary_serialize($clipboard); $this->type = $type; $this->manager = AsyncWorld::fromRevertClipboard($clipboard); + $world = Server::getInstance()->getWorldManager()->getWorld($clipboard->worldId); foreach($clipboard->chunks as $hash => $chunk){ World::getXZ($hash, $x, $z); - var_dump("Chunk $hash at $x, $z"); + if($type === self::TYPE_REDO){ + $this->manager->setChunk($x, $z, $world->getChunk($x, $z)); + } } } @@ -58,23 +61,20 @@ public function __construct(UuidInterface $sessionUUID, RevertClipboard $clipboa * @return void * @throws Exception */ - public function onRun(): void{ + public function onRun() : void{ $this->publishProgress([0, "Start"]); /** @var RevertClipboard $clipboard */ $clipboard = igbinary_unserialize($this->clipboard/*, ['allowed_classes' => [RevertClipboard::class]]*/);//TODO test pm4 $manager = $this->manager; -// $oldBlocks = []; -// if ($this->type === self::TYPE_UNDO) -// $oldBlocks = iterator_to_array($this->undoChunks($manager, $clipboard)); -// if ($this->type === self::TYPE_REDO) -// $oldBlocks = iterator_to_array($this->redoChunks($manager, $clipboard)); + $oldBlocks = []; if($this->type === self::TYPE_UNDO) - iterator_to_array($this->undoChunks($manager, $clipboard)); - if($this->type === self::TYPE_REDO) - iterator_to_array($this->redoChunks($manager, $clipboard)); + $oldBlocks = iterator_to_array($this->undoChunks($manager, $clipboard)); + if($this->type === self::TYPE_REDO){ + $oldBlocks = iterator_to_array($this->redoChunks($manager, $clipboard)); + } $chunks = $manager->getChunks(); - $this->setResult($chunks); + $this->setResult([$chunks, $oldBlocks]); } /** @@ -91,10 +91,9 @@ private function undoChunks(AsyncWorld &$manager, RevertClipboard $clipboard) : $this->publishProgress([0, "Reverted $changed blocks out of $count"]); //$block is "data" array foreach($clipboard->blocksAfter as $block){ - yield $block; $block = self::singleDataToBlock($block);//turn data into real block - var_dump("HAD " . $manager->getBlockAt($block->getPosition()->x, $block->getPosition()->y, $block->getPosition()->z)->getId()); - var_dump("SET " . $block); + $original = $manager->getBlockAt($block->getPosition()->x, $block->getPosition()->y, $block->getPosition()->z); + yield self::singleBlockToData($original, $block->getPosition()); $manager->setBlockAt($block->getPosition()->getFloorX(), $block->getPosition()->getFloorY(), $block->getPosition()->getFloorZ(), $block); $changed++; $this->publishProgress([$changed / $count, "Reverted $changed blocks out of $count"]); @@ -104,6 +103,7 @@ private function undoChunks(AsyncWorld &$manager, RevertClipboard $clipboard) : /** * @param AsyncWorld $manager * @param RevertClipboard $clipboard + * * @return Generator * @throws InvalidArgumentException * @phpstan-return Generator @@ -114,10 +114,9 @@ private function redoChunks(AsyncWorld &$manager, RevertClipboard $clipboard) : $this->publishProgress([0, "Redone $changed blocks out of $count"]); //$block is "data" array foreach($clipboard->blocksAfter as $block){ - yield $block; $block = self::singleDataToBlock($block);//turn data into real block - var_dump("HAD " . $manager->getBlockAt($block->getPosition()->x, $block->getPosition()->y, $block->getPosition()->z)->getId()); - var_dump("SET " . $block); + $original = $manager->getBlockAt($block->getPosition()->x, $block->getPosition()->y, $block->getPosition()->z); + yield self::singleBlockToData($original, $block->getPosition()); $manager->setBlockAt($block->getPosition()->getFloorX(), $block->getPosition()->getFloorY(), $block->getPosition()->getFloorZ(), $block); $changed++; $this->publishProgress([$changed / $count, "Redone $changed blocks out of $count"]); @@ -127,8 +126,7 @@ private function redoChunks(AsyncWorld &$manager, RevertClipboard $clipboard) : /** * @throws AssumptionFailedError */ - public function onCompletion(): void - { + public function onCompletion() : void{ try{ $session = SessionHelper::getSessionByUUID(Uuid::fromString($this->sessionUUID)); if($session instanceof UserSession) $session->getBossBar()->hideFromAll(); @@ -136,12 +134,12 @@ public function onCompletion(): void Loader::getInstance()->getLogger()->logException($e); $session = null; } - $result = $this->getResult(); + [$chunks, $oldBlocks] = $this->getResult(); /** @var RevertClipboard $clipboard */ $clipboard = igbinary_unserialize($this->clipboard/*, ['allowed_classes' => [RevertClipboard::class]]*/);//TODO test pm4 - $clipboard->chunks = $result; + $clipboard->chunks = $chunks; $totalCount = $changed = count($clipboard->blocksAfter); -// $clipboard->blocksAfter = $result["oldBlocks"];//already is a array of data //commented out because we don't modify the array anymore + $clipboard->blocksAfter = $oldBlocks;//already is a array of data $world = $clipboard->getWorld(); foreach($clipboard->chunks as $hash => $chunk){ World::getXZ($hash, $x, $z); From 5308f14d866ee1fb5bd74ffef2a543fc4f47872f Mon Sep 17 00:00:00 2001 From: XenialDan Date: Wed, 5 Oct 2022 09:31:04 +0200 Subject: [PATCH 21/24] Fix replace and pasteasset --- src/xenialdan/MagicWE2/task/AsyncPasteAssetTask.php | 2 +- src/xenialdan/MagicWE2/task/AsyncReplaceTask.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xenialdan/MagicWE2/task/AsyncPasteAssetTask.php b/src/xenialdan/MagicWE2/task/AsyncPasteAssetTask.php index c818c6c..d463b54 100644 --- a/src/xenialdan/MagicWE2/task/AsyncPasteAssetTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncPasteAssetTask.php @@ -72,7 +72,7 @@ public function onRun(): void /** @var Selection $selection */ $selection = igbinary_unserialize($this->selection/*, ['allowed_classes' => [Selection::class]]*/);//TODO test pm4 - $manager = $selection->getIterator()->getManager(); + $manager = $this->manager; // unset($touchedChunks); //$selection = igbinary_unserialize($this->selection/*, ['allowed_classes' => [Selection::class]]*/);//TODO test pm4 diff --git a/src/xenialdan/MagicWE2/task/AsyncReplaceTask.php b/src/xenialdan/MagicWE2/task/AsyncReplaceTask.php index 29fb300..40f2da9 100644 --- a/src/xenialdan/MagicWE2/task/AsyncReplaceTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncReplaceTask.php @@ -62,7 +62,7 @@ public function onRun(): void /** @var Selection $selection */ $selection = igbinary_unserialize($this->selection/*, ['allowed_classes' => [Selection::class]]*/);//TODO test pm4 - $manager = $selection->getIterator()->getManager(); + $manager = $this->manager; $oldBlocks = iterator_to_array($this->execute($manager, $selection, $this->searchBlocks, $this->replaceBlocks, $changed)); From dd31cb69e909e895f7d6d7eec6239959aefd7ae0 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Wed, 5 Oct 2022 10:20:52 +0200 Subject: [PATCH 22/24] Shut up some phpstan errors --- src/xenialdan/MagicWE2/API.php | 2 +- src/xenialdan/MagicWE2/EventListener.php | 9 ------- .../commands/selection/ChunkCommand.php | 3 --- .../commands/selection/HPos1Command.php | 4 ---- .../commands/selection/HPos2Command.php | 4 ---- .../commands/selection/Pos1Command.php | 4 ---- .../commands/selection/Pos2Command.php | 4 ---- .../MagicWE2/commands/tool/DebugCommand.php | 24 +++++++++---------- src/xenialdan/MagicWE2/helper/ArrayUtils.php | 6 ++--- .../MagicWE2/selection/Selection.php | 4 ++-- src/xenialdan/MagicWE2/session/data/Asset.php | 8 +++---- .../MagicWE2/task/AsyncRevertTask.php | 4 ++-- src/xenialdan/MagicWE2/tool/Debug.php | 6 ++--- 13 files changed, 26 insertions(+), 56 deletions(-) diff --git a/src/xenialdan/MagicWE2/API.php b/src/xenialdan/MagicWE2/API.php index 838a786..b20017f 100644 --- a/src/xenialdan/MagicWE2/API.php +++ b/src/xenialdan/MagicWE2/API.php @@ -684,7 +684,7 @@ public static function getRotationData(BlockState $blockState, int $rotation) : return API::$rotationData[$id . ":" . $meta][(string) $rotation] ?? []; } - public static function setRotationData(array $json){ + public static function setRotationData(array $json) : void{ self::$rotationData = $json; } diff --git a/src/xenialdan/MagicWE2/EventListener.php b/src/xenialdan/MagicWE2/EventListener.php index 161cd19..2440cb6 100644 --- a/src/xenialdan/MagicWE2/EventListener.php +++ b/src/xenialdan/MagicWE2/EventListener.php @@ -188,9 +188,6 @@ private function onBreakBlock(BlockBreakEvent $event) : void{ if(($selection = $session->getLatestSelection()) === null){ $session->addSelection(($selection = new Selection($session->getUUID(), $event->getBlock()->getPosition()->getWorld()))); // TODO check if the selection inside of the session updates } - if(is_null($selection)){ - throw new Error("No selection created - Check the console for errors"); - } $selection->setPos1($event->getBlock()->getPosition()); break; } @@ -241,9 +238,6 @@ private function onRightClickBlock(PlayerInteractEvent $event) : void{ if(($selection = $session->getLatestSelection()) === null){ $session->addSelection(($selection = new Selection($session->getUUID(), $event->getBlock()->getPosition()->getWorld()))); // TODO check if the selection inside of the session updates } - if(is_null($selection)){ - throw new Error("No selection created - Check the console for errors"); - } $selection->setPos2($event->getBlock()->getPosition()); break; } @@ -321,9 +315,6 @@ private function onLeftClickBlock(PlayerInteractEvent $event) : void{ if(($selection = $session->getLatestSelection()) === null){ $session->addSelection(($selection = new Selection($session->getUUID(), $event->getBlock()->getPosition()->getWorld()))); // TODO check if the selection inside of the session updates } - if(is_null($selection)){ - throw new Error("No selection created - Check the console for errors"); - } $selection->setPos1($event->getBlock()->getPosition()); break; } diff --git a/src/xenialdan/MagicWE2/commands/selection/ChunkCommand.php b/src/xenialdan/MagicWE2/commands/selection/ChunkCommand.php index fde77b7..bd42788 100644 --- a/src/xenialdan/MagicWE2/commands/selection/ChunkCommand.php +++ b/src/xenialdan/MagicWE2/commands/selection/ChunkCommand.php @@ -56,9 +56,6 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo if(($selection = $session->getLatestSelection()) === null){ $session->addSelection(($selection = new Selection($session->getUUID(), $sender->getWorld()))); // TODO check if the selection inside of the session updates } - if(is_null($selection)){ - throw new Error("No selection created - Check the console for errors"); - } $chunk = $sender->getWorld()->getOrLoadChunkAtPosition($sender->getPosition()); if(is_null($chunk)){ throw new Error("Could not find a chunk at your position"); diff --git a/src/xenialdan/MagicWE2/commands/selection/HPos1Command.php b/src/xenialdan/MagicWE2/commands/selection/HPos1Command.php index 5b54c42..d3faa61 100644 --- a/src/xenialdan/MagicWE2/commands/selection/HPos1Command.php +++ b/src/xenialdan/MagicWE2/commands/selection/HPos1Command.php @@ -16,7 +16,6 @@ use xenialdan\MagicWE2\Loader; use xenialdan\MagicWE2\selection\Selection; use xenialdan\MagicWE2\session\UserSession; -use function is_null; class HPos1Command extends BaseCommand{ @@ -53,9 +52,6 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo if(($selection = $session->getLatestSelection()) === null){ $session->addSelection(($selection = new Selection($session->getUUID(), $sender->getWorld()))); // TODO check if the selection inside of the session updates } - if(is_null($selection)){ - throw new Error("No selection created - Check the console for errors"); - } $target = $sender->getTargetBlock(Loader::getInstance()->getToolDistance()); if($target === null){ $sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.notarget')); diff --git a/src/xenialdan/MagicWE2/commands/selection/HPos2Command.php b/src/xenialdan/MagicWE2/commands/selection/HPos2Command.php index ae34c9f..9a243c7 100644 --- a/src/xenialdan/MagicWE2/commands/selection/HPos2Command.php +++ b/src/xenialdan/MagicWE2/commands/selection/HPos2Command.php @@ -16,7 +16,6 @@ use xenialdan\MagicWE2\Loader; use xenialdan\MagicWE2\selection\Selection; use xenialdan\MagicWE2\session\UserSession; -use function is_null; class HPos2Command extends BaseCommand{ @@ -53,9 +52,6 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo if(($selection = $session->getLatestSelection()) === null){ $session->addSelection(($selection = new Selection($session->getUUID(), $sender->getWorld()))); // TODO check if the selection inside of the session updates } - if(is_null($selection)){ - throw new Error("No selection created - Check the console for errors"); - } $target = $sender->getTargetBlock(Loader::getInstance()->getToolDistance()); if($target === null){ $sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.notarget')); diff --git a/src/xenialdan/MagicWE2/commands/selection/Pos1Command.php b/src/xenialdan/MagicWE2/commands/selection/Pos1Command.php index 2a144c5..926c0f0 100644 --- a/src/xenialdan/MagicWE2/commands/selection/Pos1Command.php +++ b/src/xenialdan/MagicWE2/commands/selection/Pos1Command.php @@ -16,7 +16,6 @@ use xenialdan\MagicWE2\Loader; use xenialdan\MagicWE2\selection\Selection; use xenialdan\MagicWE2\session\UserSession; -use function is_null; class Pos1Command extends BaseCommand{ @@ -53,9 +52,6 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo if(($selection = $session->getLatestSelection()) === null){ $session->addSelection(($selection = new Selection($session->getUUID(), $sender->getWorld()))); // TODO check if the selection inside of the session updates } - if(is_null($selection)){ - throw new Error("No selection created - Check the console for errors"); - } $selection->setPos1($sender->getPosition()); } catch (Exception $error) { Loader::getInstance()->getLogger()->logException($error); diff --git a/src/xenialdan/MagicWE2/commands/selection/Pos2Command.php b/src/xenialdan/MagicWE2/commands/selection/Pos2Command.php index 3866160..de70047 100644 --- a/src/xenialdan/MagicWE2/commands/selection/Pos2Command.php +++ b/src/xenialdan/MagicWE2/commands/selection/Pos2Command.php @@ -16,7 +16,6 @@ use xenialdan\MagicWE2\Loader; use xenialdan\MagicWE2\selection\Selection; use xenialdan\MagicWE2\session\UserSession; -use function is_null; class Pos2Command extends BaseCommand{ @@ -53,9 +52,6 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo if(($selection = $session->getLatestSelection()) === null){ $session->addSelection(($selection = new Selection($session->getUUID(), $sender->getWorld()))); // TODO check if the selection inside of the session updates } - if(is_null($selection)){ - throw new Error("No selection created - Check the console for errors"); - } $selection->setPos2($sender->getPosition()); } catch (Exception $error) { Loader::getInstance()->getLogger()->logException($error); diff --git a/src/xenialdan/MagicWE2/commands/tool/DebugCommand.php b/src/xenialdan/MagicWE2/commands/tool/DebugCommand.php index 21beb52..30723cf 100644 --- a/src/xenialdan/MagicWE2/commands/tool/DebugCommand.php +++ b/src/xenialdan/MagicWE2/commands/tool/DebugCommand.php @@ -16,43 +16,41 @@ use xenialdan\MagicWE2\Loader; use xenialdan\MagicWE2\tool\Debug; -class DebugCommand extends BaseCommand -{ +class DebugCommand extends BaseCommand{ /** * This is where all the arguments, permissions, sub-commands, etc would be registered * @throws InvalidArgumentException */ - protected function prepare(): void - { + protected function prepare() : void{ $this->setPermission("we.command.tool.debug"); } /** * @inheritDoc */ - public function onRun(CommandSender $sender, string $aliasUsed, array $args): void - { + public function onRun(CommandSender $sender, string $aliasUsed, array $args) : void{ $lang = Loader::getInstance()->getLanguage(); - if ($sender instanceof Player && SessionHelper::hasSession($sender)) { - try { + if($sender instanceof Player && SessionHelper::hasSession($sender)){ + try{ $lang = SessionHelper::getUserSession($sender)->getLanguage(); - } catch (SessionException) { + }catch(SessionException){ } } - if (!$sender instanceof Player) { + if(!$sender instanceof Player){ $sender->sendMessage(TF::RED . $lang->translateString('error.runingame')); return; } /** @var Player $sender */ - try { + try{ + $session = SessionHelper::getUserSession($sender); $item = ($session->debug ?? (new Debug()))->toItem($lang); $sender->getInventory()->addItem($item); - } catch (Exception $error) { + }catch(Exception $error){ $sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error')); $sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage()); $sender->sendMessage($this->getUsage()); - } catch (Error $error) { + }catch(Error $error){ Loader::getInstance()->getLogger()->logException($error); $sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage()); } diff --git a/src/xenialdan/MagicWE2/helper/ArrayUtils.php b/src/xenialdan/MagicWE2/helper/ArrayUtils.php index e195cd4..92035cb 100644 --- a/src/xenialdan/MagicWE2/helper/ArrayUtils.php +++ b/src/xenialdan/MagicWE2/helper/ArrayUtils.php @@ -9,7 +9,7 @@ class ArrayUtils{ - public static function advanceWrap(&$array) : array{ + public static function advanceWrap(array &$array) : array{ $result = [key($array), current($array)]; if(!self::hasNext($array)){ reset($array); @@ -19,7 +19,7 @@ public static function advanceWrap(&$array) : array{ return $result; } - public static function regressWrap(&$array) : array{ + public static function regressWrap(array &$array) : array{ $return = [key($array), current($array)]; if(!self::hasPrev($array)){ end($array); @@ -37,7 +37,7 @@ public static function hasPrev(array $array) : bool{ return prev($array) !== false || key($array) !== null; } - public static function setPointerToValue(array &$array, $value) : void{ + public static function setPointerToValue(array &$array, mixed $value) : void{ reset($array); #var_dump($array,current($array),$value); while(current($array) !== $value && self::hasNext($array)) next($array); diff --git a/src/xenialdan/MagicWE2/selection/Selection.php b/src/xenialdan/MagicWE2/selection/Selection.php index 856e76c..d91d40a 100644 --- a/src/xenialdan/MagicWE2/selection/Selection.php +++ b/src/xenialdan/MagicWE2/selection/Selection.php @@ -200,7 +200,7 @@ public function setShape(Shape $shape) : void{ // $manager = $this->getIterator()->getManager(); // if($manager instanceof AsyncWorld) $manager->copyChunks($this); }catch(RuntimeException | SelectionException $e){ - Loader::getInstance()->getLogger()->debug($e); + Loader::getInstance()->getLogger()->debug($e->getMessage()); } } @@ -220,7 +220,7 @@ public function isValid() : bool{ $this->getPos1(); $this->getPos2(); }catch(Exception $e){ - Loader::getInstance()->getLogger()->debug($e); + Loader::getInstance()->getLogger()->debug($e->getMessage()); return false; } return true; diff --git a/src/xenialdan/MagicWE2/session/data/Asset.php b/src/xenialdan/MagicWE2/session/data/Asset.php index 6e3c330..3a20edc 100644 --- a/src/xenialdan/MagicWE2/session/data/Asset.php +++ b/src/xenialdan/MagicWE2/session/data/Asset.php @@ -66,8 +66,8 @@ public function __construct(string $filename, Schematic|SingleClipboard|MCStruct public function getSize(): Vector3 { - if ($this->structure instanceof Schematic) return new Vector3($this->structure->getWidth(), $this->structure->getHeight(), $this->structure->getLength()); - if ($this->structure instanceof MCStructure) return $this->structure->getSize(); + if($this->structure instanceof Schematic) return new Vector3($this->structure->getWidth(), $this->structure->getHeight(), $this->structure->getLength()); + if($this->structure instanceof MCStructure) return new Vector3($this->structure->getSize()->getX(), $this->structure->getSize()->getY(), $this->structure->getSize()->getZ()); else return new Vector3($this->structure->selection->getSizeX(), $this->structure->selection->getSizeY(), $this->structure->selection->getSizeZ()); //throw new Exception("Unknown structure type"); } @@ -81,8 +81,8 @@ public function getTotalCount(): int public function getOrigin(): Vector3 { - if ($this->structure instanceof Schematic) return new Vector3(0, 0, 0); - if ($this->structure instanceof MCStructure) return $this->structure->getStructureWorldOrigin(); + if($this->structure instanceof Schematic) return new Vector3(0, 0, 0); + if($this->structure instanceof MCStructure) return new Vector3($this->structure->getStructureWorldOrigin()->getX(), $this->structure->getStructureWorldOrigin()->getY(), $this->structure->getStructureWorldOrigin()->getZ()); else return $this->structure->position; //throw new Exception("Unknown structure type"); } diff --git a/src/xenialdan/MagicWE2/task/AsyncRevertTask.php b/src/xenialdan/MagicWE2/task/AsyncRevertTask.php index cc746c5..5793bb4 100644 --- a/src/xenialdan/MagicWE2/task/AsyncRevertTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncRevertTask.php @@ -92,7 +92,7 @@ private function undoChunks(AsyncWorld &$manager, RevertClipboard $clipboard) : //$block is "data" array foreach($clipboard->blocksAfter as $block){ $block = self::singleDataToBlock($block);//turn data into real block - $original = $manager->getBlockAt($block->getPosition()->x, $block->getPosition()->y, $block->getPosition()->z); + $original = $manager->getBlockAt($block->getPosition()->getFloorX(), $block->getPosition()->getFloorY(), $block->getPosition()->getFloorZ()); yield self::singleBlockToData($original, $block->getPosition()); $manager->setBlockAt($block->getPosition()->getFloorX(), $block->getPosition()->getFloorY(), $block->getPosition()->getFloorZ(), $block); $changed++; @@ -115,7 +115,7 @@ private function redoChunks(AsyncWorld &$manager, RevertClipboard $clipboard) : //$block is "data" array foreach($clipboard->blocksAfter as $block){ $block = self::singleDataToBlock($block);//turn data into real block - $original = $manager->getBlockAt($block->getPosition()->x, $block->getPosition()->y, $block->getPosition()->z); + $original = $manager->getBlockAt($block->getPosition()->getFloorX(), $block->getPosition()->getFloorY(), $block->getPosition()->getFloorZ()); yield self::singleBlockToData($original, $block->getPosition()); $manager->setBlockAt($block->getPosition()->getFloorX(), $block->getPosition()->getFloorY(), $block->getPosition()->getFloorZ(), $block); $changed++; diff --git a/src/xenialdan/MagicWE2/tool/Debug.php b/src/xenialdan/MagicWE2/tool/Debug.php index 3c5a2ae..a7c2bd3 100644 --- a/src/xenialdan/MagicWE2/tool/Debug.php +++ b/src/xenialdan/MagicWE2/tool/Debug.php @@ -96,7 +96,7 @@ public function toItem(Language $lang) : Item{ public function getCurrentState(string $blockIdentifier) : ?string{ if(array_key_exists($blockIdentifier, $this->states)){ - return key($this->states[$blockIdentifier]); + return (string) ($this->states[$blockIdentifier]); } return null; } @@ -117,7 +117,7 @@ public function getName() : string{ * @throws InvalidArgumentException * @throws AssumptionFailedError */ - public function useSecondary(UserSession $session, Block $block){ + public function useSecondary(UserSession $session, Block $block) : void{ //cycle values /** @var BlockStatesParser $blockStatesParser */ $blockStatesParser = BlockStatesParser::getInstance(); @@ -155,7 +155,7 @@ public function useSecondary(UserSession $session, Block $block){ } } - public function usePrimary(UserSession $session, Block $block){ + public function usePrimary(UserSession $session, Block $block) : void{ //cycle states /** @var BlockStatesParser $blockStatesParser */ $blockStatesParser = BlockStatesParser::getInstance(); From 7e7e523f796d6d98660514fc2399dad85585ad25 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Fri, 14 Oct 2022 23:22:15 +0200 Subject: [PATCH 23/24] Implement API::rotateStructure() TODO: improve speeds --- src/xenialdan/MagicWE2/API.php | 47 ++++++++++++++++++- .../MagicWE2/task/AsyncPasteAssetTask.php | 1 + 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/xenialdan/MagicWE2/API.php b/src/xenialdan/MagicWE2/API.php index b20017f..b36c782 100644 --- a/src/xenialdan/MagicWE2/API.php +++ b/src/xenialdan/MagicWE2/API.php @@ -14,6 +14,7 @@ use pocketmine\nbt\NoSuchTagException; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\UnexpectedTagTypeException; +use pocketmine\network\mcpe\protocol\types\BlockPosition; use pocketmine\player\Player; use pocketmine\Server; use pocketmine\utils\AssumptionFailedError; @@ -26,6 +27,7 @@ use xenialdan\libblockstate\BlockStatesParser; use xenialdan\libblockstate\exception\BlockQueryParsingFailedException; use xenialdan\libstructure\format\MCStructure; +use xenialdan\libstructure\format\MCStructureData; use xenialdan\MagicWE2\clipboard\Clipboard; use xenialdan\MagicWE2\clipboard\SingleClipboard; use xenialdan\MagicWE2\exception\BlockQueryAlreadyParsedException; @@ -50,7 +52,9 @@ use xenialdan\MagicWE2\task\AsyncPasteTask; use xenialdan\MagicWE2\task\AsyncReplaceTask; use xenialdan\MagicWE2\tool\Brush; +use function array_keys; use function str_replace; +use function var_dump; class API { @@ -591,8 +595,47 @@ private static function rotateSchematic(Schematic $structure, int $rotation, arr } private static function rotateStructure(MCStructure $structure, int $rotation, array &$errors = []) : MCStructure{ - //TODO this is not yet implemented due to lack of support for creating new MCStructures in libstructure - return $structure; + if($rotation % 90 !== 0){ + throw new InvalidArgumentException("Rotation must be divisible by 90"); + } + $rotation = self::positiveModulo($rotation, 360); + if($rotation === 0) return $structure; + + $shape = new Cuboid(Vector3::zero(), $structure->getSize()->getX(), $structure->getSize()->getY(), $structure->getSize()->getZ()); + $shape = $shape->rotate($rotation); + var_dump("TILES BEFORE ROTATE", array_keys($structure->getBlockEntitiesRaw())); + $new = new MCStructure(MCStructureData::fromStructure($structure), new BlockPosition($shape->width, $shape->height, $shape->depth), $structure->origin); + var_dump("TILES AFTER ROTATE", array_keys($new->getBlockEntitiesRaw())); + + + //$x = $y = $z = null; + foreach($structure->blocks() as $entry){ + if($entry === null) continue; + //TODO set block to rotated blockstate + $state = BlockStatesParser::getInstance()->getFromBlock($entry); + try{ + $stateRotated = self::rotateBlockState($state, $rotation); + [$x, $y, $z] = [$entry->getPosition()->getX(), $entry->getPosition()->getY(), $entry->getPosition()->getZ()]; + + $newV3 = match ($rotation)//TODO figure out how to avoid new Vector3 objects + { + RotateAction::ROTATE_90 => new Vector3($structure->getSize()->getZ() - $z - 1, $y, $x), + RotateAction::ROTATE_180 => new Vector3($structure->getSize()->getX() - $x - 1, $y, $structure->getSize()->getZ() - $z - 1),//TODO is this flip instead of rotate? + RotateAction::ROTATE_270 => new Vector3($z, $y, $structure->getSize()->getX() - $x - 1), + default => new Vector3($x, $y, $z) + }; + //TODO move origin of structure + if(($tile = $structure->translateBlockEntity($entry->getPosition(), new Vector3($structure->origin->getX(), $structure->origin->getY(), $structure->origin->getZ())) !== null)){ + var_dump($tile); + } + $new->set($newV3->getX(), $newV3->getY(), $newV3->getZ(), $stateRotated); + }catch(BlockQueryParsingFailedException | NoSuchTagException | UnexpectedTagTypeException $e){ + $errors[] = $e->getMessage();//TODO implement error printing, for now silently continue + continue; + } + } + $new->check(); + return $new->parse(); } /** diff --git a/src/xenialdan/MagicWE2/task/AsyncPasteAssetTask.php b/src/xenialdan/MagicWE2/task/AsyncPasteAssetTask.php index d463b54..747ff8c 100644 --- a/src/xenialdan/MagicWE2/task/AsyncPasteAssetTask.php +++ b/src/xenialdan/MagicWE2/task/AsyncPasteAssetTask.php @@ -110,6 +110,7 @@ private function execute(AsyncWorld $manager, Asset $asset, ?int &$changed): Gen if ($structure instanceof MCStructure) { /** @var Block $block */ foreach ($structure->blocks() as $block) {// [0,0,0 -> sizex,sizey,sizez] + if($block === null) continue; #var_dump($block->getPosition()->asVector3(), $this->pasteVector, $this->selection); $pos = $block->getPosition()->addVector($this->target)->subtract($asset->getSize()->getX() / 2, 0, $asset->getSize()->getZ() / 2); [$block->getPosition()->x, $block->getPosition()->y, $block->getPosition()->z] = [$x, $y, $z] = [$pos->getX(), $pos->getY(), $pos->getZ()]; From a95bef47abca2a1b68073d0f34758d59b275d15e Mon Sep 17 00:00:00 2001 From: XenialDan Date: Fri, 14 Oct 2022 23:34:06 +0200 Subject: [PATCH 24/24] Bump required libstructure version (0.3.0 rewrite) --- .poggit.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.poggit.yml b/.poggit.yml index 0cd4d27..b3d168d 100644 --- a/.poggit.yml +++ b/.poggit.yml @@ -25,8 +25,8 @@ projects: version: ^4.3.4 branch: "4.0" - src: thebigsmilexd/libstructure/libstructure - version: ^0.2.0 - branch: feature/filter-palette + version: ^0.3.0 + branch: rewrite - src: thebigsmilexd/libblockstate/libblockstate version: ^0.1.2 branch: master