PocketMine-MP 5.23.3 git-976fc63567edab7a6fb6aeae739f43cf9fe57de4
Loading...
Searching...
No Matches
Farmland.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
35use function intdiv;
36
37class Farmland extends Transparent{
38 public const MAX_WETNESS = 7;
39
40 private const WATER_SEARCH_HORIZONTAL_LENGTH = 9;
41
42 private const WATER_SEARCH_VERTICAL_LENGTH = 2;
43
44 private const WATER_POSITION_INDEX_UNKNOWN = -1;
46 private const WATER_POSITION_INDICES_TOTAL = (self::WATER_SEARCH_HORIZONTAL_LENGTH ** 2) * 2;
47
48 protected int $wetness = 0; //"moisture" blockstate property in PC
49
63 private int $waterPositionIndex = self::WATER_POSITION_INDEX_UNKNOWN;
64
65 protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
66 $w->boundedIntAuto(0, self::MAX_WETNESS, $this->wetness);
67 $w->boundedIntAuto(-1, self::WATER_POSITION_INDICES_TOTAL - 1, $this->waterPositionIndex);
68 }
69
70 public function getWetness() : int{ return $this->wetness; }
71
73 public function setWetness(int $wetness) : self{
74 if($wetness < 0 || $wetness > self::MAX_WETNESS){
75 throw new \InvalidArgumentException("Wetness must be in range 0 ... " . self::MAX_WETNESS);
76 }
77 $this->wetness = $wetness;
78 return $this;
79 }
80
84 public function getWaterPositionIndex() : int{ return $this->waterPositionIndex; }
85
89 public function setWaterPositionIndex(int $waterPositionIndex) : self{
90 if($waterPositionIndex < -1 || $waterPositionIndex >= self::WATER_POSITION_INDICES_TOTAL){
91 throw new \InvalidArgumentException("Water XZ index must be in range -1 ... " . (self::WATER_POSITION_INDICES_TOTAL - 1));
92 }
93 $this->waterPositionIndex = $waterPositionIndex;
94 return $this;
95 }
96
97 protected function recalculateCollisionBoxes() : array{
98 return [AxisAlignedBB::one()->trim(Facing::UP, 1 / 16)];
99 }
100
101 public function onNearbyBlockChange() : void{
102 if($this->getSide(Facing::UP)->isSolid()){
103 $this->position->getWorld()->setBlock($this->position, VanillaBlocks::DIRT());
104 }
105 }
106
107 public function ticksRandomly() : bool{
108 return true;
109 }
110
111 public function onRandomTick() : void{
112 $world = $this->position->getWorld();
113
114 //this property may be updated by canHydrate() - track this so we know if we need to set the block again
115 $oldWaterPositionIndex = $this->waterPositionIndex;
116 $changed = false;
117
118 if(!$this->canHydrate()){
119 if($this->wetness > 0){
120 $event = new FarmlandHydrationChangeEvent($this, $this->wetness, $this->wetness - 1);
121 $event->call();
122 if(!$event->isCancelled()){
123 $this->wetness = $event->getNewHydration();
124 $world->setBlock($this->position, $this, false);
125 $changed = true;
126 }
127 }else{
128 $world->setBlock($this->position, VanillaBlocks::DIRT());
129 $changed = true;
130 }
131 }elseif($this->wetness < self::MAX_WETNESS){
132 $event = new FarmlandHydrationChangeEvent($this, $this->wetness, self::MAX_WETNESS);
133 $event->call();
134 if(!$event->isCancelled()){
135 $this->wetness = $event->getNewHydration();
136 $world->setBlock($this->position, $this, false);
137 $changed = true;
138 }
139 }
140
141 if(!$changed && $oldWaterPositionIndex !== $this->waterPositionIndex){
142 //ensure the water square index is saved regardless of whether anything else happened
143 $world->setBlock($this->position, $this, false);
144 }
145 }
146
147 public function onEntityLand(Entity $entity) : ?float{
148 if($entity instanceof Living && Utils::getRandomFloat() < $entity->getFallDistance() - 0.5){
149 $ev = new EntityTrampleFarmlandEvent($entity, $this);
150 $ev->call();
151 if(!$ev->isCancelled()){
152 $this->position->getWorld()->setBlock($this->position, VanillaBlocks::DIRT());
153 }
154 }
155 return null;
156 }
157
158 protected function canHydrate() : bool{
159 $world = $this->position->getWorld();
160
161 $startX = $this->position->getFloorX() - (int) (self::WATER_SEARCH_HORIZONTAL_LENGTH / 2);
162 $startY = $this->position->getFloorY();
163 $startZ = $this->position->getFloorZ() - (int) (self::WATER_SEARCH_HORIZONTAL_LENGTH / 2);
164
165 if($this->waterPositionIndex !== self::WATER_POSITION_INDEX_UNKNOWN){
166 $raw = $this->waterPositionIndex;
167 $x = $raw % self::WATER_SEARCH_HORIZONTAL_LENGTH;
168 $raw = intdiv($raw, self::WATER_SEARCH_HORIZONTAL_LENGTH);
169 $z = $raw % self::WATER_SEARCH_HORIZONTAL_LENGTH;
170 $raw = intdiv($raw, self::WATER_SEARCH_HORIZONTAL_LENGTH);
171 $y = $raw % self::WATER_SEARCH_VERTICAL_LENGTH;
172
173 if($world->getBlockAt($startX + $x, $startY + $y, $startZ + $z) instanceof Water){
174 return true;
175 }
176 }
177
178 //no water found at cached position - search the whole area
179 //y will increment after x/z have been exhausted, as usually water will be at the same Y as the farmland
180 for($y = 0; $y < self::WATER_SEARCH_VERTICAL_LENGTH; $y++){
181 for($x = 0; $x < self::WATER_SEARCH_HORIZONTAL_LENGTH; $x++){
182 for($z = 0; $z < self::WATER_SEARCH_HORIZONTAL_LENGTH; $z++){
183 if($world->getBlockAt($startX + $x, $startY + $y, $startZ + $z) instanceof Water){
184 $this->waterPositionIndex = $x + ($z * self::WATER_SEARCH_HORIZONTAL_LENGTH) + ($y * self::WATER_SEARCH_HORIZONTAL_LENGTH ** 2);
185 return true;
186 }
187 }
188 }
189 }
190
191 $this->waterPositionIndex = self::WATER_POSITION_INDEX_UNKNOWN;
192 return false;
193 }
194
195 public function getDropsForCompatibleTool(Item $item) : array{
196 return [
197 VanillaBlocks::DIRT()->asItem()
198 ];
199 }
200
201 public function getPickedItem(bool $addUserData = false) : Item{
202 return VanillaBlocks::DIRT()->asItem();
203 }
204}
setWetness(int $wetness)
Definition Farmland.php:73
getPickedItem(bool $addUserData=false)
Definition Farmland.php:201
onEntityLand(Entity $entity)
Definition Farmland.php:147
describeBlockOnlyState(RuntimeDataDescriber $w)
Definition Farmland.php:65
getDropsForCompatibleTool(Item $item)
Definition Farmland.php:195
boundedIntAuto(int $min, int $max, int &$value)