mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-04-20 16:00:20 +00:00
Implemented pitcher plants, crops and podsÂ
This commit is contained in:
parent
fe543a4789
commit
628d77f8d7
@ -742,8 +742,11 @@ final class BlockTypeIds{
|
||||
public const CHISELED_BOOKSHELF = 10712;
|
||||
public const TORCHFLOWER = 10713;
|
||||
public const TORCHFLOWER_CROP = 10714;
|
||||
public const PITCHER_PLANT = 10715;
|
||||
public const PITCHER_CROP = 10716;
|
||||
public const DOUBLE_PITCHER_CROP = 10717;
|
||||
|
||||
public const FIRST_UNUSED_BLOCK_ID = 10715;
|
||||
public const FIRST_UNUSED_BLOCK_ID = 10718;
|
||||
|
||||
private static int $nextDynamicId = self::FIRST_UNUSED_BLOCK_ID;
|
||||
|
||||
|
110
src/block/DoublePitcherCrop.php
Normal file
110
src/block/DoublePitcherCrop.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\AgeableTrait;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\event\block\StructureGrowEvent;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use function mt_rand;
|
||||
|
||||
final class DoublePitcherCrop extends DoublePlant{
|
||||
use AgeableTrait {
|
||||
describeBlockOnlyState as describeAge;
|
||||
}
|
||||
|
||||
public const MAX_AGE = 1;
|
||||
|
||||
public function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
parent::describeBlockOnlyState($w);
|
||||
$this->describeAge($w);
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
if($this->top){
|
||||
return [];
|
||||
}
|
||||
|
||||
//the pod exists only in the bottom half of the plant
|
||||
return [
|
||||
AxisAlignedBB::one()
|
||||
->trim(Facing::UP, 11 / 16)
|
||||
->squash(Axis::X, 3 / 16)
|
||||
->squash(Axis::Z, 3 / 16)
|
||||
->extend(Facing::DOWN, 1 / 16) //presumably this is to correct for farmland being 15/16 of a block tall
|
||||
];
|
||||
}
|
||||
|
||||
private function grow(?Player $player) : bool{
|
||||
if($this->age >= self::MAX_AGE){
|
||||
return false;
|
||||
}
|
||||
|
||||
$bottom = $this->top ? $this->getSide(Facing::DOWN) : $this;
|
||||
$top = $this->top ? $this : $this->getSide(Facing::UP);
|
||||
if($top->getTypeId() !== BlockTypeIds::AIR && !$top->hasSameTypeId($this)){
|
||||
return false;
|
||||
}
|
||||
|
||||
$newState = (clone $this)->setAge($this->age + 1);
|
||||
|
||||
$tx = new BlockTransaction($this->position->getWorld());
|
||||
$tx->addBlock($bottom->position, (clone $newState)->setTop(false));
|
||||
$tx->addBlock($top->position, (clone $newState)->setTop(true));
|
||||
|
||||
$ev = new StructureGrowEvent($bottom, $tx, $player);
|
||||
$ev->call();
|
||||
|
||||
return !$ev->isCancelled() && $tx->apply();
|
||||
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item instanceof Fertilizer && $this->grow($player)){
|
||||
$item->pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ticksRandomly() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
//TODO: the growth speed is influenced by farmland and nearby crops
|
||||
//only the bottom half of the plant can grow randomly
|
||||
if(mt_rand(0, 2) === 0 && !$this->top){
|
||||
$this->grow(null);
|
||||
}
|
||||
}
|
||||
}
|
105
src/block/PitcherCrop.php
Normal file
105
src/block/PitcherCrop.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\AgeableTrait;
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\StaticSupportTrait;
|
||||
use pocketmine\event\block\StructureGrowEvent;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use function mt_rand;
|
||||
|
||||
final class PitcherCrop extends Flowable{
|
||||
use AgeableTrait;
|
||||
use StaticSupportTrait;
|
||||
|
||||
public const MAX_AGE = 2;
|
||||
|
||||
private function canBeSupportedAt(Block $block) : bool{
|
||||
return $block->getSide(Facing::DOWN)->getTypeId() === BlockTypeIds::FARMLAND;
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
$widthTrim = $this->age === 0 ? 5 : 3;
|
||||
$heightTrim = $this->age === 0 ? 13 : 11;
|
||||
return [
|
||||
AxisAlignedBB::one()
|
||||
->trim(Facing::UP, $heightTrim / 16)
|
||||
->squash(Axis::X, $widthTrim / 16)
|
||||
->squash(Axis::Z, $widthTrim / 16)
|
||||
->extend(Facing::DOWN, 1 / 16) //presumably this is to correct for farmland being 15/16 of a block tall
|
||||
];
|
||||
}
|
||||
|
||||
private function grow(?Player $player) : bool{
|
||||
if($this->age > self::MAX_AGE){
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->age === self::MAX_AGE){
|
||||
$up = $this->getSide(Facing::UP);
|
||||
if($up->getTypeId() !== BlockTypeIds::AIR){
|
||||
return false;
|
||||
}
|
||||
|
||||
$tx = new BlockTransaction($this->position->getWorld());
|
||||
$tx->addBlock($this->position, VanillaBlocks::DOUBLE_PITCHER_CROP()->setTop(false));
|
||||
$tx->addBlock($this->position->up(), VanillaBlocks::DOUBLE_PITCHER_CROP()->setTop(true));
|
||||
|
||||
$ev = new StructureGrowEvent($this, $tx, $player);
|
||||
$ev->call();
|
||||
|
||||
return !$ev->isCancelled() && $tx->apply();
|
||||
}
|
||||
|
||||
return BlockEventHelper::grow($this, (clone $this)->setAge($this->age + 1), $player);
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item instanceof Fertilizer && $this->grow($player)){
|
||||
$item->pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ticksRandomly() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
//TODO: the growth speed is influenced by farmland and nearby crops
|
||||
if(mt_rand(0, 2) === 0){
|
||||
$this->grow(null);
|
||||
}
|
||||
}
|
||||
}
|
@ -284,6 +284,7 @@ use function strtolower;
|
||||
* @method static Stair DIORITE_STAIRS()
|
||||
* @method static Wall DIORITE_WALL()
|
||||
* @method static Dirt DIRT()
|
||||
* @method static DoublePitcherCrop DOUBLE_PITCHER_CROP()
|
||||
* @method static DoubleTallGrass DOUBLE_TALLGRASS()
|
||||
* @method static DragonEgg DRAGON_EGG()
|
||||
* @method static DriedKelp DRIED_KELP()
|
||||
@ -579,6 +580,8 @@ use function strtolower;
|
||||
* @method static DoublePlant PEONY()
|
||||
* @method static PinkPetals PINK_PETALS()
|
||||
* @method static Flower PINK_TULIP()
|
||||
* @method static PitcherCrop PITCHER_CROP()
|
||||
* @method static DoublePlant PITCHER_PLANT()
|
||||
* @method static Podzol PODZOL()
|
||||
* @method static Opaque POLISHED_ANDESITE()
|
||||
* @method static Slab POLISHED_ANDESITE_SLAB()
|
||||
@ -852,6 +855,9 @@ final class VanillaBlocks{
|
||||
self::register("pink_petals", new PinkPetals(new BID(Ids::PINK_PETALS), "Pink Petals", new Info(BreakInfo::instant())));
|
||||
self::register("double_tallgrass", new DoubleTallGrass(new BID(Ids::DOUBLE_TALLGRASS), "Double Tallgrass", new Info(BreakInfo::instant(ToolType::SHEARS, 1))));
|
||||
self::register("large_fern", new DoubleTallGrass(new BID(Ids::LARGE_FERN), "Large Fern", new Info(BreakInfo::instant(ToolType::SHEARS, 1))));
|
||||
self::register("pitcher_plant", new DoublePlant(new BID(Ids::PITCHER_PLANT), "Pitcher Plant", new Info(BreakInfo::instant())));
|
||||
self::register("pitcher_crop", new PitcherCrop(new BID(Ids::PITCHER_CROP), "Pitcher Crop", new Info(BreakInfo::instant())));
|
||||
self::register("double_pitcher_crop", new DoublePitcherCrop(new BID(Ids::DOUBLE_PITCHER_CROP), "Double Pitcher Crop", new Info(BreakInfo::instant())));
|
||||
self::register("dragon_egg", new DragonEgg(new BID(Ids::DRAGON_EGG), "Dragon Egg", new Info(BreakInfo::pickaxe(3.0, ToolTier::WOOD))));
|
||||
self::register("dried_kelp", new DriedKelp(new BID(Ids::DRIED_KELP), "Dried Kelp Block", new Info(new BreakInfo(0.5, ToolType::NONE, 0, 12.5))));
|
||||
self::register("emerald", new Opaque(new BID(Ids::EMERALD), "Emerald Block", new Info(BreakInfo::pickaxe(5.0, ToolTier::IRON, 30.0))));
|
||||
|
@ -65,6 +65,7 @@ use pocketmine\block\DaylightSensor;
|
||||
use pocketmine\block\DetectorRail;
|
||||
use pocketmine\block\Dirt;
|
||||
use pocketmine\block\Door;
|
||||
use pocketmine\block\DoublePitcherCrop;
|
||||
use pocketmine\block\DoublePlant;
|
||||
use pocketmine\block\DoubleTallGrass;
|
||||
use pocketmine\block\DyedCandle;
|
||||
@ -103,6 +104,7 @@ use pocketmine\block\NetherPortal;
|
||||
use pocketmine\block\NetherVines;
|
||||
use pocketmine\block\NetherWartPlant;
|
||||
use pocketmine\block\PinkPetals;
|
||||
use pocketmine\block\PitcherCrop;
|
||||
use pocketmine\block\Potato;
|
||||
use pocketmine\block\PoweredRail;
|
||||
use pocketmine\block\PumpkinStem;
|
||||
@ -1457,6 +1459,20 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
->writeInt(StateNames::GROWTH, $block->getCount() - 1);
|
||||
});
|
||||
$this->map(Blocks::PINK_TULIP(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_TULIP_PINK));
|
||||
$this->map(Blocks::PITCHER_PLANT(), function(DoublePlant $block) : Writer{
|
||||
return Writer::create(Ids::PITCHER_PLANT)
|
||||
->writeBool(StateNames::UPPER_BLOCK_BIT, $block->isTop());
|
||||
});
|
||||
$this->map(Blocks::PITCHER_CROP(), function(PitcherCrop $block) : Writer{
|
||||
return Writer::create(Ids::PITCHER_CROP)
|
||||
->writeInt(StateNames::GROWTH, $block->getAge())
|
||||
->writeBool(StateNames::UPPER_BLOCK_BIT, false);
|
||||
});
|
||||
$this->map(Blocks::DOUBLE_PITCHER_CROP(), function(DoublePitcherCrop $block) : Writer{
|
||||
return Writer::create(Ids::PITCHER_CROP)
|
||||
->writeInt(StateNames::GROWTH, $block->getAge() + 1 + PitcherCrop::MAX_AGE)
|
||||
->writeBool(StateNames::UPPER_BLOCK_BIT, $block->isTop());
|
||||
});
|
||||
$this->map(Blocks::POLISHED_ANDESITE(), fn() => Helper::encodeStone(StringValues::STONE_TYPE_ANDESITE_SMOOTH));
|
||||
$this->map(Blocks::POLISHED_ANDESITE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab3($block, StringValues::STONE_SLAB_TYPE_3_POLISHED_ANDESITE));
|
||||
$this->mapStairs(Blocks::POLISHED_ANDESITE_STAIRS(), Ids::POLISHED_ANDESITE_STAIRS);
|
||||
|
@ -28,8 +28,10 @@ use pocketmine\block\Bamboo;
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\CaveVines;
|
||||
use pocketmine\block\ChorusFlower;
|
||||
use pocketmine\block\DoublePitcherCrop;
|
||||
use pocketmine\block\Light;
|
||||
use pocketmine\block\PinkPetals;
|
||||
use pocketmine\block\PitcherCrop;
|
||||
use pocketmine\block\Slab;
|
||||
use pocketmine\block\Stair;
|
||||
use pocketmine\block\SweetBerryBush;
|
||||
@ -1296,6 +1298,22 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
->setFacing($in->readCardinalHorizontalFacing())
|
||||
->setCount(min($growth + 1, PinkPetals::MAX_COUNT));
|
||||
});
|
||||
$this->map(Ids::PITCHER_CROP, function(Reader $in) : Block{
|
||||
$growth = $in->readBoundedInt(StateNames::GROWTH, 0, 7);
|
||||
$top = $in->readBool(StateNames::UPPER_BLOCK_BIT);
|
||||
if($growth <= PitcherCrop::MAX_AGE){
|
||||
//top pitcher crop with age 0-2 is an invalid state
|
||||
//only the bottom half should exist in this case
|
||||
return $top ? Blocks::AIR() : Blocks::PITCHER_CROP()->setAge($growth);
|
||||
}
|
||||
return Blocks::DOUBLE_PITCHER_CROP()
|
||||
->setAge(min($growth - PitcherCrop::MAX_AGE - 1, DoublePitcherCrop::MAX_AGE))
|
||||
->setTop($top);
|
||||
});
|
||||
$this->map(Ids::PITCHER_PLANT, function(Reader $in) : Block{
|
||||
return Blocks::PITCHER_PLANT()
|
||||
->setTop($in->readBool(StateNames::UPPER_BLOCK_BIT));
|
||||
});
|
||||
$this->mapStairs(Ids::POLISHED_ANDESITE_STAIRS, fn() => Blocks::POLISHED_ANDESITE_STAIRS());
|
||||
$this->map(Ids::POLISHED_BASALT, function(Reader $in) : Block{
|
||||
return Blocks::POLISHED_BASALT()
|
||||
|
@ -147,6 +147,7 @@ final class ItemSerializerDeserializerRegistrar{
|
||||
$this->map1to1Block(Ids::JUNGLE_DOOR, Blocks::JUNGLE_DOOR());
|
||||
$this->map1to1Block(Ids::MANGROVE_DOOR, Blocks::MANGROVE_DOOR());
|
||||
$this->map1to1Block(Ids::NETHER_WART, Blocks::NETHER_WART());
|
||||
$this->map1to1Block(Ids::PITCHER_POD, Blocks::PITCHER_CROP());
|
||||
$this->map1to1Block(Ids::REPEATER, Blocks::REDSTONE_REPEATER());
|
||||
$this->map1to1Block(Ids::SPRUCE_DOOR, Blocks::SPRUCE_DOOR());
|
||||
$this->map1to1Block(Ids::SUGAR_CANE, Blocks::SUGARCANE());
|
||||
|
Loading…
x
Reference in New Issue
Block a user