mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-04-20 16:00:20 +00:00
Added candles and cakes with candles
This commit is contained in:
parent
20cb67461f
commit
eafc23c756
89
src/block/BaseCake.php
Normal file
89
src/block/BaseCake.php
Normal 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());
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
78
src/block/CakeWithCandle.php
Normal file
78
src/block/CakeWithCandle.php
Normal 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());
|
||||
}
|
||||
}
|
34
src/block/CakeWithDyedCandle.php
Normal file
34
src/block/CakeWithDyedCandle.php
Normal 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
132
src/block/Candle.php
Normal 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
36
src/block/DyedCandle.php
Normal 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;
|
||||
}
|
||||
}
|
@ -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{
|
||||
|
99
src/block/utils/CandleTrait.php
Normal file
99
src/block/utils/CandleTrait.php
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
@ -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)));
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user