PageRenderTime 33ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/src/pocketmine/level/Explosion.php

https://gitlab.com/wesleyvanneck/ImagicalMine
PHP | 277 lines | 187 code | 38 blank | 52 comment | 22 complexity | 0fa97c1a0503c3990c38c07623b0fb3e MD5 | raw file
  1. <?php
  2. /**
  3. * src/pocketmine/level/Explosion.php
  4. *
  5. * @package default
  6. */
  7. /*
  8. *
  9. * _ _ _ __ __ _
  10. * (_) (_) | | \/ (_)
  11. * _ _ __ ___ __ _ __ _ _ ___ __ _| | \ / |_ _ __ ___
  12. * | | '_ ` _ \ / _` |/ _` | |/ __/ _` | | |\/| | | '_ \ / _ \
  13. * | | | | | | | (_| | (_| | | (_| (_| | | | | | | | | | __/
  14. * |_|_| |_| |_|\__,_|\__, |_|\___\__,_|_|_| |_|_|_| |_|\___|
  15. * __/ |
  16. * |___/
  17. *
  18. * This program is a third party build by ImagicalMine.
  19. *
  20. * PocketMine is free software: you can redistribute it and/or modify
  21. * it under the terms of the GNU Lesser General Public License as published by
  22. * the Free Software Foundation, either version 3 of the License, or
  23. * (at your option) any later version.
  24. *
  25. * @author ImagicalMine Team
  26. * @link http://forums.imagicalcorp.ml/
  27. *
  28. *
  29. */
  30. namespace pocketmine\level;
  31. use pocketmine\block\Block;
  32. use pocketmine\entity\Entity;
  33. use pocketmine\event\entity\EntityDamageByBlockEvent;
  34. use pocketmine\event\entity\EntityDamageByEntityEvent;
  35. use pocketmine\event\entity\EntityDamageEvent;
  36. use pocketmine\event\entity\EntityExplodeEvent;
  37. use pocketmine\event\block\BlockUpdateEvent;
  38. use pocketmine\item\Item;
  39. use pocketmine\math\AxisAlignedBB;
  40. use pocketmine\math\Math;
  41. use pocketmine\math\Vector3;
  42. use pocketmine\nbt\tag\ListTag;
  43. use pocketmine\nbt\tag\DoubleTag;
  44. use pocketmine\nbt\tag\FloatTag;
  45. use pocketmine\nbt\tag\ByteTag;
  46. use pocketmine\nbt\tag\CompoundTag;
  47. use pocketmine\network\protocol\ExplodePacket;
  48. use pocketmine\block\Redstone;
  49. use pocketmine\block\RedstoneTools;
  50. use pocketmine\utils\Random;
  51. class Explosion
  52. {
  53. private $rays = 16; //Rays
  54. public $level;
  55. public $source;
  56. public $size;
  57. /**
  58. *
  59. * @var Block[]
  60. */
  61. public $affectedBlocks = [];
  62. public $stepLen = 0.3;
  63. /** @var Entity|Block */
  64. private $what;
  65. /**
  66. *
  67. * @param Position $center
  68. * @param unknown $size
  69. * @param unknown $what (optional)
  70. */
  71. public function __construct(Position $center, $size, $what = null)
  72. {
  73. $this->level = $center->getLevel();
  74. $this->source = $center;
  75. $this->size = max($size, 0);
  76. $this->what = $what;
  77. }
  78. /**
  79. *
  80. * @deprecated
  81. * @return bool
  82. */
  83. public function explode()
  84. {
  85. if ($this->explodeA()) {
  86. return $this->explodeB();
  87. }
  88. return false;
  89. }
  90. /**
  91. *
  92. * @return bool
  93. */
  94. public function explodeA()
  95. {
  96. if ($this->size < 0.1) {
  97. return false;
  98. }
  99. $vector = new Vector3(0, 0, 0);
  100. $vBlock = new Vector3(0, 0, 0);
  101. $mRays = intval($this->rays - 1);
  102. for ($i = 0; $i < $this->rays; ++$i) {
  103. for ($j = 0; $j < $this->rays; ++$j) {
  104. for ($k = 0; $k < $this->rays; ++$k) {
  105. if ($i === 0 or $i === $mRays or $j === 0 or $j === $mRays or $k === 0 or $k === $mRays) {
  106. $vector->setComponents($i / $mRays * 2 - 1, $j / $mRays * 2 - 1, $k / $mRays * 2 - 1);
  107. $vector->setComponents(($vector->x / ($len = $vector->length())) * $this->stepLen, ($vector->y / $len) * $this->stepLen, ($vector->z / $len) * $this->stepLen);
  108. $pointerX = $this->source->x;
  109. $pointerY = $this->source->y;
  110. $pointerZ = $this->source->z;
  111. for ($blastForce = $this->size * (mt_rand(700, 1300) / 1000); $blastForce > 0; $blastForce -= $this->stepLen * 0.75) {
  112. $x = (int) $pointerX;
  113. $y = (int) $pointerY;
  114. $z = (int) $pointerZ;
  115. $vBlock->x = $pointerX >= $x ? $x : $x - 1;
  116. $vBlock->y = $pointerY >= $y ? $y : $y - 1;
  117. $vBlock->z = $pointerZ >= $z ? $z : $z - 1;
  118. if ($vBlock->y < 0 or $vBlock->y > 127) {
  119. break;
  120. }
  121. $block = $this->level->getBlock($vBlock);
  122. if ($block->getId() !== 0) {
  123. $blastForce -= ($block->getResistance() / 5 + 0.3) * $this->stepLen;
  124. if ($blastForce > 0) {
  125. if (!isset($this->affectedBlocks[$index = Level::blockHash($block->x, $block->y, $block->z)])) {
  126. $this->affectedBlocks[$index] = $block;
  127. }
  128. }
  129. }
  130. $pointerX += $vector->x;
  131. $pointerY += $vector->y;
  132. $pointerZ += $vector->z;
  133. }
  134. }
  135. }
  136. }
  137. }
  138. return true;
  139. }
  140. /**
  141. *
  142. * @return unknown
  143. */
  144. public function explodeB()
  145. {
  146. $send = [];
  147. $updateBlocks = [];
  148. $source = (new Vector3($this->source->x, $this->source->y, $this->source->z))->floor();
  149. $yield = (1 / $this->size) * 100;
  150. if ($this->what instanceof Entity) {
  151. $this->level->getServer()->getPluginManager()->callEvent($ev = new EntityExplodeEvent($this->what, $this->source, $this->affectedBlocks, $yield));
  152. if ($ev->isCancelled()) {
  153. return false;
  154. } else {
  155. $yield = $ev->getYield();
  156. $this->affectedBlocks = $ev->getBlockList();
  157. }
  158. }
  159. $explosionSize = $this->size * 2;
  160. $minX = Math::floorFloat($this->source->x - $explosionSize - 1);
  161. $maxX = Math::ceilFloat($this->source->x + $explosionSize + 1);
  162. $minY = Math::floorFloat($this->source->y - $explosionSize - 1);
  163. $maxY = Math::ceilFloat($this->source->y + $explosionSize + 1);
  164. $minZ = Math::floorFloat($this->source->z - $explosionSize - 1);
  165. $maxZ = Math::ceilFloat($this->source->z + $explosionSize + 1);
  166. $explosionBB = new AxisAlignedBB($minX, $minY, $minZ, $maxX, $maxY, $maxZ);
  167. $list = $this->level->getNearbyEntities($explosionBB, $this->what instanceof Entity ? $this->what : null);
  168. foreach ($list as $entity) {
  169. $distance = $entity->distance($this->source) / $explosionSize;
  170. if ($distance <= 1) {
  171. $motion = $entity->subtract($this->source)->normalize();
  172. $impact = (1 - $distance) * ($exposure = 1);
  173. $damage = (int) ((($impact * $impact + $impact) / 2) * 8 * $explosionSize + 1);
  174. if ($this->what instanceof Entity) {
  175. $ev = new EntityDamageByEntityEvent($this->what, $entity, EntityDamageEvent::CAUSE_ENTITY_EXPLOSION, $damage);
  176. } elseif ($this->what instanceof Block) {
  177. $ev = new EntityDamageByBlockEvent($this->what, $entity, EntityDamageEvent::CAUSE_BLOCK_EXPLOSION, $damage);
  178. } else {
  179. $ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_BLOCK_EXPLOSION, $damage);
  180. }
  181. $entity->attack($ev->getFinalDamage(), $ev);
  182. $entity->setMotion($motion->multiply($impact));
  183. }
  184. }
  185. $air = Item::get(Item::AIR);
  186. foreach ($this->affectedBlocks as $block) {
  187. if ($block->getId() === Block::TNT) {
  188. $mot = (new Random())->nextSignedFloat() * M_PI * 2;
  189. $tnt = Entity::createEntity("PrimedTNT", $this->level->getChunk($block->x >> 4, $block->z >> 4), new CompoundTag("", [
  190. "Pos" => new ListTag("Pos", [
  191. new DoubleTag("", $block->x + 0.5),
  192. new DoubleTag("", $block->y),
  193. new DoubleTag("", $block->z + 0.5)
  194. ]),
  195. "Motion" => new ListTag("Motion", [
  196. new DoubleTag("", -sin($mot) * 0.02),
  197. new DoubleTag("", 0.2),
  198. new DoubleTag("", -cos($mot) * 0.02)
  199. ]),
  200. "Rotation" => new ListTag("Rotation", [
  201. new FloatTag("", 0),
  202. new FloatTag("", 0)
  203. ]),
  204. "Fuse" => new ByteTag("Fuse", mt_rand(10, 30))
  205. ]));
  206. $tnt->spawnToAll();
  207. } elseif (mt_rand(0, 100) < $yield) {
  208. foreach ($block->getDrops($air) as $drop) {
  209. $this->level->dropItem($block->add(0.5, 0.5, 0.5), Item::get(...$drop));
  210. }
  211. }
  212. $this->level->setBlockIdAt($block->x, $block->y, $block->z, 0);
  213. $pos = new Vector3($block->x, $block->y, $block->z);
  214. for ($side = 0; $side < 5; $side++) {
  215. $sideBlock = $pos->getSide($side);
  216. if (!isset($this->affectedBlocks[$index = Level::blockHash($sideBlock->x, $sideBlock->y, $sideBlock->z)]) and !isset($updateBlocks[$index])) {
  217. $this->level->getServer()->getPluginManager()->callEvent($ev = new BlockUpdateEvent($this->level->getBlock($sideBlock)));
  218. if (!$ev->isCancelled()) {
  219. $targetBlock=$ev->getBlock();
  220. $targetBlock->onUpdate(Level::BLOCK_UPDATE_NORMAL);
  221. if ($targetBlock instanceof Redstone) {
  222. $targetBlock->onRedstoneUpdate(Level::REDSTONE_UPDATE_BREAK, 0);
  223. }
  224. }
  225. $updateBlocks[$index] = true;
  226. }
  227. }
  228. $send[] = new Vector3($block->x - $source->x, $block->y - $source->y, $block->z - $source->z);
  229. }
  230. $pk = new ExplodePacket();
  231. $pk->x = $this->source->x;
  232. $pk->y = $this->source->y;
  233. $pk->z = $this->source->z;
  234. $pk->radius = $this->size;
  235. $pk->records = $send;
  236. $this->level->addChunkPacket($source->x >> 4, $source->z >> 4, $pk);
  237. return true;
  238. }
  239. }