PocketMine-MP 5.15.1 git-5ef247620a7c6301a849b54e5ef1009217729fc8
WaterCauldron.php
1<?php
2
3/*
4 *
5 * ____ _ _ __ __ _ __ __ ____
6 * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8 * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9 * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * @author PocketMine Team
17 * @link http://www.pocketmine.net/
18 *
19 *
20 */
21
22declare(strict_types=1);
23
24namespace pocketmine\block;
25
26use pocketmine\block\tile\Cauldron as TileCauldron;
27use pocketmine\block\utils\DyeColor;
47use function array_pop;
48use function assert;
49use function count;
50
51final class WaterCauldron extends FillableCauldron{
52
53 public const WATER_BOTTLE_FILL_AMOUNT = 2;
54
55 public const DYE_ARMOR_USE_AMOUNT = 1;
56 public const CLEAN_ARMOR_USE_AMOUNT = 1;
57 public const CLEAN_BANNER_USE_AMOUNT = 1;
58 public const CLEAN_SHULKER_BOX_USE_AMOUNT = 1;
59
60 //TODO: I'm not sure if this was intended to be 2 (to match java) but in Bedrock you can extinguish yourself 6 times ...
61 public const ENTITY_EXTINGUISH_USE_AMOUNT = 1;
62
63 private ?Color $customWaterColor = null;
64
65 public function readStateFromWorld() : Block{
66 $result = parent::readStateFromWorld();
67 if($result !== $this){
68 return $result;
69 }
70
71 $tile = $this->position->getWorld()->getTile($this->position);
72
73 $potionItem = $tile instanceof TileCauldron ? $tile->getPotionItem() : null;
74 if($potionItem !== null){
75 //TODO: HACK! we keep potion cauldrons as a separate block type due to different behaviour, but in the
76 //blockstate they are typically indistinguishable from water cauldrons. This hack converts cauldrons into
77 //their appropriate type.
78 return VanillaBlocks::POTION_CAULDRON()->setFillLevel($this->getFillLevel())->setPotionItem($potionItem);
79 }
80
81 $this->customWaterColor = $tile instanceof TileCauldron ? $tile->getCustomWaterColor() : null;
82
83 return $this;
84 }
85
86 public function writeStateToWorld() : void{
87 parent::writeStateToWorld();
88 $tile = $this->position->getWorld()->getTile($this->position);
89 assert($tile instanceof TileCauldron);
90 $tile->setCustomWaterColor($this->customWaterColor);
91 $tile->setPotionItem(null);
92 }
93
94 public function getCustomWaterColor() : ?Color{ return $this->customWaterColor; }
95
97 public function setCustomWaterColor(?Color $customWaterColor) : self{
98 $this->customWaterColor = $customWaterColor;
99 return $this;
100 }
101
102 public function getFillSound() : Sound{
103 return new CauldronFillWaterSound();
104 }
105
106 public function getEmptySound() : Sound{
107 return new CauldronEmptyWaterSound();
108 }
109
110 public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
111 $world = $this->position->getWorld();
112 if(($dyeColor = match($item->getTypeId()){
113 ItemTypeIds::LAPIS_LAZULI => DyeColor::BLUE,
114 ItemTypeIds::INK_SAC => DyeColor::BLACK,
115 ItemTypeIds::COCOA_BEANS => DyeColor::BROWN,
116 ItemTypeIds::BONE_MEAL => DyeColor::WHITE,
117 ItemTypeIds::DYE => $item instanceof Dye ? $item->getColor() : null,
118 default => null
119 }) !== null && ($newColor = $dyeColor->getRgbValue())->toRGBA() !== $this->customWaterColor?->toRGBA()
120 ){
121 $world->setBlock($this->position, $this->setCustomWaterColor($this->customWaterColor === null ? $newColor : Color::mix($this->customWaterColor, $newColor)));
122 $world->addSound($this->position->add(0.5, 0.5, 0.5), new CauldronAddDyeSound());
123
124 $item->pop();
125 }elseif($item instanceof Potion || $item instanceof SplashPotion){ //TODO: lingering potion
126 if($item->getType() === PotionType::WATER){
127 $this->setCustomWaterColor(null)->addFillLevels(self::WATER_BOTTLE_FILL_AMOUNT, $item, VanillaItems::GLASS_BOTTLE(), $returnedItems);
128 }else{
129 $this->mix($item, VanillaItems::GLASS_BOTTLE(), $returnedItems);
130 }
131 }elseif($item instanceof Armor){
132 if($this->customWaterColor !== null){
133 if(match($item->getTypeId()){ //TODO: a DyeableArmor class would probably be a better idea, since not all types of armor are dyeable
134 ItemTypeIds::LEATHER_CAP,
135 ItemTypeIds::LEATHER_TUNIC,
136 ItemTypeIds::LEATHER_PANTS,
137 ItemTypeIds::LEATHER_BOOTS => true,
138 default => false
139 } && $item->getCustomColor()?->toRGBA() !== $this->customWaterColor->toRGBA()){
140 $item->setCustomColor($this->customWaterColor);
141 $world->setBlock($this->position, $this->withFillLevel($this->getFillLevel() - self::DYE_ARMOR_USE_AMOUNT));
142 $world->addSound($this->position->add(0.5, 0.5, 0.5), new CauldronDyeItemSound());
143 }
144 }elseif($item->getCustomColor() !== null){
145 $item->clearCustomColor();
146 $world->setBlock($this->position, $this->withFillLevel($this->getFillLevel() - self::CLEAN_ARMOR_USE_AMOUNT));
147 $world->addSound($this->position->add(0.5, 0.5, 0.5), new CauldronCleanItemSound());
148 }
149 }elseif($item instanceof Banner){
150 $patterns = $item->getPatterns();
151 if(count($patterns) > 0 && $this->customWaterColor === null){
152 array_pop($patterns);
153 $item->setPatterns($patterns);
154
155 $world->setBlock($this->position, $this->withFillLevel($this->getFillLevel() - self::CLEAN_BANNER_USE_AMOUNT));
156 $world->addSound($this->position->add(0.5, 0.5, 0.5), new CauldronCleanItemSound());
157 }
158 }elseif(ItemTypeIds::toBlockTypeId($item->getTypeId()) === BlockTypeIds::DYED_SHULKER_BOX){
159 if($this->customWaterColor === null){
160 $newItem = VanillaBlocks::SHULKER_BOX()->asItem();
161 $newItem->setNamedTag($item->getNamedTag());
162
163 $item->pop();
164 $returnedItems[] = $newItem;
165
166 $world->setBlock($this->position, $this->withFillLevel($this->getFillLevel() - self::CLEAN_SHULKER_BOX_USE_AMOUNT));
167 $world->addSound($this->position->add(0.5, 0.5, 0.5), new CauldronCleanItemSound());
168 }
169 }else{
170 match($item->getTypeId()){
171 ItemTypeIds::WATER_BUCKET => $this->setCustomWaterColor(null)->addFillLevels(self::MAX_FILL_LEVEL, $item, VanillaItems::BUCKET(), $returnedItems),
172 ItemTypeIds::BUCKET => $this->removeFillLevels(self::MAX_FILL_LEVEL, $item, VanillaItems::WATER_BUCKET(), $returnedItems),
173 ItemTypeIds::GLASS_BOTTLE => $this->removeFillLevels(self::WATER_BOTTLE_FILL_AMOUNT, $item, VanillaItems::POTION()->setType(PotionType::WATER), $returnedItems),
174 ItemTypeIds::LAVA_BUCKET, ItemTypeIds::POWDER_SNOW_BUCKET => $this->mix($item, VanillaItems::BUCKET(), $returnedItems),
175 default => null
176 };
177 }
178
179 return true;
180 }
181
182 public function hasEntityCollision() : bool{ return true; }
183
184 public function onEntityInside(Entity $entity) : bool{
185 if($entity->isOnFire()){
186 $entity->extinguish();
187 //TODO: particles
188
189 $this->position->getWorld()->setBlock($this->position, $this->withFillLevel($this->getFillLevel() - self::ENTITY_EXTINGUISH_USE_AMOUNT));
190 }
191
192 return true;
193 }
194
195 public function onNearbyBlockChange() : void{
196 $hasCustomWaterColor = $this->customWaterColor !== null;
197 if($this->getFillLevel() < self::MAX_FILL_LEVEL || $hasCustomWaterColor){
198 $world = $this->position->getWorld();
199 if($world->getBlock($this->position->up())->getTypeId() === BlockTypeIds::WATER){
200 if($hasCustomWaterColor){
201 //TODO: particles
202 }
203 $world->setBlock($this->position, $this->setCustomWaterColor(null)->setFillLevel(FillableCauldron::MAX_FILL_LEVEL));
204 $world->addSound($this->position->add(0.5, 0.5, 0.5), $this->getFillSound());
205 }
206 }
207 }
208}
setCustomWaterColor(?Color $customWaterColor)
onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player=null, array &$returnedItems=[])
pop(int $count=1)
Definition: Item.php:430
setNamedTag(CompoundTag $tag)
Definition: Item.php:263