diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 5fd602a56..8536bea93 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -1656,6 +1656,12 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ } if($target instanceof Entity and $this->getGamemode() !== Player::VIEW and $this->blocked === false and $this->dead !== true and $target->dead !== true){ + if($target instanceof DroppedItem or $target instanceof Arrow){ + $this->kick("Attempting to attack an invalid entity"); + $this->server->getLogger()->warning("Player ". $this->getName() ." tried to attack an invalid entity"); + return; + } + $item = $this->inventory->getItemInHand(); $damageTable = [ Item::WOODEN_SWORD => 4, diff --git a/src/pocketmine/block/Block.php b/src/pocketmine/block/Block.php index 677d0b682..f5e4b4f1b 100644 --- a/src/pocketmine/block/Block.php +++ b/src/pocketmine/block/Block.php @@ -28,8 +28,10 @@ use pocketmine\entity\Villager; use pocketmine\entity\Zombie; use pocketmine\item\Item; use pocketmine\level\Level; +use pocketmine\level\MovingObjectPosition; use pocketmine\level\Position; use pocketmine\math\AxisAlignedBB; +use pocketmine\math\Vector3; use pocketmine\metadata\Metadatable; use pocketmine\metadata\MetadataValue; use pocketmine\Player; @@ -844,6 +846,88 @@ abstract class Block extends Position implements Metadatable{ ); } + public function calculateIntercept(Vector3 $pos1, Vector3 $pos2){ + $bb = $this->getBoundingBox(); + if($bb === null){ + return null; + } + + $v1 = $pos1->getIntermediateWithXValue($pos2, $bb->minX); + $v2 = $pos1->getIntermediateWithXValue($pos2, $bb->maxX); + $v3 = $pos1->getIntermediateWithYValue($pos2, $bb->minY); + $v4 = $pos1->getIntermediateWithYValue($pos2, $bb->maxY); + $v5 = $pos1->getIntermediateWithZValue($pos2, $bb->minZ); + $v6 = $pos1->getIntermediateWithZValue($pos2, $bb->maxZ); + + if($v1 !== null and !$bb->isVectorInYZ($v1)){ + $v1 = null; + } + + if($v2 !== null and !$bb->isVectorInYZ($v2)){ + $v2 = null; + } + + if($v3 !== null and !$bb->isVectorInXZ($v3)){ + $v3 = null; + } + + if($v4 !== null and !$bb->isVectorInXZ($v4)){ + $v4 = null; + } + + if($v5 !== null and !$bb->isVectorInXY($v5)){ + $v5 = null; + } + + if($v6 !== null and !$bb->isVectorInXY($v6)){ + $v6 = null; + } + + $vector = $v1; + + if($v2 !== null and ($vector === null or $pos1->distanceSquared($v2) < $pos1->distanceSquared($vector))){ + $vector = $v2; + } + + if($v3 !== null and ($vector === null or $pos1->distanceSquared($v3) < $pos1->distanceSquared($vector))){ + $vector = $v3; + } + + if($v4 !== null and ($vector === null or $pos1->distanceSquared($v4) < $pos1->distanceSquared($vector))){ + $vector = $v4; + } + + if($v5 !== null and ($vector === null or $pos1->distanceSquared($v5) < $pos1->distanceSquared($vector))){ + $vector = $v5; + } + + if($v6 !== null and ($vector === null or $pos1->distanceSquared($v6) < $pos1->distanceSquared($vector))){ + $vector = $v6; + } + + if($vector === null){ + return null; + } + + $f = -1; + + if($vector === $v1){ + $f = 4; + }elseif($vector === $v2){ + $f = 5; + }elseif($vector === $v3){ + $f = 0; + }elseif($vector === $v4){ + $f = 1; + }elseif($vector === $v5){ + $f = 2; + }elseif($vector === $v6){ + $f = 3; + } + + return MovingObjectPosition::fromBlock($this->x, $this->y, $this->z, $f, $vector->add($this->x, $this->y, $this->z)); + } + /** * Places the Block, using block space and block target, and side. Returns if the block has been placed. * diff --git a/src/pocketmine/entity/Living.php b/src/pocketmine/entity/Living.php index 6021d447d..3be887443 100644 --- a/src/pocketmine/entity/Living.php +++ b/src/pocketmine/entity/Living.php @@ -58,6 +58,11 @@ abstract class Living extends Entity implements Damageable{ public abstract function getName(); + public function hasLineOfSight(Entity $entity){ + //TODO: head height + return $this->getLevel()->rayTraceBlocks(new Vector3($this->x, $this->y + $this->height, $this->z), new Vector3($entity->x, $entity->y + $entity->height, $entity->z)) === null; + } + public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){ //TODO: attack tick limit $pk = new EntityEventPacket(); diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index c70ddfe4b..15e8253c5 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -723,6 +723,78 @@ class Level implements ChunkManager, Metadatable{ return $collides; } + /* + public function rayTraceBlocks(Vector3 $pos1, Vector3 $pos2, $flag = false, $flag1 = false, $flag2 = false){ + if(!is_nan($pos1->x) and !is_nan($pos1->y) and !is_nan($pos1->z)){ + if(!is_nan($pos2->x) and !is_nan($pos2->y) and !is_nan($pos2->z)){ + $x1 = (int) $pos1->x; + $y1 = (int) $pos1->y; + $z1 = (int) $pos1->z; + $x2 = (int) $pos2->x; + $y2 = (int) $pos2->y; + $z2 = (int) $pos2->z; + + $block = $this->getBlock(new Vector3($x1, $y1, $z1)); + + if(!$flag1 or $block->getBoundingBox() !== null){ + $ob = $block->calculateIntercept($pos1, $pos2); + if($ob !== null){ + return $ob; + } + } + + $movingObjectPosition = null; + + $k = 200; + + while($k-- >= 0){ + if(is_nan($pos1->x) or is_nan($pos1->y) or is_nan($pos1->z)){ + return null; + } + + if($x1 === $x2 and $y1 === $y2 and $z1 === $z2){ + return $flag2 ? $movingObjectPosition : null; + } + + $flag3 = true; + $flag4 = true; + $flag5 = true; + + $i = 999; + $j = 999; + $k = 999; + + if($x1 > $x2){ + $i = $x2 + 1; + }elseif($x1 < $x2){ + $i = $x2; + }else{ + $flag3 = false; + } + + if($y1 > $y2){ + $j = $y2 + 1; + }elseif($y1 < $y2){ + $j = $y2; + }else{ + $flag4 = false; + } + + if($z1 > $z2){ + $k = $z2 + 1; + }elseif($z1 < $z2){ + $k = $z2; + }else{ + $flag5 = false; + } + + //TODO + } + } + } + } + */ + /** * Gets the Block object on the Vector3 location * diff --git a/src/pocketmine/math/AxisAlignedBB.php b/src/pocketmine/math/AxisAlignedBB.php index ebeb7e92d..8db9aa4f8 100644 --- a/src/pocketmine/math/AxisAlignedBB.php +++ b/src/pocketmine/math/AxisAlignedBB.php @@ -264,7 +264,6 @@ class AxisAlignedBB{ return $vector->x >= $this->minX and $vector->x <= $this->maxX and $vector->y >= $this->minY and $vector->y <= $this->maxY; } - public function calculateIntercept(Vector3 $pos1, Vector3 $pos2){ $v1 = $pos1->getIntermediateWithXValue($pos2, $this->minX); $v2 = $pos1->getIntermediateWithXValue($pos2, $this->maxX);