PocketMine-MP 5.33.2 git-1133d49c924b4358c79d44eeb97dcbf56cb4d1eb
Loading...
Searching...
No Matches
BaseSign.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\Sign as TileSign;
27use pocketmine\block\utils\DyeColor;
29use pocketmine\block\utils\SupportType;
31use pocketmine\block\utils\WoodType;
32use pocketmine\block\utils\WoodTypeTrait;
45use function abs;
46use function array_map;
47use function assert;
48use function atan2;
49use function fmod;
50use function rad2deg;
51use function strlen;
52
53abstract class BaseSign extends Transparent implements WoodMaterial{
54 use WoodTypeTrait;
55
56 protected SignText $text; //TODO: rename this (BC break)
57 protected SignText $backText;
58 private bool $waxed = false;
59
60 protected ?int $editorEntityRuntimeId = null;
61
63 private \Closure $asItemCallback;
64
68 public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo, WoodType $woodType, \Closure $asItemCallback){
69 $this->woodType = $woodType;
70 parent::__construct($idInfo, $name, $typeInfo);
71 $this->text = new SignText();
72 $this->backText = new SignText();
73 $this->asItemCallback = $asItemCallback;
74 }
75
76 public function readStateFromWorld() : Block{
77 parent::readStateFromWorld();
78 $tile = $this->position->getWorld()->getTile($this->position);
79 if($tile instanceof TileSign){
80 $this->text = $tile->getText();
81 $this->backText = $tile->getBackText();
82 $this->waxed = $tile->isWaxed();
83 $this->editorEntityRuntimeId = $tile->getEditorEntityRuntimeId();
84 }
85
86 return $this;
87 }
88
89 public function writeStateToWorld() : void{
90 parent::writeStateToWorld();
91 $tile = $this->position->getWorld()->getTile($this->position);
92 assert($tile instanceof TileSign);
93 $tile->setText($this->text);
94 $tile->setBackText($this->backText);
95 $tile->setWaxed($this->waxed);
96 $tile->setEditorEntityRuntimeId($this->editorEntityRuntimeId);
97 }
98
99 public function isSolid() : bool{
100 return false;
101 }
102
103 public function getMaxStackSize() : int{
104 return 16;
105 }
106
107 protected function recalculateCollisionBoxes() : array{
108 return [];
109 }
110
111 public function getSupportType(Facing $facing) : SupportType{
112 return SupportType::NONE;
113 }
114
115 abstract protected function getSupportingFace() : Facing;
116
117 public function onNearbyBlockChange() : void{
118 if($this->getSide($this->getSupportingFace())->getTypeId() === BlockTypeIds::AIR){
119 $this->position->getWorld()->useBreakOn($this->position);
120 }
121 }
122
123 public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
124 if($player !== null){
125 $this->editorEntityRuntimeId = $player->getId();
126 }
127 return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
128 }
129
130 public function onPostPlace() : void{
131 $player = $this->editorEntityRuntimeId !== null ?
132 $this->position->getWorld()->getEntity($this->editorEntityRuntimeId) :
133 null;
134 if($player instanceof Player){
135 $player->openSignEditor($this->position);
136 }
137 }
138
139 private function doSignChange(SignText $newText, Player $player, Item $item, bool $frontFace) : bool{
140 $ev = new SignChangeEvent($this, $player, $newText, $frontFace);
141 $ev->call();
142 if(!$ev->isCancelled()){
143 $this->setFaceText($frontFace, $ev->getNewText());
144 $this->position->getWorld()->setBlock($this->position, $this);
145 $item->pop();
146 return true;
147 }
148
149 return false;
150 }
151
152 private function changeSignGlowingState(bool $glowing, Player $player, Item $item, bool $frontFace) : bool{
153 $text = $this->getFaceText($frontFace);
154 if($text->isGlowing() !== $glowing && $this->doSignChange(new SignText($text->getLines(), $text->getBaseColor(), $glowing), $player, $item, $frontFace)){
155 $this->position->getWorld()->addSound($this->position, new InkSacUseSound());
156 return true;
157 }
158 return false;
159 }
160
161 private function wax(Player $player, Item $item) : bool{
162 if($this->waxed){
163 return false;
164 }
165
166 $this->waxed = true;
167 $this->position->getWorld()->setBlock($this->position, $this);
168 $item->pop();
169
170 return true;
171 }
172
173 public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
174 if($player === null){
175 return false;
176 }
177 if($this->waxed){
178 return true;
179 }
180
181 $frontFace = $this->interactsFront($this->getHitboxCenter(), $player->getPosition(), $this->getFacingDegrees());
182
183 $dyeColor = $item instanceof Dye ? $item->getColor() : match($item->getTypeId()){
184 ItemTypeIds::BONE_MEAL => DyeColor::WHITE,
185 ItemTypeIds::LAPIS_LAZULI => DyeColor::BLUE,
186 ItemTypeIds::COCOA_BEANS => DyeColor::BROWN,
187 default => null
188 };
189 if($dyeColor !== null){
190 $color = $dyeColor === DyeColor::BLACK ? new Color(0, 0, 0) : $dyeColor->getRgbValue();
191 $text = $this->getFaceText($frontFace);
192 if(
193 $color->toARGB() !== $text->getBaseColor()->toARGB() &&
194 $this->doSignChange(new SignText($text->getLines(), $color, $text->isGlowing()), $player, $item, $frontFace)
195 ){
196 $this->position->getWorld()->addSound($this->position, new DyeUseSound());
197 return true;
198 }
199 }elseif(match($item->getTypeId()){
200 ItemTypeIds::INK_SAC => $this->changeSignGlowingState(false, $player, $item, $frontFace),
201 ItemTypeIds::GLOW_INK_SAC => $this->changeSignGlowingState(true, $player, $item, $frontFace),
202 ItemTypeIds::HONEYCOMB => $this->wax($player, $item),
203 default => false
204 }){
205 return true;
206 }
207
208 $player->openSignEditor($this->position, $frontFace);
209
210 return true;
211 }
212
213 private function interactsFront(Vector3 $hitboxCenter, Vector3 $playerPosition, float $signFacingDegrees) : bool{
214 $playerCenterDiffX = $playerPosition->x - $hitboxCenter->x;
215 $playerCenterDiffZ = $playerPosition->z - $hitboxCenter->z;
216
217 $f1 = rad2deg(atan2($playerCenterDiffZ, $playerCenterDiffX)) - 90.0;
218
219 $rotationDiff = $signFacingDegrees - $f1;
220 $rotation = fmod($rotationDiff + 180.0, 360.0) - 180.0; // Normalize to [-180, 180]
221 return abs($rotation) <= 90.0;
222 }
223
227 protected function getHitboxCenter() : Vector3{
228 return $this->position->add(0.5, 0.5, 0.5);
229 }
230
234 protected function getFacingDegrees() : float{
235 return 0;
236 }
237
243 public function getText() : SignText{
244 return $this->text;
245 }
246
252 public function setText(SignText $text) : self{
253 $this->text = $text;
254 return $this;
255 }
256
257 public function getFaceText(bool $frontFace) : SignText{
258 return $frontFace ? $this->text : $this->backText;
259 }
260
262 public function setFaceText(bool $frontFace, SignText $text) : self{
263 $frontFace ? $this->text = $text : $this->backText = $text;
264 return $this;
265 }
266
270 public function isWaxed() : bool{ return $this->waxed; }
271
273 public function setWaxed(bool $waxed) : self{
274 $this->waxed = $waxed;
275 return $this;
276 }
277
283 public function getEditorEntityRuntimeId() : ?int{ return $this->editorEntityRuntimeId; }
284
286 public function setEditorEntityRuntimeId(?int $editorEntityRuntimeId) : self{
287 $this->editorEntityRuntimeId = $editorEntityRuntimeId;
288 return $this;
289 }
290
295 public function updateText(Player $author, SignText $text) : bool{
296 return $this->updateFaceText($author, true, $text);
297 }
298
305 public function updateFaceText(Player $author, bool $frontFace, SignText $text) : bool{
306 $size = 0;
307 foreach($text->getLines() as $line){
308 $size += strlen($line);
309 }
310 if($size > 1000){
311 throw new \UnexpectedValueException($author->getName() . " tried to write $size bytes of text onto a sign (bigger than max 1000)");
312 }
313 $oldText = $this->getFaceText($frontFace);
314 $ev = new SignChangeEvent($this, $author, new SignText(array_map(function(string $line) : string{
315 return TextFormat::clean($line, false);
316 }, $text->getLines()), $oldText->getBaseColor(), $oldText->isGlowing()), $frontFace);
317 if($this->waxed || $this->editorEntityRuntimeId !== $author->getId()){
318 $ev->cancel();
319 }
320 $ev->call();
321 if(!$ev->isCancelled()){
322 $this->setFaceText($frontFace, $ev->getNewText());
323 $this->setEditorEntityRuntimeId(null);
324 $this->position->getWorld()->setBlock($this->position, $this);
325 return true;
326 }
327
328 return false;
329 }
330
331 public function asItem() : Item{
332 return ($this->asItemCallback)();
333 }
334
335 public function getFuelTime() : int{
336 return $this->woodType->isFlammable() ? 200 : 0;
337 }
338}
setEditorEntityRuntimeId(?int $editorEntityRuntimeId)
Definition BaseSign.php:286
getSupportType(Facing $facing)
Definition BaseSign.php:111
updateText(Player $author, SignText $text)
Definition BaseSign.php:295
onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player=null, array &$returnedItems=[])
Definition BaseSign.php:173
place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player=null)
Definition BaseSign.php:123
updateFaceText(Player $author, bool $frontFace, SignText $text)
Definition BaseSign.php:305
setFaceText(bool $frontFace, SignText $text)
Definition BaseSign.php:262
setText(SignText $text)
Definition BaseSign.php:252
__construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo, WoodType $woodType, \Closure $asItemCallback)
Definition BaseSign.php:68