Implemented sweet berries (#4164)

this doesn't implement the server-side logic for the "stickiness" (slowdown) because we don't have the system needed for it yet.
It also doesn't have parity with vanilla on the damage.
This commit is contained in:
Angel 2021-07-19 15:01:33 -04:00 committed by GitHub
parent f64ef50ce3
commit 309bed414f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 210 additions and 3 deletions

View File

@ -585,7 +585,7 @@ class BlockFactory{
//TODO: minecraft:sticky_piston
//TODO: minecraft:stonecutter_block
//TODO: minecraft:structure_block
//TODO: minecraft:sweet_berry_bush
$this->register(new SweetBerryBush(new BID(Ids::SWEET_BERRY_BUSH, 0, ItemIds::SWEET_BERRIES), "Sweet Berry Bush", BlockBreakInfo::instant()));
//TODO: minecraft:turtle_egg
//endregion

View File

@ -0,0 +1,161 @@
<?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\BlockDataSerializer;
use pocketmine\entity\Entity;
use pocketmine\entity\Living;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use function mt_rand;
class SweetBerryBush extends Flowable{
public const STAGE_SAPLING = 0;
public const STAGE_BUSH_NO_BERRIES = 1;
public const STAGE_BUSH_SOME_BERRIES = 2;
public const STAGE_MATURE = 3;
protected int $age = self::STAGE_SAPLING;
protected function writeStateToMeta() : int{
return $this->age;
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->age = BlockDataSerializer::readBoundedInt("stage", $stateMeta, self::STAGE_SAPLING, self::STAGE_MATURE);
}
public function getStateBitmask() : int{
return 0b111;
}
public function getAge() : int{ return $this->age; }
/** @return $this */
public function setAge(int $age) : self{
if($age < self::STAGE_SAPLING || $age > self::STAGE_MATURE){
throw new \InvalidArgumentException("Age must be in range 0-3");
}
$this->age = $age;
return $this;
}
public function getBerryDropAmount() : int{
if($this->age === self::STAGE_MATURE){
return mt_rand(2, 3);
}elseif($this->age >= self::STAGE_BUSH_SOME_BERRIES){
return mt_rand(1, 2);
}
return 0;
}
protected function canBeSupportedBy(Block $block) : bool{
$id = $block->getId();
return $id === BlockLegacyIds::GRASS || $id === BlockLegacyIds::DIRT || $id === BlockLegacyIds::PODZOL;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedBy($blockReplace->getSide(Facing::DOWN))){
return false;
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->age < self::STAGE_MATURE && $item instanceof Fertilizer){
$block = clone $this;
$block->age++;
$ev = new BlockGrowEvent($this, $block);
$ev->call();
if(!$ev->isCancelled()){
$this->pos->getWorld()->setBlock($this->pos, $ev->getNewState());
}
$item->pop();
}elseif(($dropAmount = $this->getBerryDropAmount()) > 0){
$this->pos->getWorld()->setBlock($this->pos, $this->setAge(self::STAGE_BUSH_NO_BERRIES));
$this->pos->getWorld()->dropItem($this->pos, $this->asItem()->setCount($dropAmount));
}
return true;
}
public function asItem() : Item{
return VanillaItems::SWEET_BERRIES();
}
public function getDropsForCompatibleTool(Item $item) : array{
if(($dropAmount = $this->getBerryDropAmount()) > 0){
return [
$this->asItem()->setCount($dropAmount)
];
}
return [];
}
public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedBy($this->getSide(Facing::DOWN))){
$this->pos->getWorld()->useBreakOn($this->pos);
}
}
public function ticksRandomly() : bool{
return true;
}
public function onRandomTick() : void{
if($this->age < self::STAGE_MATURE and mt_rand(0, 2) === 1){
$block = clone $this;
++$block->age;
$ev = new BlockGrowEvent($this, $block);
$ev->call();
if(!$ev->isCancelled()){
$this->pos->getWorld()->setBlock($this->pos, $ev->getNewState());
}
}
}
public function hasEntityCollision() : bool{
return true;
}
public function onEntityInside(Entity $entity) : bool{
//TODO: in MCPE, this only triggers if moving while inside the bush block - we don't have the system to deal
//with that reliably right now
if($this->age >= self::STAGE_BUSH_NO_BERRIES && $entity instanceof Living){
$entity->attack(new EntityDamageByBlockEvent($this, $entity, EntityDamageByBlockEvent::CAUSE_CONTACT, 1));
}
return true;
}
}

View File

@ -545,6 +545,7 @@ use function assert;
* @method static Wood STRIPPED_SPRUCE_WOOD()
* @method static Sugarcane SUGARCANE()
* @method static DoublePlant SUNFLOWER()
* @method static SweetBerryBush SWEET_BERRY_BUSH()
* @method static TallGrass TALL_GRASS()
* @method static TNT TNT()
* @method static Torch TORCH()
@ -1107,6 +1108,7 @@ final class VanillaBlocks{
self::register("stripped_spruce_wood", $factory->get(467, 9));
self::register("sugarcane", $factory->get(83, 0));
self::register("sunflower", $factory->get(175, 0));
self::register("sweet_berry_bush", $factory->get(462, 0));
self::register("tall_grass", $factory->get(31, 1));
self::register("tnt", $factory->get(46, 0));
self::register("torch", $factory->get(50, 5));

View File

@ -326,7 +326,7 @@ class ItemFactory{
//TODO: minecraft:shield
//TODO: minecraft:sparkler
//TODO: minecraft:spawn_egg
//TODO: minecraft:sweet_berries
$this->register(new SweetBerries(new ItemIdentifier(ItemIds::SWEET_BERRIES, 0), "Sweet Berries"));
//TODO: minecraft:tnt_minecart
//TODO: minecraft:trident
//TODO: minecraft:turtle_helmet

42
src/item/SweetBerries.php Normal file
View File

@ -0,0 +1,42 @@
<?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\item;
use pocketmine\block\Block;
use pocketmine\block\VanillaBlocks;
class SweetBerries extends Food{
public function getFoodRestore() : int{
return 2;
}
public function getSaturationRestore() : float{
return 1.2;
}
public function getBlock(?int $clickedFace = null) : Block{
return VanillaBlocks::SWEET_BERRY_BUSH();
}
}

View File

@ -334,6 +334,7 @@ use function assert;
* @method static Potion STRONG_TURTLE_MASTER_POTION()
* @method static SplashPotion STRONG_TURTLE_MASTER_SPLASH_POTION()
* @method static Item SUGAR()
* @method static SweetBerries SWEET_BERRIES()
* @method static Potion SWIFTNESS_POTION()
* @method static SplashPotion SWIFTNESS_SPLASH_POTION()
* @method static Potion THICK_POTION()
@ -700,6 +701,7 @@ final class VanillaItems{
self::register("strong_turtle_master_potion", $factory->get(373, 39));
self::register("strong_turtle_master_splash_potion", $factory->get(438, 39));
self::register("sugar", $factory->get(353));
self::register("sweet_berries", $factory->get(477));
self::register("swiftness_potion", $factory->get(373, 14));
self::register("swiftness_splash_potion", $factory->get(438, 14));
self::register("thick_potion", $factory->get(373, 3));

File diff suppressed because one or more lines are too long