From e3ef7b2ba7adde6a8c91916f3b733005f45fdc3e Mon Sep 17 00:00:00 2001 From: XenialDan Date: Fri, 4 Dec 2020 06:29:10 +0100 Subject: [PATCH] Fix #214 (Shapes may have an additional block) i.e. diameter 17 placed on 24:24 would go from 16:16 to 32:32, right into the next chunk TODO: i noticed that some calculations are off (i.e. Sphere total count) --- .../MagicWE2/selection/shape/Cone.php | 4 +- .../MagicWE2/selection/shape/Cube.php | 26 ++-- .../MagicWE2/selection/shape/Cuboid.php | 28 ++-- .../MagicWE2/selection/shape/Custom.php | 131 +++++++++--------- .../MagicWE2/selection/shape/Cylinder.php | 26 ++-- .../MagicWE2/selection/shape/Ellipsoid.php | 26 ++-- .../MagicWE2/selection/shape/Pyramid.php | 26 ++-- .../MagicWE2/selection/shape/Sphere.php | 100 ++++++------- .../MagicWE2/session/UserSession.php | 2 +- 9 files changed, 184 insertions(+), 185 deletions(-) diff --git a/src/xenialdan/MagicWE2/selection/shape/Cone.php b/src/xenialdan/MagicWE2/selection/shape/Cone.php index 533c04db..8814e408 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Cone.php +++ b/src/xenialdan/MagicWE2/selection/shape/Cone.php @@ -108,9 +108,9 @@ public function getLayer($manager, int $flags = API::FLAG_BASE): Generator public function getTouchedChunks($manager): array {//TODO optimize to remove "corner" chunks $this->validateChunkManager($manager); - $maxX = $this->getMaxVec3()->x >> 4; + $maxX = ($this->getMaxVec3()->x + 1) >> 4; $minX = $this->getMinVec3()->x >> 4; - $maxZ = $this->getMaxVec3()->z >> 4; + $maxZ = ($this->getMaxVec3()->z + 1) >> 4; $minZ = $this->getMinVec3()->z >> 4; $touchedChunks = []; for ($x = $minX; $x <= $maxX; $x++) { diff --git a/src/xenialdan/MagicWE2/selection/shape/Cube.php b/src/xenialdan/MagicWE2/selection/shape/Cube.php index 7a2a6329..640d9ceb 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Cube.php +++ b/src/xenialdan/MagicWE2/selection/shape/Cube.php @@ -81,21 +81,21 @@ public function getLayer($manager, int $flags = API::FLAG_BASE): Generator */ public function getTouchedChunks($manager): array { - $this->validateChunkManager($manager); - $maxX = $this->getMaxVec3()->x >> 4; - $minX = $this->getMinVec3()->x >> 4; - $maxZ = $this->getMaxVec3()->z >> 4; - $minZ = $this->getMinVec3()->z >> 4; - $touchedChunks = []; - for ($x = $minX; $x <= $maxX; $x++) { - for ($z = $minZ; $z <= $maxZ; $z++) { - $chunk = $manager->getChunk($x, $z); - if ($chunk === null) { - continue; - } + $this->validateChunkManager($manager); + $maxX = ($this->getMaxVec3()->x + 1) >> 4; + $minX = $this->getMinVec3()->x >> 4; + $maxZ = ($this->getMaxVec3()->z + 1) >> 4; + $minZ = $this->getMinVec3()->z >> 4; + $touchedChunks = []; + for ($x = $minX; $x <= $maxX; $x++) { + for ($z = $minZ; $z <= $maxZ; $z++) { + $chunk = $manager->getChunk($x, $z); + if ($chunk === null) { + continue; + } print "Touched Chunk at: $x:$z" . PHP_EOL; $touchedChunks[World::chunkHash($x, $z)] = FastChunkSerializer::serialize($chunk); - } + } } print "Touched chunks count: " . count($touchedChunks) . PHP_EOL; return $touchedChunks; diff --git a/src/xenialdan/MagicWE2/selection/shape/Cuboid.php b/src/xenialdan/MagicWE2/selection/shape/Cuboid.php index 5521536c..4f04b235 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Cuboid.php +++ b/src/xenialdan/MagicWE2/selection/shape/Cuboid.php @@ -103,21 +103,21 @@ public function getLayer($manager, int $flags = API::FLAG_BASE): Generator */ public function getTouchedChunks($manager): array { - $this->validateChunkManager($manager); - $maxX = $this->getMaxVec3()->x >> 4; - $minX = $this->getMinVec3()->x >> 4; - $maxZ = $this->getMaxVec3()->z >> 4; - $minZ = $this->getMinVec3()->z >> 4; - $touchedChunks = []; - for ($x = $minX; $x <= $maxX; $x++) { - for ($z = $minZ; $z <= $maxZ; $z++) { - $chunk = $manager->getChunk($x, $z); - if ($chunk === null) { - continue; - } + $this->validateChunkManager($manager); + $maxX = ($this->getMaxVec3()->x + 1) >> 4; + $minX = $this->getMinVec3()->x >> 4; + $maxZ = ($this->getMaxVec3()->z + 1) >> 4; + $minZ = $this->getMinVec3()->z >> 4; + $touchedChunks = []; + for ($x = $minX; $x <= $maxX; $x++) { + for ($z = $minZ; $z <= $maxZ; $z++) { + $chunk = $manager->getChunk($x, $z); + if ($chunk === null) { + continue; + } $touchedChunks[World::chunkHash($x, $z)] = FastChunkSerializer::serialize($chunk); - } - } + } + } return $touchedChunks; } diff --git a/src/xenialdan/MagicWE2/selection/shape/Custom.php b/src/xenialdan/MagicWE2/selection/shape/Custom.php index 92af1ce0..90345fdb 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Custom.php +++ b/src/xenialdan/MagicWE2/selection/shape/Custom.php @@ -27,9 +27,9 @@ public function __construct(Vector3 $pasteVector, array $positions) { $this->pasteVector = $pasteVector; $this->positions = $positions; - } + } - /** + /** * Returns the blocks by their actual position * @param World|AsyncChunkManager $manager The world or AsyncChunkManager * @param Block[] $filterblocks If not empty, applying a filter on the block list @@ -37,14 +37,14 @@ public function __construct(Vector3 $pasteVector, array $positions) * @return Generator|Block[] * @throws Exception */ - public function getBlocks($manager, array $filterblocks = [], int $flags = API::FLAG_BASE): Generator - { - $this->validateChunkManager($manager); - foreach ($this->positions as $position) { + public function getBlocks($manager, array $filterblocks = [], int $flags = API::FLAG_BASE): Generator + { + $this->validateChunkManager($manager); + foreach ($this->positions as $position) { //TODO filterblocks yield API::setComponents($manager->getBlockAt($position->getFloorX(), $position->getFloorY(), $position->getFloorZ()), (int)$position->x, (int)$position->y, (int)$position->z); } - } + } /** * Returns a flat layer of all included x z positions in selection @@ -53,69 +53,68 @@ public function getBlocks($manager, array $filterblocks = [], int $flags = API:: * @return Generator|Vector2[] * @throws Exception */ - public function getLayer($manager, int $flags = API::FLAG_BASE): Generator - { - $this->validateChunkManager($manager); - /* Mapping: $walked[$hash]=true */ - $walked = []; - foreach ($this->positions as $position) { - $hash = World::chunkHash($position->getFloorX(), $position->getFloorZ()); - if (isset($walked[$hash])) continue; - $walked[$hash] = true; - yield new Vector2($position->x, $position->z); - } - } + public function getLayer($manager, int $flags = API::FLAG_BASE): Generator + { + $this->validateChunkManager($manager); + /* Mapping: $walked[$hash]=true */ + $walked = []; + foreach ($this->positions as $position) { + $hash = World::chunkHash($position->getFloorX(), $position->getFloorZ()); + if (isset($walked[$hash])) continue; + $walked[$hash] = true; + yield new Vector2($position->x, $position->z); + } + } - /** - * @param World|AsyncChunkManager $manager - * @return string[] fastSerialized chunks - * @throws Exception - */ - public function getTouchedChunks($manager): array - { - $this->validateChunkManager($manager); - $touchedChunks = []; - foreach ($this->getLayer($manager) as $vector2) { - $x = $vector2->getFloorX() >> 4; - $z = $vector2->getFloorY() >> 4; - $chunk = $manager->getChunk($x, $z); - if ($chunk === null) { - continue; - } + /** + * @param World|AsyncChunkManager $manager + * @return string[] fastSerialized chunks + * @throws Exception + */ + public function getTouchedChunks($manager): array + { + $this->validateChunkManager($manager); + $touchedChunks = []; + foreach ($this->getLayer($manager) as $vector2) { + $x = $vector2->getFloorX() >> 4; + $z = $vector2->getFloorY() >> 4; + if (isset($touchedChunks[World::chunkHash($x, $z)]) || ($chunk = $manager->getChunk($x, $z)) === null) { + continue; + } print "Touched Chunk at: $x:$z" . PHP_EOL; $touchedChunks[World::chunkHash($x, $z)] = FastChunkSerializer::serialize($chunk); - } - print "Touched chunks count: " . count($touchedChunks) . PHP_EOL; - return $touchedChunks; - } + } + print "Touched chunks count: " . count($touchedChunks) . PHP_EOL; + return $touchedChunks; + } - public function getAABB(): AxisAlignedBB - { - $minX = $maxX = $minY = $maxY = $minZ = $maxZ = null; - foreach ($this->positions as $position) { - if (is_null($minX)) { - $minX = $maxX = $position->x; - $minY = $maxY = $position->y; - $minZ = $maxZ = $position->z; - continue; - } - $minX = min($minX, $position->x); - $minY = min($minY, $position->y); - $minZ = min($minZ, $position->z); - $maxX = max($maxX, $position->x); - $maxY = max($maxY, $position->y); - $maxZ = max($maxZ, $position->z); - } - return new AxisAlignedBB($minX, $minY, $minZ, $maxX, $maxY, $maxZ); - } + public function getAABB(): AxisAlignedBB + { + $minX = $maxX = $minY = $maxY = $minZ = $maxZ = null; + foreach ($this->positions as $position) { + if (is_null($minX)) { + $minX = $maxX = $position->x; + $minY = $maxY = $position->y; + $minZ = $maxZ = $position->z; + continue; + } + $minX = min($minX, $position->x); + $minY = min($minY, $position->y); + $minZ = min($minZ, $position->z); + $maxX = max($maxX, $position->x); + $maxY = max($maxY, $position->y); + $maxZ = max($maxZ, $position->z); + } + return new AxisAlignedBB($minX, $minY, $minZ, $maxX, $maxY, $maxZ); + } - public function getTotalCount(): int - { - return count($this->positions); - } + public function getTotalCount(): int + { + return count($this->positions); + } - public static function getName(): string - { - return "Custom"; - } + public static function getName(): string + { + return "Custom"; + } } \ No newline at end of file diff --git a/src/xenialdan/MagicWE2/selection/shape/Cylinder.php b/src/xenialdan/MagicWE2/selection/shape/Cylinder.php index 5157bde0..8a97dc8c 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Cylinder.php +++ b/src/xenialdan/MagicWE2/selection/shape/Cylinder.php @@ -98,21 +98,21 @@ public function getLayer($manager, int $flags = API::FLAG_BASE): Generator */ public function getTouchedChunks($manager): array {//TODO optimize to remove "corner" chunks - $this->validateChunkManager($manager); - $maxX = $this->getMaxVec3()->x >> 4; - $minX = $this->getMinVec3()->x >> 4; - $maxZ = $this->getMaxVec3()->z >> 4; - $minZ = $this->getMinVec3()->z >> 4; - $touchedChunks = []; - for ($x = $minX; $x <= $maxX; $x++) { - for ($z = $minZ; $z <= $maxZ; $z++) { - $chunk = $manager->getChunk($x, $z); - if ($chunk === null) { - continue; - } + $this->validateChunkManager($manager); + $maxX = ($this->getMaxVec3()->x + 1) >> 4; + $minX = $this->getMinVec3()->x >> 4; + $maxZ = ($this->getMaxVec3()->z + 1) >> 4; + $minZ = $this->getMinVec3()->z >> 4; + $touchedChunks = []; + for ($x = $minX; $x <= $maxX; $x++) { + for ($z = $minZ; $z <= $maxZ; $z++) { + $chunk = $manager->getChunk($x, $z); + if ($chunk === null) { + continue; + } print "Touched Chunk at: $x:$z" . PHP_EOL; $touchedChunks[World::chunkHash($x, $z)] = FastChunkSerializer::serialize($chunk); - } + } } print "Touched chunks count: " . count($touchedChunks) . PHP_EOL; return $touchedChunks; diff --git a/src/xenialdan/MagicWE2/selection/shape/Ellipsoid.php b/src/xenialdan/MagicWE2/selection/shape/Ellipsoid.php index 4a4c05a6..b2df0172 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Ellipsoid.php +++ b/src/xenialdan/MagicWE2/selection/shape/Ellipsoid.php @@ -126,21 +126,21 @@ public function getLayer($manager, int $flags = API::FLAG_BASE): Generator */ public function getTouchedChunks($manager): array {//TODO optimize to remove "corner" chunks - $this->validateChunkManager($manager); - $maxX = $this->getMaxVec3()->x >> 4; - $minX = $this->getMinVec3()->x >> 4; - $maxZ = $this->getMaxVec3()->z >> 4; - $minZ = $this->getMinVec3()->z >> 4; - $touchedChunks = []; - for ($x = $minX - 1; $x <= $maxX + 1; $x++) { - for ($z = $minZ - 1; $z <= $maxZ + 1; $z++) { - $chunk = $manager->getChunk($x, $z); - if ($chunk === null) { - continue; - } + $this->validateChunkManager($manager); + $maxX = ($this->getMaxVec3()->x + 1) >> 4; + $minX = $this->getMinVec3()->x >> 4; + $maxZ = ($this->getMaxVec3()->z + 1) >> 4; + $minZ = $this->getMinVec3()->z >> 4; + $touchedChunks = []; + for ($x = $minX - 1; $x <= $maxX + 1; $x++) { + for ($z = $minZ - 1; $z <= $maxZ + 1; $z++) { + $chunk = $manager->getChunk($x, $z); + if ($chunk === null) { + continue; + } print "Touched Chunk at: $x:$z" . PHP_EOL; $touchedChunks[World::chunkHash($x, $z)] = FastChunkSerializer::serialize($chunk); - } + } } print "Touched chunks count: " . count($touchedChunks) . PHP_EOL; return $touchedChunks; diff --git a/src/xenialdan/MagicWE2/selection/shape/Pyramid.php b/src/xenialdan/MagicWE2/selection/shape/Pyramid.php index dc130a21..7c1d6b63 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Pyramid.php +++ b/src/xenialdan/MagicWE2/selection/shape/Pyramid.php @@ -114,21 +114,21 @@ public function getLayer($manager, int $flags = API::FLAG_BASE): Generator */ public function getTouchedChunks($manager): array {//TODO optimize to remove "corner" chunks - $this->validateChunkManager($manager); - $maxX = $this->getMaxVec3()->x >> 4; - $minX = $this->getMinVec3()->x >> 4; - $maxZ = $this->getMaxVec3()->z >> 4; - $minZ = $this->getMinVec3()->z >> 4; - $touchedChunks = []; - for ($x = $minX; $x <= $maxX; $x++) { - for ($z = $minZ; $z <= $maxZ; $z++) { - $chunk = $manager->getChunk($x, $z); - if ($chunk === null) { - continue; - } + $this->validateChunkManager($manager); + $maxX = ($this->getMaxVec3()->x + 1) >> 4; + $minX = $this->getMinVec3()->x >> 4; + $maxZ = ($this->getMaxVec3()->z + 1) >> 4; + $minZ = $this->getMinVec3()->z >> 4; + $touchedChunks = []; + for ($x = $minX; $x <= $maxX; $x++) { + for ($z = $minZ; $z <= $maxZ; $z++) { + $chunk = $manager->getChunk($x, $z); + if ($chunk === null) { + continue; + } print "Touched Chunk at: $x:$z" . PHP_EOL; $touchedChunks[World::chunkHash($x, $z)] = FastChunkSerializer::serialize($chunk); - } + } } print "Touched chunks count: " . count($touchedChunks) . PHP_EOL; return $touchedChunks; diff --git a/src/xenialdan/MagicWE2/selection/shape/Sphere.php b/src/xenialdan/MagicWE2/selection/shape/Sphere.php index 991a8962..eaa51370 100644 --- a/src/xenialdan/MagicWE2/selection/shape/Sphere.php +++ b/src/xenialdan/MagicWE2/selection/shape/Sphere.php @@ -28,9 +28,9 @@ public function __construct(Vector3 $pasteVector, int $diameter) { $this->pasteVector = $pasteVector; $this->diameter = $diameter; - } + } - /** + /** * Returns the blocks by their actual position * @param World|AsyncChunkManager $manager The world or AsyncChunkManager * @param Block[] $filterblocks If not empty, applying a filter on the block list @@ -38,8 +38,8 @@ public function __construct(Vector3 $pasteVector, int $diameter) * @return Generator|Block[] * @throws Exception */ - public function getBlocks($manager, array $filterblocks = [], int $flags = API::FLAG_BASE): Generator - { + public function getBlocks($manager, array $filterblocks = [], int $flags = API::FLAG_BASE): Generator + { $this->validateChunkManager($manager); 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++) { @@ -60,9 +60,9 @@ public function getBlocks($manager, array $filterblocks = [], int $flags = API:: } } } - } - } - } + } + } + } /** * Returns a flat layer of all included x z positions in selection @@ -71,7 +71,7 @@ public function getBlocks($manager, array $filterblocks = [], int $flags = API:: * @return Generator|Vector2[] * @throws Exception */ - public function getLayer($manager, int $flags = API::FLAG_BASE): Generator + public function getLayer($manager, int $flags = API::FLAG_BASE): Generator { $this->validateChunkManager($manager); $centerVec2 = new Vector2($this->getPasteVector()->getX(), $this->getPasteVector()->getZ()); @@ -85,52 +85,52 @@ public function getLayer($manager, int $flags = API::FLAG_BASE): Generator } } - /** - * @param World|AsyncChunkManager $manager - * @return string[] fastSerialized chunks - * @throws Exception - */ - public function getTouchedChunks($manager): array - {//TODO optimize to remove "corner" chunks - $this->validateChunkManager($manager); - $maxX = $this->getMaxVec3()->x >> 4; - $minX = $this->getMinVec3()->x >> 4; - $maxZ = $this->getMaxVec3()->z >> 4; - $minZ = $this->getMinVec3()->z >> 4; - $touchedChunks = []; - for ($x = $minX; $x <= $maxX; $x++) { - for ($z = $minZ; $z <= $maxZ; $z++) { - $chunk = $manager->getChunk($x, $z); - if ($chunk === null) { - continue; - } + /** + * @param World|AsyncChunkManager $manager + * @return string[] fastSerialized chunks + * @throws Exception + */ + public function getTouchedChunks($manager): array + {//TODO optimize to remove "corner" chunks + $this->validateChunkManager($manager); + $maxX = ($this->getMaxVec3()->x + 1) >> 4; + $minX = $this->getMinVec3()->x >> 4; + $maxZ = ($this->getMaxVec3()->z + 1) >> 4; + $minZ = $this->getMinVec3()->z >> 4; + $touchedChunks = []; + for ($x = $minX; $x <= $maxX; $x++) { + for ($z = $minZ; $z <= $maxZ; $z++) { + $chunk = $manager->getChunk($x, $z); + if ($chunk === null) { + continue; + } print "Touched Chunk at: $x:$z" . PHP_EOL; $touchedChunks[World::chunkHash($x, $z)] = FastChunkSerializer::serialize($chunk); - } - } - print "Touched chunks count: " . count($touchedChunks) . PHP_EOL; - return $touchedChunks; - } + } + } + print "Touched chunks count: " . count($touchedChunks) . PHP_EOL; + return $touchedChunks; + } - public function getAABB(): AxisAlignedBB - { - return new AxisAlignedBB( - floor($this->pasteVector->x - $this->diameter / 2), - $this->pasteVector->y, - floor($this->pasteVector->z - $this->diameter / 2), - -1 + floor($this->pasteVector->x - $this->diameter / 2) + $this->diameter, - -1 + $this->pasteVector->y + $this->diameter, - -1 + floor($this->pasteVector->z - $this->diameter / 2) + $this->diameter - ); - } + public function getAABB(): AxisAlignedBB + { + return new AxisAlignedBB( + floor($this->pasteVector->x - $this->diameter / 2), + $this->pasteVector->y, + floor($this->pasteVector->z - $this->diameter / 2), + -1 + floor($this->pasteVector->x - $this->diameter / 2) + $this->diameter, + -1 + $this->pasteVector->y + $this->diameter, + -1 + floor($this->pasteVector->z - $this->diameter / 2) + $this->diameter + ); + } - public function getTotalCount(): int - { + public function getTotalCount(): int + { return (int)ceil((4 / 3) * M_PI * (($this->diameter / 2) ** 3)); - } + } - public static function getName(): string - { - return "Sphere"; - } + public static function getName(): string + { + return "Sphere"; + } } \ No newline at end of file diff --git a/src/xenialdan/MagicWE2/session/UserSession.php b/src/xenialdan/MagicWE2/session/UserSession.php index 23a1b236..ffed9bd0 100644 --- a/src/xenialdan/MagicWE2/session/UserSession.php +++ b/src/xenialdan/MagicWE2/session/UserSession.php @@ -227,7 +227,7 @@ public function getBrushFromItem(Item $item): Brush throw new BrushException("Brush can not be restored - version mismatch"); } /** @var BrushProperties $properties */ - $properties = json_decode($entry->getString("properties"), true, 512, JSON_THROW_ON_ERROR); + $properties = json_decode($entry->getString("properties"), false, 512, JSON_THROW_ON_ERROR); $uuid = UUID::fromString($properties->uuid); $brush = $this->getBrush($uuid); if ($brush instanceof Brush) {