PageRenderTime 43ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/pocketmine/block/Liquid.php

https://gitlab.com/Skull3x/ClearSky
PHP | 437 lines | 349 code | 84 blank | 4 comment | 57 complexity | a33583cb5169cb45215e996eed5c410c MD5 | raw file
  1. <?php
  2. namespace pocketmine\block;
  3. use pocketmine\entity\Entity;
  4. use pocketmine\item\Item;
  5. use pocketmine\level\Level;
  6. use pocketmine\math\Vector3;
  7. abstract class Liquid extends Transparent{
  8. /** @var Vector3 */
  9. private $temporalVector = null;
  10. public function hasEntityCollision(){
  11. return true;
  12. }
  13. public function isBreakable(Item $item){
  14. return false;
  15. }
  16. public function canBeReplaced(){
  17. return true;
  18. }
  19. public function isSolid(){
  20. return false;
  21. }
  22. public $adjacentSources = 0;
  23. public $isOptimalFlowDirection = [0, 0, 0, 0];
  24. public $flowCost = [0, 0, 0, 0];
  25. public function getFluidHeightPercent(){
  26. $d = $this->meta;
  27. if($d >= 8){
  28. $d = 0;
  29. }
  30. return ($d + 1) / 9;
  31. }
  32. protected function getFlowDecay(Vector3 $pos){
  33. if(!($pos instanceof Block)){
  34. $pos = $this->getLevel()->getBlock($pos);
  35. }
  36. if($pos->getId() !== $this->getId()){
  37. return -1;
  38. }else{
  39. return $pos->getDamage();
  40. }
  41. }
  42. protected function getEffectiveFlowDecay(Vector3 $pos){
  43. if(!($pos instanceof Block)){
  44. $pos = $this->getLevel()->getBlock($pos);
  45. }
  46. if($pos->getId() !== $this->getId()){
  47. return -1;
  48. }
  49. $decay = $pos->getDamage();
  50. if($decay >= 8){
  51. $decay = 0;
  52. }
  53. return $decay;
  54. }
  55. public function getFlowVector(){
  56. $vector = new Vector3(0, 0, 0);
  57. if($this->temporalVector === null){
  58. $this->temporalVector = new Vector3(0, 0, 0);
  59. }
  60. $decay = $this->getEffectiveFlowDecay($this);
  61. for($j = 0; $j < 4; ++$j){
  62. $x = $this->x;
  63. $y = $this->y;
  64. $z = $this->z;
  65. if($j === 0){
  66. --$x;
  67. }elseif($j === 1){
  68. ++$x;
  69. }elseif($j === 2){
  70. --$z;
  71. }elseif($j === 3){
  72. ++$z;
  73. }
  74. $sideBlock = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z));
  75. $blockDecay = $this->getEffectiveFlowDecay($sideBlock);
  76. if($blockDecay < 0){
  77. if(!$sideBlock->canBeFlowedInto()){
  78. continue;
  79. }
  80. $blockDecay = $this->getEffectiveFlowDecay($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z)));
  81. if($blockDecay >= 0){
  82. $realDecay = $blockDecay - ($decay - 8);
  83. $vector->x += ($sideBlock->x - $this->x) * $realDecay;
  84. $vector->y += ($sideBlock->y - $this->y) * $realDecay;
  85. $vector->z += ($sideBlock->z - $this->z) * $realDecay;
  86. }
  87. continue;
  88. }else{
  89. $realDecay = $blockDecay - $decay;
  90. $vector->x += ($sideBlock->x - $this->x) * $realDecay;
  91. $vector->y += ($sideBlock->y - $this->y) * $realDecay;
  92. $vector->z += ($sideBlock->z - $this->z) * $realDecay;
  93. }
  94. }
  95. if($this->getDamage() >= 8){
  96. $falling = false;
  97. if(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1))->canBeFlowedInto()){
  98. $falling = true;
  99. }elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1))->canBeFlowedInto()){
  100. $falling = true;
  101. }elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z))->canBeFlowedInto()){
  102. $falling = true;
  103. }elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z))->canBeFlowedInto()){
  104. $falling = true;
  105. }elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z - 1))->canBeFlowedInto()){
  106. $falling = true;
  107. }elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z + 1))->canBeFlowedInto()){
  108. $falling = true;
  109. }elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y + 1, $this->z))->canBeFlowedInto()){
  110. $falling = true;
  111. }elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y + 1, $this->z))->canBeFlowedInto()){
  112. $falling = true;
  113. }
  114. if($falling){
  115. $vector = $vector->normalize()->add(0, -6, 0);
  116. }
  117. }
  118. return $vector->normalize();
  119. }
  120. public function addVelocityToEntity(Entity $entity, Vector3 $vector){
  121. $flow = $this->getFlowVector();
  122. $vector->x += $flow->x;
  123. $vector->y += $flow->y;
  124. $vector->z += $flow->z;
  125. }
  126. public function tickRate(){
  127. if($this instanceof Water){
  128. return 5;
  129. }elseif($this instanceof Lava){
  130. return 30;
  131. }
  132. return 0;
  133. }
  134. public function onUpdate($type){
  135. if($type === Level::BLOCK_UPDATE_NORMAL){
  136. $this->checkForHarden();
  137. $this->getLevel()->scheduleUpdate($this, $this->tickRate());
  138. }elseif($type === Level::BLOCK_UPDATE_SCHEDULED){
  139. if($this->temporalVector === null){
  140. $this->temporalVector = new Vector3(0, 0, 0);
  141. }
  142. $decay = $this->getFlowDecay($this);
  143. $multiplier = $this instanceof Lava ? 2 : 1;
  144. $flag = true;
  145. if($decay > 0){
  146. $smallestFlowDecay = -100;
  147. $this->adjacentSources = 0;
  148. $smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1)), $smallestFlowDecay);
  149. $smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1)), $smallestFlowDecay);
  150. $smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z)), $smallestFlowDecay);
  151. $smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z)), $smallestFlowDecay);
  152. $k = $smallestFlowDecay + $multiplier;
  153. if($k >= 8 or $smallestFlowDecay < 0){
  154. $k = -1;
  155. }
  156. if(($topFlowDecay = $this->getFlowDecay($this->level->getBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z))))) >= 0){
  157. if($topFlowDecay >= 8){
  158. $k = $topFlowDecay;
  159. }else{
  160. $k = $topFlowDecay | 0x08;
  161. }
  162. }
  163. if($this->adjacentSources >= 2 and $this instanceof Water){
  164. $bottomBlock = $this->level->getBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y - 1, $this->z)));
  165. if($bottomBlock->isSolid()){
  166. $k = 0;
  167. }elseif($bottomBlock instanceof Water and $bottomBlock->getDamage() === 0){
  168. $k = 0;
  169. }
  170. }
  171. if($this instanceof Lava and $decay < 8 and $k < 8 and $k > 1 and mt_rand(0, 4) !== 0){
  172. $k = $decay;
  173. $flag = false;
  174. }
  175. if($k !== $decay){
  176. $decay = $k;
  177. if($decay < 0){
  178. $this->getLevel()->setBlock($this, new Air(), true);
  179. }else{
  180. $this->getLevel()->setBlock($this, Block::get($this->id, $decay), true);
  181. $this->getLevel()->scheduleUpdate($this, $this->tickRate());
  182. }
  183. }elseif($flag){
  184. //$this->getLevel()->scheduleUpdate($this, $this->tickRate());
  185. //$this->updateFlow();
  186. }
  187. }else{
  188. //$this->updateFlow();
  189. }
  190. $bottomBlock = $this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y - 1, $this->z));
  191. if($bottomBlock->canBeFlowedInto() or $bottomBlock instanceof Liquid){
  192. if($this instanceof Lava and $bottomBlock instanceof Water){
  193. $this->getLevel()->setBlock($bottomBlock, Block::get(Item::STONE), true);
  194. return;
  195. }
  196. if($decay >= 8){
  197. $this->getLevel()->setBlock($bottomBlock, Block::get($this->id, $decay), true);
  198. $this->getLevel()->scheduleUpdate($bottomBlock, $this->tickRate());
  199. }else{
  200. $this->getLevel()->setBlock($bottomBlock, Block::get($this->id, $decay + 8), true);
  201. $this->getLevel()->scheduleUpdate($bottomBlock, $this->tickRate());
  202. }
  203. }elseif($decay >= 0 and ($decay === 0 or !$bottomBlock->canBeFlowedInto())){
  204. $flags = $this->getOptimalFlowDirections();
  205. $l = $decay + $multiplier;
  206. if($decay >= 8){
  207. $l = 1;
  208. }
  209. if($l >= 8){
  210. $this->checkForHarden();
  211. return;
  212. }
  213. if($flags[0]){
  214. $this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z)), $l);
  215. }
  216. if($flags[1]){
  217. $this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z)), $l);
  218. }
  219. if($flags[2]){
  220. $this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1)), $l);
  221. }
  222. if($flags[3]){
  223. $this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1)), $l);
  224. }
  225. }
  226. $this->checkForHarden();
  227. }
  228. }
  229. private function flowIntoBlock(Block $block, $newFlowDecay){
  230. if($block->canBeFlowedInto()){
  231. if($block->getId() > 0){
  232. $this->getLevel()->useBreakOn($block);
  233. }
  234. $this->getLevel()->setBlock($block, Block::get($this->getId(), $newFlowDecay), true);
  235. $this->getLevel()->scheduleUpdate($block, $this->tickRate());
  236. }
  237. }
  238. private function calculateFlowCost(Block $block, $accumulatedCost, $previousDirection){
  239. $cost = 1000;
  240. for($j = 0; $j < 4; ++$j){
  241. if(
  242. ($j === 0 and $previousDirection === 1) or
  243. ($j === 1 and $previousDirection === 0) or
  244. ($j === 2 and $previousDirection === 3) or
  245. ($j === 3 and $previousDirection === 2)
  246. ){
  247. $x = $block->x;
  248. $y = $block->y;
  249. $z = $block->z;
  250. if($j === 0){
  251. --$x;
  252. }elseif($j === 1){
  253. ++$x;
  254. }elseif($j === 2){
  255. --$z;
  256. }elseif($j === 3){
  257. ++$z;
  258. }
  259. $blockSide = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z));
  260. if(!$blockSide->canBeFlowedInto() and !($blockSide instanceof Liquid)){
  261. continue;
  262. }elseif($blockSide instanceof Liquid and $blockSide->getDamage() === 0){
  263. continue;
  264. }elseif($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z))->canBeFlowedInto()){
  265. return $accumulatedCost;
  266. }
  267. if($accumulatedCost >= 4){
  268. continue;
  269. }
  270. $realCost = $this->calculateFlowCost($blockSide, $accumulatedCost + 1, $j);
  271. if($realCost < $cost){
  272. $cost = $realCost;
  273. }
  274. }
  275. }
  276. return $cost;
  277. }
  278. public function getHardness(){
  279. return 100;
  280. }
  281. private function getOptimalFlowDirections(){
  282. if($this->temporalVector === null){
  283. $this->temporalVector = new Vector3(0, 0, 0);
  284. }
  285. for($j = 0; $j < 4; ++$j){
  286. $this->flowCost[$j] = 1000;
  287. $x = $this->x;
  288. $y = $this->y;
  289. $z = $this->z;
  290. if($j === 0){
  291. --$x;
  292. }elseif($j === 1){
  293. ++$x;
  294. }elseif($j === 2){
  295. --$z;
  296. }elseif($j === 3){
  297. ++$z;
  298. }
  299. $block = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z));
  300. if(!$block->canBeFlowedInto() and !($block instanceof Liquid)){
  301. continue;
  302. }elseif($block instanceof Liquid and $block->getDamage() === 0){
  303. continue;
  304. }elseif($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z))->canBeFlowedInto()){
  305. $this->flowCost[$j] = 0;
  306. }else{
  307. $this->flowCost[$j] = $this->calculateFlowCost($block, 1, $j);
  308. }
  309. }
  310. $minCost = $this->flowCost[0];
  311. for($i = 1; $i < 4; ++$i){
  312. if($this->flowCost[$i] < $minCost){
  313. $minCost = $this->flowCost[$i];
  314. }
  315. }
  316. for($i = 0; $i < 4; ++$i){
  317. $this->isOptimalFlowDirection[$i] = ($this->flowCost[$i] === $minCost);
  318. }
  319. return $this->isOptimalFlowDirection;
  320. }
  321. private function getSmallestFlowDecay(Vector3 $pos, $decay){
  322. $blockDecay = $this->getFlowDecay($pos);
  323. if($blockDecay < 0){
  324. return $decay;
  325. }elseif($blockDecay === 0){
  326. ++$this->adjacentSources;
  327. }elseif($blockDecay >= 8){
  328. $blockDecay = 0;
  329. }
  330. return ($decay >= 0 && $blockDecay >= $decay) ? $decay : $blockDecay;
  331. }
  332. private function checkForHarden(){
  333. if($this instanceof Lava){
  334. $colliding = false;
  335. for($side = 0; $side <= 5 and !$colliding; ++$side){
  336. $colliding = $this->getSide($side) instanceof Water;
  337. }
  338. if($colliding){
  339. if($this->getDamage() === 0){
  340. $this->getLevel()->setBlock($this, Block::get(Item::OBSIDIAN), true);
  341. }elseif($this->getDamage() <= 4){
  342. $this->getLevel()->setBlock($this, Block::get(Item::COBBLESTONE), true);
  343. }
  344. }
  345. }
  346. }
  347. public function getBoundingBox(){
  348. return null;
  349. }
  350. public function getDrops(Item $item){
  351. return [];
  352. }
  353. }