From 1c7b1e9e5d42bfd8d034ee225a91c173e6e14fe9 Mon Sep 17 00:00:00 2001 From: ShockedPlot7560 <66992287+ShockedPlot7560@users.noreply.github.com> Date: Wed, 28 Sep 2022 17:38:24 +0200 Subject: [PATCH 1/6] Fix sugarcane behaviour on fertilizers (#4930) --- src/block/Sugarcane.php | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/block/Sugarcane.php b/src/block/Sugarcane.php index fe1935c8b..80c758504 100644 --- a/src/block/Sugarcane.php +++ b/src/block/Sugarcane.php @@ -31,6 +31,7 @@ use pocketmine\math\Facing; use pocketmine\math\Vector3; use pocketmine\player\Player; use pocketmine\world\BlockTransaction; +use pocketmine\world\Position; class Sugarcane extends Flowable{ public const MAX_AGE = 15; @@ -49,14 +50,23 @@ class Sugarcane extends Flowable{ return 0b1111; } - private function grow() : bool{ - $grew = false; + private function seekToBottom() : Position{ $world = $this->position->getWorld(); + $bottom = $this->position; + while(($next = $world->getBlock($bottom->down()))->isSameType($this)){ + $bottom = $next->position; + } + return $bottom; + } + + private function grow(Position $pos) : bool{ + $grew = false; + $world = $pos->getWorld(); for($y = 1; $y < 3; ++$y){ - if(!$world->isInWorld($this->position->x, $this->position->y + $y, $this->position->z)){ + if(!$world->isInWorld($pos->x, $pos->y + $y, $pos->z)){ break; } - $b = $world->getBlockAt($this->position->x, $this->position->y + $y, $this->position->z); + $b = $world->getBlockAt($pos->x, $pos->y + $y, $pos->z); if($b->getId() === BlockLegacyIds::AIR){ $ev = new BlockGrowEvent($b, VanillaBlocks::SUGARCANE()); $ev->call(); @@ -65,12 +75,12 @@ class Sugarcane extends Flowable{ } $world->setBlock($b->position, $ev->getNewState()); $grew = true; - }else{ + }elseif(!$b->isSameType($this)){ break; } } $this->age = 0; - $world->setBlock($this->position, $this); + $world->setBlock($pos, $this); return $grew; } @@ -87,7 +97,7 @@ class Sugarcane extends Flowable{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ if($item instanceof Fertilizer){ - if(!$this->getSide(Facing::DOWN)->isSameType($this) && $this->grow()){ + if($this->grow($this->seekToBottom())){ $item->pop(); } @@ -111,7 +121,7 @@ class Sugarcane extends Flowable{ public function onRandomTick() : void{ if(!$this->getSide(Facing::DOWN)->isSameType($this)){ if($this->age === self::MAX_AGE){ - $this->grow(); + $this->grow($this->position); }else{ ++$this->age; $this->position->getWorld()->setBlock($this->position, $this); From b21cd82e9456672a331f4187c2bcb66d3c6e6fa1 Mon Sep 17 00:00:00 2001 From: BrandPVP <114182697+BrandPVP@users.noreply.github.com> Date: Wed, 28 Sep 2022 19:27:33 +0300 Subject: [PATCH 2/6] Allow specifying a key for encrypted resource packs (#5297) --- resources/resource_packs.yml | 1 + .../handler/ResourcePacksPacketHandler.php | 14 ++++++++-- src/resourcepacks/ResourcePackManager.php | 26 +++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/resources/resource_packs.yml b/resources/resource_packs.yml index 39677852d..f236117d5 100644 --- a/resources/resource_packs.yml +++ b/resources/resource_packs.yml @@ -10,3 +10,4 @@ resource_stack: # - natural.zip # - vanilla.zip #If you want to force clients to use vanilla resources, you must place a vanilla resource pack in your resources folder and add it to the stack here. + #To specify a resource encryption key, put the key in the .key file alongside the resource pack. Example: vanilla.zip.key diff --git a/src/network/mcpe/handler/ResourcePacksPacketHandler.php b/src/network/mcpe/handler/ResourcePacksPacketHandler.php index a7c603ceb..d1ba85724 100644 --- a/src/network/mcpe/handler/ResourcePacksPacketHandler.php +++ b/src/network/mcpe/handler/ResourcePacksPacketHandler.php @@ -65,9 +65,19 @@ class ResourcePacksPacketHandler extends PacketHandler{ ){} public function setUp() : void{ - $resourcePackEntries = array_map(static function(ResourcePack $pack) : ResourcePackInfoEntry{ + $resourcePackEntries = array_map(function(ResourcePack $pack) : ResourcePackInfoEntry{ //TODO: more stuff - return new ResourcePackInfoEntry($pack->getPackId(), $pack->getPackVersion(), $pack->getPackSize(), "", "", "", false); + $encryptionKey = $this->resourcePackManager->getPackEncryptionKey($pack->getPackId()); + + return new ResourcePackInfoEntry( + $pack->getPackId(), + $pack->getPackVersion(), + $pack->getPackSize(), + $encryptionKey ?? "", + "", + $pack->getPackId(), + false + ); }, $this->resourcePackManager->getResourceStack()); //TODO: support forcing server packs $this->session->sendDataPacket(ResourcePacksInfoPacket::create($resourcePackEntries, [], $this->resourcePackManager->resourcePacksRequired(), false, false)); diff --git a/src/resourcepacks/ResourcePackManager.php b/src/resourcepacks/ResourcePackManager.php index 4aaa9afc7..f037f52ff 100644 --- a/src/resourcepacks/ResourcePackManager.php +++ b/src/resourcepacks/ResourcePackManager.php @@ -23,12 +23,14 @@ declare(strict_types=1); namespace pocketmine\resourcepacks; +use pocketmine\errorhandler\ErrorToExceptionHandler; use pocketmine\utils\Config; use Webmozart\PathUtil\Path; use function array_keys; use function copy; use function count; use function file_exists; +use function file_get_contents; use function gettype; use function is_array; use function is_dir; @@ -49,6 +51,12 @@ class ResourcePackManager{ /** @var ResourcePack[] */ private array $uuidList = []; + /** + * @var string[] + * @phpstan-var array + */ + private array $encryptionKeys = []; + /** * @param string $path Path to resource-packs directory. */ @@ -106,6 +114,17 @@ class ResourcePackManager{ if($newPack instanceof ResourcePack){ $this->resourcePacks[] = $newPack; $this->uuidList[strtolower($newPack->getPackId())] = $newPack; + + $keyPath = Path::join($this->path, $pack . ".key"); + if(file_exists($keyPath)){ + try{ + $this->encryptionKeys[strtolower($newPack->getPackId())] = ErrorToExceptionHandler::trapAndRemoveFalse( + fn() => file_get_contents($keyPath) + ); + }catch(\ErrorException $e){ + throw new ResourcePackException("Could not read encryption key file: " . $e->getMessage(), 0, $e); + } + } }else{ throw new ResourcePackException("Format not recognized"); } @@ -153,4 +172,11 @@ class ResourcePackManager{ public function getPackIdList() : array{ return array_keys($this->uuidList); } + + /** + * Returns the key with which the pack was encrypted, or null if the pack has no key. + */ + public function getPackEncryptionKey(string $id) : ?string{ + return $this->encryptionKeys[strtolower($id)] ?? null; + } } From bda0ca23b497bcfae33de6adc0ef177db10dd7ce Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 28 Sep 2022 17:34:51 +0100 Subject: [PATCH 3/6] Living: deprecated hasLineOfSight() --- src/entity/Living.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/entity/Living.php b/src/entity/Living.php index 58b7c1791..890b6e740 100644 --- a/src/entity/Living.php +++ b/src/entity/Living.php @@ -294,6 +294,10 @@ abstract class Living extends Entity{ return $nbt; } + /** + * @deprecated This function always returns true, no matter whether the target is in the line of sight or not. + * @see VoxelRayTrace::inDirection() for a more generalized method of ray-tracing to a target. + */ public function hasLineOfSight(Entity $entity) : bool{ //TODO: head height return true; From d6bbf8217dfb47054e32acf689702a70c7d508d8 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 28 Sep 2022 20:57:17 +0100 Subject: [PATCH 4/6] ResourcePackManager: avoid repeated operation --- src/resourcepacks/ResourcePackManager.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/resourcepacks/ResourcePackManager.php b/src/resourcepacks/ResourcePackManager.php index f037f52ff..e6b37543a 100644 --- a/src/resourcepacks/ResourcePackManager.php +++ b/src/resourcepacks/ResourcePackManager.php @@ -113,12 +113,13 @@ class ResourcePackManager{ if($newPack instanceof ResourcePack){ $this->resourcePacks[] = $newPack; - $this->uuidList[strtolower($newPack->getPackId())] = $newPack; + $index = strtolower($newPack->getPackId()); + $this->uuidList[$index] = $newPack; $keyPath = Path::join($this->path, $pack . ".key"); if(file_exists($keyPath)){ try{ - $this->encryptionKeys[strtolower($newPack->getPackId())] = ErrorToExceptionHandler::trapAndRemoveFalse( + $this->encryptionKeys[$index] = ErrorToExceptionHandler::trapAndRemoveFalse( fn() => file_get_contents($keyPath) ); }catch(\ErrorException $e){ From 0c7f8470b945db3219428c807f186eec9f1aa503 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 28 Sep 2022 21:30:06 +0100 Subject: [PATCH 5/6] Avoid repeated strtolower usages in a couple of places --- src/command/SimpleCommandMap.php | 5 +++-- src/item/LegacyStringToItemParser.php | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/command/SimpleCommandMap.php b/src/command/SimpleCommandMap.php index 5c33bf25a..07afecf6d 100644 --- a/src/command/SimpleCommandMap.php +++ b/src/command/SimpleCommandMap.php @@ -272,10 +272,11 @@ class SimpleCommandMap implements CommandMap{ } //These registered commands have absolute priority + $lowerAlias = strtolower($alias); if(count($targets) > 0){ - $this->knownCommands[strtolower($alias)] = new FormattedCommandAlias(strtolower($alias), $targets); + $this->knownCommands[$lowerAlias] = new FormattedCommandAlias($lowerAlias, $targets); }else{ - unset($this->knownCommands[strtolower($alias)]); + unset($this->knownCommands[$lowerAlias]); } } diff --git a/src/item/LegacyStringToItemParser.php b/src/item/LegacyStringToItemParser.php index e05f4d031..3d69dd7ac 100644 --- a/src/item/LegacyStringToItemParser.php +++ b/src/item/LegacyStringToItemParser.php @@ -108,8 +108,9 @@ final class LegacyStringToItemParser{ throw new LegacyStringToItemParserException("Unable to parse \"" . $b[1] . "\" from \"" . $input . "\" as a valid meta value"); } - if(isset($this->map[strtolower($b[0])])){ - $item = $this->itemFactory->get($this->map[strtolower($b[0])], $meta); + $id = strtolower($b[0]); + if(isset($this->map[$id])){ + $item = $this->itemFactory->get($this->map[$id], $meta); }else{ throw new LegacyStringToItemParserException("Unable to resolve \"" . $input . "\" to a valid item"); } From 41970feb573bb27a0372b9b13451ac6e97ad479b Mon Sep 17 00:00:00 2001 From: Dylan T Date: Thu, 29 Sep 2022 22:30:12 +0100 Subject: [PATCH 6/6] Entity: Fire EntitySpawnEvent/ItemSpawnEvent on the first entity tick, instead of in the constructor (#5314) This allows plugins to modify the entity via setters in EntitySpawnEvent without their changes getting overwritten by setter calls directly after the 'new YourEntity' statement. As well as benefiting plugins, this also clears a path for a BC-breaking change in PM5 (to have the programmer use addEntity() to spawn entities, instead of the constructor doing it, which will improve on a number of data handling aspects). fixes #4973 This targets next-minor because it has some side effects on plugins that depended on the old behaviour, such as VanillaHopper, so it's not suitable for a patch release. --- src/entity/Entity.php | 14 ++++++++++++-- src/entity/object/ItemEntity.php | 5 ++++- src/player/Player.php | 4 ++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/entity/Entity.php b/src/entity/Entity.php index 54873f9f1..3e34d5c26 100644 --- a/src/entity/Entity.php +++ b/src/entity/Entity.php @@ -249,10 +249,8 @@ abstract class Entity{ $this->getWorld()->addEntity($this); $this->lastUpdate = $this->server->getTick(); - (new EntitySpawnEvent($this))->call(); $this->scheduleUpdate(); - } abstract protected function getInitialSizeInfo() : EntitySizeInfo; @@ -937,6 +935,14 @@ abstract class Entity{ return (new Vector2(-cos(deg2rad($this->location->yaw) - M_PI_2), -sin(deg2rad($this->location->yaw) - M_PI_2)))->normalize(); } + /** + * Called from onUpdate() on the first tick of a new entity. This is called before any movement processing or + * main ticking logic. Use this to fire any events related to spawning the entity. + */ + protected function onFirstUpdate(int $currentTick) : void{ + (new EntitySpawnEvent($this))->call(); + } + public function onUpdate(int $currentTick) : bool{ if($this->closed){ return false; @@ -953,6 +959,10 @@ abstract class Entity{ $this->lastUpdate = $currentTick; + if($this->justCreated){ + $this->onFirstUpdate($currentTick); + } + if(!$this->isAlive()){ if($this->onDeathUpdate($tickDiff)){ $this->flagForDespawn(); diff --git a/src/entity/object/ItemEntity.php b/src/entity/object/ItemEntity.php index 5c39f3bec..4fe844f7e 100644 --- a/src/entity/object/ItemEntity.php +++ b/src/entity/object/ItemEntity.php @@ -92,8 +92,11 @@ class ItemEntity extends Entity{ $this->pickupDelay = $nbt->getShort("PickupDelay", $this->pickupDelay); $this->owner = $nbt->getString("Owner", $this->owner); $this->thrower = $nbt->getString("Thrower", $this->thrower); + } - (new ItemSpawnEvent($this))->call(); + protected function onFirstUpdate(int $currentTick) : void{ + (new ItemSpawnEvent($this))->call(); //this must be called before EntitySpawnEvent, to maintain backwards compatibility + parent::onFirstUpdate($currentTick); } protected function entityBaseTick(int $tickDiff = 1) : bool{ diff --git a/src/player/Player.php b/src/player/Player.php index 340452b31..157038beb 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -1343,6 +1343,10 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $this->lastUpdate = $currentTick; + if($this->justCreated){ + $this->onFirstUpdate($currentTick); + } + if(!$this->isAlive() && $this->spawned){ $this->onDeathUpdate($tickDiff); return true;