PocketMine-MP 5.33.2 git-1133d49c924b4358c79d44eeb97dcbf56cb4d1eb
Loading...
Searching...
No Matches
BaseRail.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
32use function array_reverse;
33use function array_search;
34use function array_shift;
35use function count;
36use function in_array;
37
38abstract class BaseRail extends Flowable{
39
40 public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
41 if($blockReplace->getAdjacentSupportType(Facing::DOWN)->hasEdgeSupport()){
42 return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
43 }
44
45 return false;
46 }
47
48 public function onPostPlace() : void{
49 $this->tryReconnect();
50 }
51
57 protected static function searchState(array $connections, array $lookup) : ?int{
58 $shape = array_search($connections, $lookup, true);
59 if($shape === false){
60 $shape = array_search(array_reverse($connections), $lookup, true);
61 }
62 return $shape === false ? null : $shape;
63 }
64
72 abstract protected function setShapeFromConnections(array $connections) : void;
73
79 abstract protected function getCurrentShapeConnections() : array;
80
86 private function getConnectedDirections() : array{
88 $connections = [];
89
91 foreach($this->getCurrentShapeConnections() as $connection){
92 $connectionFace = Facing::from($connection & ~RailConnectionInfo::FLAG_ASCEND);
93 $other = $this->getSide($connectionFace);
94 $otherConnection = Facing::opposite($connectionFace)->value;
95
96 if(($connection & RailConnectionInfo::FLAG_ASCEND) !== 0){
97 $other = $other->getSide(Facing::UP);
98
99 }elseif(!($other instanceof BaseRail)){ //check for rail sloping up to meet this one
100 $other = $other->getSide(Facing::DOWN);
101 $otherConnection |= RailConnectionInfo::FLAG_ASCEND;
102 }
103
104 if(
105 $other instanceof BaseRail &&
106 in_array($otherConnection, $other->getCurrentShapeConnections(), true)
107 ){
108 $connections[] = $connection;
109 }
110 }
111
112 return $connections;
113 }
114
121 private function getPossibleConnectionDirections(array $constraints) : array{
122 switch(count($constraints)){
123 case 0:
124 //No constraints, can connect in any direction
125 $possible = [
126 Facing::NORTH->value => true,
127 Facing::SOUTH->value => true,
128 Facing::WEST->value => true,
129 Facing::EAST->value => true
130 ];
131 foreach($possible as $p => $_){
132 $possible[$p | RailConnectionInfo::FLAG_ASCEND] = true;
133 }
134
135 return $possible;
136 case 1:
137 return $this->getPossibleConnectionDirectionsOneConstraint(array_shift($constraints));
138 case 2:
139 return [];
140 default:
141 throw new \InvalidArgumentException("Expected at most 2 constraints, got " . count($constraints));
142 }
143 }
144
149 protected function getPossibleConnectionDirectionsOneConstraint(int $constraint) : array{
150 $opposite = Facing::opposite(Facing::from($constraint & ~RailConnectionInfo::FLAG_ASCEND));
151
152 $possible = [$opposite->value => true];
153
154 if(($constraint & RailConnectionInfo::FLAG_ASCEND) === 0){
155 //We can slope the other way if this connection isn't already a slope
156 $possible[$opposite->value | RailConnectionInfo::FLAG_ASCEND] = true;
157 }
158
159 return $possible;
160 }
161
162 private function tryReconnect() : void{
163 $thisConnections = $this->getConnectedDirections();
164 $changed = false;
165
166 $world = $this->position->getWorld();
167 do{
168 $possible = $this->getPossibleConnectionDirections($thisConnections);
169 $continue = false;
170
171 foreach($possible as $thisSide => $_){
172 $thisSideEnum = Facing::from($thisSide & ~RailConnectionInfo::FLAG_ASCEND);
173 $otherSide = Facing::opposite($thisSideEnum)->value;
174
175 $other = $this->getSide($thisSideEnum);
176
177 if(($thisSide & RailConnectionInfo::FLAG_ASCEND) !== 0){
178 $other = $other->getSide(Facing::UP);
179
180 }elseif(!($other instanceof BaseRail)){ //check if other rails can slope up to meet this one
181 $other = $other->getSide(Facing::DOWN);
182 $otherSide |= RailConnectionInfo::FLAG_ASCEND;
183 }
184
185 if(!($other instanceof BaseRail) || count($otherConnections = $other->getConnectedDirections()) >= 2){
186 //we can only connect to a rail that has less than 2 connections
187 continue;
188 }
189
190 $otherPossible = $other->getPossibleConnectionDirections($otherConnections);
191
192 if(isset($otherPossible[$otherSide])){
193 $otherConnections[] = $otherSide;
194 $other->setConnections($otherConnections);
195 $world->setBlock($other->position, $other);
196
197 $changed = true;
198 $thisConnections[] = $thisSide;
199 $continue = count($thisConnections) < 2;
200
201 break; //force recomputing possible directions, since this connection could invalidate others
202 }
203 }
204 }while($continue);
205
206 if($changed){
207 $this->setConnections($thisConnections);
208 $world->setBlock($this->position, $this);
209 }
210 }
211
215 private function setConnections(array $connections) : void{
216 if(count($connections) === 1){
217 $connections[] = Facing::opposite(Facing::from($connections[0] & ~RailConnectionInfo::FLAG_ASCEND))->value;
218 }elseif(count($connections) !== 2){
219 throw new \InvalidArgumentException("Expected exactly 2 connections, got " . count($connections));
220 }
221
222 $this->setShapeFromConnections($connections);
223 }
224
225 public function onNearbyBlockChange() : void{
226 $world = $this->position->getWorld();
227 if(!$this->getAdjacentSupportType(Facing::DOWN)->hasEdgeSupport()){
228 $world->useBreakOn($this->position);
229 }else{
230 foreach($this->getCurrentShapeConnections() as $connection){
231 if(($connection & RailConnectionInfo::FLAG_ASCEND) !== 0 && !$this->getSide(Facing::from($connection & ~RailConnectionInfo::FLAG_ASCEND))->getSupportType(Facing::UP)->hasEdgeSupport()){
232 $world->useBreakOn($this->position);
233 break;
234 }
235 }
236 }
237 }
238}
setShapeFromConnections(array $connections)
static searchState(array $connections, array $lookup)
Definition BaseRail.php:57
getPossibleConnectionDirectionsOneConstraint(int $constraint)
Definition BaseRail.php:149
place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player=null)
Definition BaseRail.php:40