Added candles and cakes with candles

This commit is contained in:
Dylan K. Taylor 2022-07-13 23:54:41 +01:00
parent 20cb67461f
commit eafc23c756
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
15 changed files with 616 additions and 61 deletions

89
src/block/BaseCake.php Normal file
View File

@ -0,0 +1,89 @@
<?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\SupportType;
use pocketmine\entity\effect\EffectInstance;
use pocketmine\entity\FoodSource;
use pocketmine\entity\Living;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
abstract class BaseCake extends Transparent implements FoodSource{
public function getSupportType(int $facing) : SupportType{
return SupportType::NONE();
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$down = $this->getSide(Facing::DOWN);
if($down->getTypeId() !== BlockTypeIds::AIR){
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
return false;
}
public function onNearbyBlockChange() : void{
if($this->getSide(Facing::DOWN)->getTypeId() === BlockTypeIds::AIR){ //Replace with common break method
$this->position->getWorld()->useBreakOn($this->position);
}
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player !== null){
return $player->consumeObject($this);
}
return false;
}
public function getFoodRestore() : int{
return 2;
}
public function getSaturationRestore() : float{
return 0.4;
}
public function requiresHunger() : bool{
return true;
}
/**
* @return EffectInstance[]
*/
public function getAdditionalEffects() : array{
return [];
}
abstract public function getResidue() : Block;
public function onConsume(Living $consumer) : void{
$this->position->getWorld()->setBlock($this->position, $this->getResidue());
}
}

View File

@ -684,6 +684,10 @@ final class BlockTypeIds{
public const CUT_COPPER = 10657;
public const CUT_COPPER_SLAB = 10658;
public const CUT_COPPER_STAIRS = 10659;
public const CANDLE = 10660;
public const DYED_CANDLE = 10661;
public const CAKE_WITH_CANDLE = 10662;
public const CAKE_WITH_DYED_CANDLE = 10663;
public const FIRST_UNUSED_BLOCK_ID = 10660;
public const FIRST_UNUSED_BLOCK_ID = 10664;
}

View File

@ -23,20 +23,16 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataReader;
use pocketmine\data\runtime\RuntimeDataWriter;
use pocketmine\entity\effect\EffectInstance;
use pocketmine\entity\FoodSource;
use pocketmine\entity\Living;
use pocketmine\item\Item;
use pocketmine\item\ItemBlock;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
class Cake extends Transparent implements FoodSource{
class Cake extends BaseCake{
public const MAX_BITES = 6;
protected int $bites = 0;
@ -63,10 +59,6 @@ class Cake extends Transparent implements FoodSource{
];
}
public function getSupportType(int $facing) : SupportType{
return SupportType::NONE();
}
public function getBites() : int{ return $this->bites; }
/** @return $this */
@ -78,49 +70,27 @@ class Cake extends Transparent implements FoodSource{
return $this;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$down = $this->getSide(Facing::DOWN);
if($down->getTypeId() !== BlockTypeIds::AIR){
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
return false;
}
public function onNearbyBlockChange() : void{
if($this->getSide(Facing::DOWN)->getTypeId() === BlockTypeIds::AIR){ //Replace with common break method
$this->position->getWorld()->setBlock($this->position, VanillaBlocks::AIR());
}
}
public function getDropsForCompatibleTool(Item $item) : array{
return [];
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player !== null){
return $player->consumeObject($this);
if($item instanceof ItemBlock){
$block = $item->getBlock();
$resultBlock = null;
if($block->getTypeId() === BlockTypeIds::CANDLE){
$resultBlock = VanillaBlocks::CAKE_WITH_CANDLE();
}elseif($block instanceof DyedCandle){
$resultBlock = VanillaBlocks::CAKE_WITH_DYED_CANDLE()->setColor($block->getColor());
}
if($resultBlock !== null){
$this->position->getWorld()->setBlock($this->position, $resultBlock);
$item->pop();
return true;
}
}
return false;
return parent::onInteract($item, $face, $clickVector, $player);
}
public function getFoodRestore() : int{
return 2;
}
public function getSaturationRestore() : float{
return 0.4;
}
public function requiresHunger() : bool{
return true;
}
/**
* @return Block
*/
public function getResidue(){
public function getResidue() : Block{
$clone = clone $this;
$clone->bites++;
if($clone->bites > self::MAX_BITES){
@ -128,15 +98,4 @@ class Cake extends Transparent implements FoodSource{
}
return $clone;
}
/**
* @return EffectInstance[]
*/
public function getAdditionalEffects() : array{
return [];
}
public function onConsume(Living $consumer) : void{
$this->position->getWorld()->setBlock($this->position, $this->getResidue());
}
}

View File

@ -0,0 +1,78 @@
<?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\CandleTrait;
use pocketmine\entity\Living;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
class CakeWithCandle extends BaseCake{
use CandleTrait {
onInteract as onInteractCandle;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [
AxisAlignedBB::one()
->contract(1 / 16, 0, 1 / 16)
->trim(Facing::UP, 0.5) //TODO: not sure if the candle affects height
];
}
public function getCandle() : Candle{
return VanillaBlocks::CANDLE();
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->onInteractCandle($item, $face, $clickVector, $player)){
return true;
}
return parent::onInteract($item, $face, $clickVector, $player);
}
public function getDropsForCompatibleTool(Item $item) : array{
return [$this->getCandle()->asItem()];
}
public function getPickedItem(bool $addUserData = false) : Item{
return VanillaBlocks::CAKE()->getPickedItem($addUserData);
}
public function getResidue() : Block{
return VanillaBlocks::CAKE()->setBites(1);
}
public function onConsume(Living $consumer) : void{
parent::onConsume($consumer);
$this->position->getWorld()->dropItem($this->position->add(0.5, 0.5, 0.5), $this->getCandle()->asItem());
}
}

View File

@ -0,0 +1,34 @@
<?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\ColoredTrait;
class CakeWithDyedCandle extends CakeWithCandle{
use ColoredTrait;
public function getCandle() : Candle{
return VanillaBlocks::DYED_CANDLE()->setColor($this->color);
}
}

132
src/block/Candle.php Normal file
View File

@ -0,0 +1,132 @@
<?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\CandleTrait;
use pocketmine\data\runtime\RuntimeDataReader;
use pocketmine\data\runtime\RuntimeDataWriter;
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\utils\AssumptionFailedError;
use pocketmine\world\BlockTransaction;
class Candle extends Transparent{
use CandleTrait {
decodeState as decodeLitState;
encodeState as encodeLitState;
getLightLevel as getBaseLightLevel;
}
public const MIN_COUNT = 1;
public const MAX_COUNT = 4;
private int $count = self::MIN_COUNT;
public function getRequiredStateDataBits() : int{
return 3;
}
protected function decodeState(RuntimeDataReader $r) : void{
$this->decodeLitState($r);
$this->count = $r->readBoundedInt(2, self::MIN_COUNT, self::MAX_COUNT);
}
protected function encodeState(RuntimeDataWriter $w) : void{
$this->encodeLitState($w);
$w->writeBoundedInt(2, self::MIN_COUNT, self::MAX_COUNT, $this->count);
}
public function getCount() : int{ return $this->count; }
/** @return $this */
public function setCount(int $count) : self{
if($count < self::MIN_COUNT || $count > self::MAX_COUNT){
throw new \InvalidArgumentException("Count must be in range " . self::MIN_COUNT . " ... " . self::MAX_COUNT);
}
$this->count = $count;
return $this;
}
public function getLightLevel() : int{
return $this->getBaseLightLevel() * $this->count;
}
protected function recalculateCollisionBoxes() : array{
return [
(match($this->count){
1 => AxisAlignedBB::one()
->squash(Axis::X, 7 / 16)
->squash(Axis::Z, 7 / 16),
2 => AxisAlignedBB::one()
->squash(Axis::X, 5 / 16)
->trim(Facing::NORTH, 7 / 16) //0.3 thick on the Z axis
->trim(Facing::SOUTH, 6 / 16),
3 => AxisAlignedBB::one()
->trim(Facing::WEST, 5 / 16)
->trim(Facing::EAST, 6 / 16)
->trim(Facing::NORTH, 6 / 16)
->trim(Facing::SOUTH, 5 / 16),
4 => AxisAlignedBB::one()
->squash(Axis::X, 5 / 16)
->trim(Facing::NORTH, 5 / 16)
->trim(Facing::SOUTH, 6 / 16),
default => throw new AssumptionFailedError("Unreachable")
})->trim(Facing::UP, 10 / 16)
];
}
protected function getCandleIfCompatibleType(Block $block) : ?Candle{
return $block instanceof Candle && $block->isSameType($this) ? $block : null;
}
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
$candle = $this->getCandleIfCompatibleType($blockReplace);
return $candle !== null ? $candle->count < self::MAX_COUNT : parent::canBePlacedAt($blockReplace, $clickVector, $face, $isClickedBlock);
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$down = $blockReplace->getSide(Facing::DOWN);
if(!$down->getSupportType(Facing::UP)->hasCenterSupport()){
return false;
}
$existing = $this->getCandleIfCompatibleType($blockReplace);
if($existing !== null){
if($existing->count >= self::MAX_COUNT){
return false;
}
$this->count = $existing->count + 1;
$this->lit = $existing->lit;
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function getDropsForCompatibleTool(Item $item) : array{
return [$this->asItem()->setCount($this->count)];
}
}

36
src/block/DyedCandle.php Normal file
View File

@ -0,0 +1,36 @@
<?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\ColoredTrait;
class DyedCandle extends Candle{
use ColoredTrait;
protected function getCandleIfCompatibleType(Block $block) : ?Candle{
$result = parent::getCandleIfCompatibleType($block);
//different coloured candles can't be combined in the same block
return $result instanceof DyedCandle && $result->color->equals($this->color) ? $result : null;
}
}

View File

@ -135,7 +135,10 @@ use function mb_strtolower;
* @method static BrownMushroomBlock BROWN_MUSHROOM_BLOCK()
* @method static Cactus CACTUS()
* @method static Cake CAKE()
* @method static CakeWithCandle CAKE_WITH_CANDLE()
* @method static CakeWithDyedCandle CAKE_WITH_DYED_CANDLE()
* @method static Opaque CALCITE()
* @method static Candle CANDLE()
* @method static Carpet CARPET()
* @method static Carrot CARROTS()
* @method static CarvedPumpkin CARVED_PUMPKIN()
@ -246,6 +249,7 @@ use function mb_strtolower;
* @method static DoubleTallGrass DOUBLE_TALLGRASS()
* @method static DragonEgg DRAGON_EGG()
* @method static DriedKelp DRIED_KELP()
* @method static DyedCandle DYED_CANDLE()
* @method static DyedShulkerBox DYED_SHULKER_BOX()
* @method static Element ELEMENT_ACTINIUM()
* @method static Element ELEMENT_ALUMINUM()
@ -1463,6 +1467,15 @@ final class VanillaBlocks{
self::register("cut_copper", new Copper(new BID(Ids::CUT_COPPER), "Cut Copper Block", $copperBreakInfo));
self::register("cut_copper_slab", new CopperSlab(new BID(Ids::CUT_COPPER_SLAB), "Cut Copper Slab", $copperBreakInfo));
self::register("cut_copper_stairs", new CopperStairs(new BID(Ids::CUT_COPPER_STAIRS), "Cut Copper Stairs", $copperBreakInfo));
$candleBreakInfo = new BreakInfo(0.1);
self::register("candle", new Candle(new BID(Ids::CANDLE), "Candle", $candleBreakInfo));
self::register("dyed_candle", new DyedCandle(new BID(Ids::DYED_CANDLE), "Dyed Candle", $candleBreakInfo));
//TODO: duplicated break info :(
$cakeBreakInfo = new BreakInfo(0.5);
self::register("cake_with_candle", new CakeWithCandle(new BID(Ids::CAKE_WITH_CANDLE), "Cake With Candle", $cakeBreakInfo));
self::register("cake_with_dyed_candle", new CakeWithDyedCandle(new BID(Ids::CAKE_WITH_DYED_CANDLE), "Cake With Dyed Candle", $cakeBreakInfo));
}
private static function registerMudBlocks() : void{

View File

@ -0,0 +1,99 @@
<?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\utils;
use pocketmine\block\Block;
use pocketmine\data\runtime\RuntimeDataReader;
use pocketmine\data\runtime\RuntimeDataWriter;
use pocketmine\entity\projectile\Projectile;
use pocketmine\item\Durable;
use pocketmine\item\enchantment\VanillaEnchantments;
use pocketmine\item\Item;
use pocketmine\item\ItemTypeIds;
use pocketmine\math\RayTraceResult;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\sound\FireExtinguishSound;
use pocketmine\world\sound\FlintSteelSound;
trait CandleTrait{
private bool $lit = false;
public function getRequiredStateDataBits() : int{ return 1; }
protected function decodeState(RuntimeDataReader $r) : void{
$this->lit = $r->readBool();
}
protected function encodeState(RuntimeDataWriter $w) : void{
$w->writeBool($this->lit);
}
public function getLightLevel() : int{
return $this->lit ? 3 : 0;
}
public function isLit() : bool{ return $this->lit; }
/** @return $this */
public function setLit(bool $lit) : self{
$this->lit = $lit;
return $this;
}
/** @see Block::onInteract() */
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($item->getTypeId() === ItemTypeIds::FLINT_AND_STEEL || $item->hasEnchantment(VanillaEnchantments::FIRE_ASPECT())){
if($this->lit){
return true;
}
if($item instanceof Durable){
$item->applyDamage(1);
}
$this->position->getWorld()->addSound($this->position, new FlintSteelSound());
$this->position->getWorld()->setBlock($this->position, $this->setLit(true));
return true;
}
if($item->isNull()){ //candle can only be extinguished with an empty hand
if(!$this->lit){
return true;
}
$this->position->getWorld()->addSound($this->position, new FireExtinguishSound());
$this->position->getWorld()->setBlock($this->position, $this->setLit(false));
return true;
}
//yes, this is intentional! in vanilla, if the candle is not interacted with, a block is placed.
return false;
}
/** @see Block::onProjectileHit() */
public function onProjectileHit(Projectile $projectile, RayTraceResult $hitResult) : void{
if(!$this->lit && $projectile->isOnFire()){
$this->position->getWorld()->setBlock($this->position, $this->setLit(true));
}
}
}

View File

@ -39,6 +39,9 @@ use pocketmine\block\BrownMushroomBlock;
use pocketmine\block\Button;
use pocketmine\block\Cactus;
use pocketmine\block\Cake;
use pocketmine\block\CakeWithCandle;
use pocketmine\block\CakeWithDyedCandle;
use pocketmine\block\Candle;
use pocketmine\block\Carpet;
use pocketmine\block\Carrot;
use pocketmine\block\CarvedPumpkin;
@ -58,6 +61,7 @@ use pocketmine\block\Dirt;
use pocketmine\block\Door;
use pocketmine\block\DoublePlant;
use pocketmine\block\DoubleTallGrass;
use pocketmine\block\DyedCandle;
use pocketmine\block\DyedShulkerBox;
use pocketmine\block\EnderChest;
use pocketmine\block\EndPortalFrame;
@ -171,6 +175,7 @@ final class BlockObjectToBlockStateSerializer implements BlockStateSerializer{
private array $serializers = [];
public function __construct(){
$this->registerCandleSerializers();
$this->registerSerializers();
}
@ -242,6 +247,50 @@ final class BlockObjectToBlockStateSerializer implements BlockStateSerializer{
return $writer->getBlockStateData();
}
private function registerCandleSerializers() : void{
$this->map(Blocks::CANDLE(), fn(Candle $block) => Helper::encodeCandle($block, new Writer(Ids::CANDLE)));
$this->map(Blocks::DYED_CANDLE(), fn(DyedCandle $block) => Helper::encodeCandle($block, new Writer(match($block->getColor()){
DyeColor::BLACK() => Ids::BLACK_CANDLE,
DyeColor::BLUE() => Ids::BLUE_CANDLE,
DyeColor::BROWN() => Ids::BROWN_CANDLE,
DyeColor::CYAN() => Ids::CYAN_CANDLE,
DyeColor::GRAY() => Ids::GRAY_CANDLE,
DyeColor::GREEN() => Ids::GREEN_CANDLE,
DyeColor::LIGHT_BLUE() => Ids::LIGHT_BLUE_CANDLE,
DyeColor::LIGHT_GRAY() => Ids::LIGHT_GRAY_CANDLE,
DyeColor::LIME() => Ids::LIME_CANDLE,
DyeColor::MAGENTA() => Ids::MAGENTA_CANDLE,
DyeColor::ORANGE() => Ids::ORANGE_CANDLE,
DyeColor::PINK() => Ids::PINK_CANDLE,
DyeColor::PURPLE() => Ids::PURPLE_CANDLE,
DyeColor::RED() => Ids::RED_CANDLE,
DyeColor::WHITE() => Ids::WHITE_CANDLE,
DyeColor::YELLOW() => Ids::YELLOW_CANDLE,
default => throw new AssumptionFailedError("Unhandled DyeColor " . $block->getColor()->name())
})));
$this->map(Blocks::CAKE_WITH_CANDLE(), fn(CakeWithCandle $block) => Writer::create(Ids::CANDLE_CAKE)
->writeBool(StateNames::LIT, $block->isLit()));
$this->map(Blocks::CAKE_WITH_DYED_CANDLE(), fn(CakeWithDyedCandle $block) => Writer::create(match($block->getColor()){
DyeColor::BLACK() => Ids::BLACK_CANDLE_CAKE,
DyeColor::BLUE() => Ids::BLUE_CANDLE_CAKE,
DyeColor::BROWN() => Ids::BROWN_CANDLE_CAKE,
DyeColor::CYAN() => Ids::CYAN_CANDLE_CAKE,
DyeColor::GRAY() => Ids::GRAY_CANDLE_CAKE,
DyeColor::GREEN() => Ids::GREEN_CANDLE_CAKE,
DyeColor::LIGHT_BLUE() => Ids::LIGHT_BLUE_CANDLE_CAKE,
DyeColor::LIGHT_GRAY() => Ids::LIGHT_GRAY_CANDLE_CAKE,
DyeColor::LIME() => Ids::LIME_CANDLE_CAKE,
DyeColor::MAGENTA() => Ids::MAGENTA_CANDLE_CAKE,
DyeColor::ORANGE() => Ids::ORANGE_CANDLE_CAKE,
DyeColor::PINK() => Ids::PINK_CANDLE_CAKE,
DyeColor::PURPLE() => Ids::PURPLE_CANDLE_CAKE,
DyeColor::RED() => Ids::RED_CANDLE_CAKE,
DyeColor::WHITE() => Ids::WHITE_CANDLE_CAKE,
DyeColor::YELLOW() => Ids::YELLOW_CANDLE_CAKE,
default => throw new AssumptionFailedError("Unhandled DyeColor " . $block->getColor()->name())
})->writeBool(StateNames::LIT, $block->isLit()));
}
private function registerSerializers() : void{
$this->map(Blocks::ACACIA_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::ACACIA_BUTTON)));
$this->map(Blocks::ACACIA_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::ACACIA_DOOR)));

View File

@ -25,6 +25,7 @@ namespace pocketmine\data\bedrock\block\convert;
use pocketmine\block\Block;
use pocketmine\block\Button;
use pocketmine\block\Candle;
use pocketmine\block\Copper;
use pocketmine\block\CopperSlab;
use pocketmine\block\CopperStairs;
@ -55,6 +56,7 @@ use pocketmine\block\Wood;
use pocketmine\data\bedrock\block\BlockLegacyMetadata;
use pocketmine\data\bedrock\block\BlockStateDeserializeException;
use pocketmine\data\bedrock\block\BlockStateNames;
use pocketmine\data\bedrock\block\BlockStateNames as StateNames;
use pocketmine\data\bedrock\block\BlockStateStringValues as StringValues;
use pocketmine\data\bedrock\MushroomBlockTypeIdMap;
use pocketmine\math\Axis;
@ -70,6 +72,13 @@ final class BlockStateDeserializerHelper{
->setPressed($in->readBool(BlockStateNames::BUTTON_PRESSED_BIT));
}
/** @throws BlockStateDeserializeException */
public static function decodeCandle(Candle $block, BlockStateReader $in) : Candle{
return $block
->setCount($in->readBoundedInt(StateNames::CANDLES, 0, 3) + 1)
->setLit($in->readBool(StateNames::LIT));
}
/**
* @phpstan-template TCrops of Crops
* @phpstan-param TCrops $block

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert;
use pocketmine\block\Button;
use pocketmine\block\Candle;
use pocketmine\block\ChemistryTable;
use pocketmine\block\Crops;
use pocketmine\block\Door;
@ -47,6 +48,7 @@ use pocketmine\block\Wall;
use pocketmine\block\WallSign;
use pocketmine\block\Wood;
use pocketmine\data\bedrock\block\BlockStateNames;
use pocketmine\data\bedrock\block\BlockStateNames as StateNames;
use pocketmine\data\bedrock\block\BlockTypeNames as Ids;
use pocketmine\data\bedrock\MushroomBlockTypeIdMap;
use pocketmine\math\Facing;
@ -67,6 +69,12 @@ final class BlockStateSerializerHelper{
->writeBool(BlockStateNames::BUTTON_PRESSED_BIT, $block->isPressed());
}
public static function encodeCandle(Candle $block, BlockStateWriter $out) : BlockStateWriter{
return $out
->writeBool(StateNames::LIT, $block->isLit())
->writeInt(StateNames::CANDLES, $block->getCount() - 1);
}
public static function encodeChemistryTable(ChemistryTable $block, string $chemistryTableType, BlockStateWriter $out) : BlockStateWriter{
return $out
->writeString(BlockStateNames::CHEMISTRY_TABLE_TYPE, $chemistryTableType)

View File

@ -59,6 +59,7 @@ final class BlockStateToBlockObjectDeserializer implements BlockStateDeserialize
private array $deserializeFuncs = [];
public function __construct(){
$this->registerCandleDeserializers();
$this->registerDeserializers();
}
@ -92,6 +93,48 @@ final class BlockStateToBlockObjectDeserializer implements BlockStateDeserialize
$this->map($id, fn(Reader $in) : Stair => Helper::decodeStairs($getBlock(), $in));
}
private function registerCandleDeserializers() : void{
$this->map(Ids::CANDLE, fn(Reader $in) => Helper::decodeCandle(Blocks::CANDLE(), $in));
$dyedCandleDeserializer = fn(DyeColor $color) => fn(Reader $in) => Helper::decodeCandle(Blocks::DYED_CANDLE()->setColor($color), $in);
$this->map(Ids::BLACK_CANDLE, $dyedCandleDeserializer(DyeColor::BLACK()));
$this->map(Ids::BLUE_CANDLE, $dyedCandleDeserializer(DyeColor::BLUE()));
$this->map(Ids::BROWN_CANDLE, $dyedCandleDeserializer(DyeColor::BROWN()));
$this->map(Ids::CYAN_CANDLE, $dyedCandleDeserializer(DyeColor::CYAN()));
$this->map(Ids::GRAY_CANDLE, $dyedCandleDeserializer(DyeColor::GRAY()));
$this->map(Ids::GREEN_CANDLE, $dyedCandleDeserializer(DyeColor::GREEN()));
$this->map(Ids::LIGHT_BLUE_CANDLE, $dyedCandleDeserializer(DyeColor::LIGHT_BLUE()));
$this->map(Ids::LIGHT_GRAY_CANDLE, $dyedCandleDeserializer(DyeColor::LIGHT_GRAY()));
$this->map(Ids::LIME_CANDLE, $dyedCandleDeserializer(DyeColor::LIME()));
$this->map(Ids::MAGENTA_CANDLE, $dyedCandleDeserializer(DyeColor::MAGENTA()));
$this->map(Ids::ORANGE_CANDLE, $dyedCandleDeserializer(DyeColor::ORANGE()));
$this->map(Ids::PINK_CANDLE, $dyedCandleDeserializer(DyeColor::PINK()));
$this->map(Ids::PURPLE_CANDLE, $dyedCandleDeserializer(DyeColor::PURPLE()));
$this->map(Ids::RED_CANDLE, $dyedCandleDeserializer(DyeColor::RED()));
$this->map(Ids::WHITE_CANDLE, $dyedCandleDeserializer(DyeColor::WHITE()));
$this->map(Ids::YELLOW_CANDLE, $dyedCandleDeserializer(DyeColor::YELLOW()));
$this->map(Ids::CANDLE_CAKE, fn(Reader $in) => Blocks::CAKE_WITH_CANDLE()->setLit($in->readBool(StateNames::LIT)));
$cakeWithDyedCandleDeserializer = fn(DyeColor $color) => fn(Reader $in) => Blocks::CAKE_WITH_DYED_CANDLE()
->setColor($color)
->setLit($in->readBool(StateNames::LIT));
$this->map(Ids::BLACK_CANDLE_CAKE, $cakeWithDyedCandleDeserializer(DyeColor::BLACK()));
$this->map(Ids::BLUE_CANDLE_CAKE, $cakeWithDyedCandleDeserializer(DyeColor::BLUE()));
$this->map(Ids::BROWN_CANDLE_CAKE, $cakeWithDyedCandleDeserializer(DyeColor::BROWN()));
$this->map(Ids::CYAN_CANDLE_CAKE, $cakeWithDyedCandleDeserializer(DyeColor::CYAN()));
$this->map(Ids::GRAY_CANDLE_CAKE, $cakeWithDyedCandleDeserializer(DyeColor::GRAY()));
$this->map(Ids::GREEN_CANDLE_CAKE, $cakeWithDyedCandleDeserializer(DyeColor::GREEN()));
$this->map(Ids::LIGHT_BLUE_CANDLE_CAKE, $cakeWithDyedCandleDeserializer(DyeColor::LIGHT_BLUE()));
$this->map(Ids::LIGHT_GRAY_CANDLE_CAKE, $cakeWithDyedCandleDeserializer(DyeColor::LIGHT_GRAY()));
$this->map(Ids::LIME_CANDLE_CAKE, $cakeWithDyedCandleDeserializer(DyeColor::LIME()));
$this->map(Ids::MAGENTA_CANDLE_CAKE, $cakeWithDyedCandleDeserializer(DyeColor::MAGENTA()));
$this->map(Ids::ORANGE_CANDLE_CAKE, $cakeWithDyedCandleDeserializer(DyeColor::ORANGE()));
$this->map(Ids::PINK_CANDLE_CAKE, $cakeWithDyedCandleDeserializer(DyeColor::PINK()));
$this->map(Ids::PURPLE_CANDLE_CAKE, $cakeWithDyedCandleDeserializer(DyeColor::PURPLE()));
$this->map(Ids::RED_CANDLE_CAKE, $cakeWithDyedCandleDeserializer(DyeColor::RED()));
$this->map(Ids::WHITE_CANDLE_CAKE, $cakeWithDyedCandleDeserializer(DyeColor::WHITE()));
$this->map(Ids::YELLOW_CANDLE_CAKE, $cakeWithDyedCandleDeserializer(DyeColor::YELLOW()));
}
private function registerDeserializers() : void{
$this->map(Ids::ACACIA_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::ACACIA_BUTTON(), $in));
$this->map(Ids::ACACIA_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::ACACIA_DOOR(), $in));

View File

@ -51,6 +51,7 @@ final class StringToItemParser extends StringToTParser{
//wall and floor banner are the same item
$result->registerBlock($prefix("banner"), fn() => Blocks::BANNER()->setColor($color));
$result->registerBlock($prefix("bed"), fn() => Blocks::BED()->setColor($color));
$result->registerBlock($prefix("candle"), fn() => Blocks::DYED_CANDLE()->setColor($color));
$result->registerBlock($prefix("carpet"), fn() => Blocks::CARPET()->setColor($color));
$result->registerBlock($prefix("concrete"), fn() => Blocks::CONCRETE()->setColor($color));
$result->registerBlock($prefix("concrete_powder"), fn() => Blocks::CONCRETE_POWDER()->setColor($color));
@ -181,6 +182,7 @@ final class StringToItemParser extends StringToTParser{
$result->registerBlock("cake", fn() => Blocks::CAKE());
$result->registerBlock("cake_block", fn() => Blocks::CAKE());
$result->registerBlock("calcite", fn() => Blocks::CALCITE());
$result->registerBlock("candle", fn() => Blocks::CANDLE());
$result->registerBlock("carpet", fn() => Blocks::CARPET());
$result->registerBlock("carrot_block", fn() => Blocks::CARROTS());
$result->registerBlock("carrots", fn() => Blocks::CARROTS());

File diff suppressed because one or more lines are too long