Added basic support for blocks with multiple AABBs, fixed stairs (#1303)

This commit is contained in:
Dylan K. Taylor 2017-10-12 16:29:24 +01:00 committed by GitHub
parent 0c092a7ceb
commit 15d6fd86e2
5 changed files with 127 additions and 119 deletions

View File

@ -71,6 +71,10 @@ class Air extends Transparent{
return null; return null;
} }
public function getCollisionBoxes() : array{
return [];
}
public function getHardness() : float{ public function getHardness() : float{
return -1; return -1;
} }

View File

@ -69,6 +69,10 @@ class Block extends Position implements BlockIds, Metadatable{
/** @var AxisAlignedBB */ /** @var AxisAlignedBB */
public $boundingBox = null; public $boundingBox = null;
/** @var AxisAlignedBB[]|null */
protected $collisionBoxes = null;
/** /**
* @param int $id The block type's ID, 0-255 * @param int $id The block type's ID, 0-255
* @param int $meta Meta value of the block type * @param int $meta Meta value of the block type
@ -489,9 +493,15 @@ class Block extends Position implements BlockIds, Metadatable{
* @return bool * @return bool
*/ */
public function collidesWithBB(AxisAlignedBB $bb) : bool{ public function collidesWithBB(AxisAlignedBB $bb) : bool{
$bb2 = $this->getBoundingBox(); $bbs = $this->getCollisionBoxes();
return $bb2 !== null and $bb->intersectsWith($bb2); foreach($bbs as $bb2){
if($bb->intersectsWith($bb2)){
return true;
}
}
return false;
} }
/** /**
@ -501,6 +511,28 @@ class Block extends Position implements BlockIds, Metadatable{
} }
/**
* @return AxisAlignedBB[]
*/
public function getCollisionBoxes() : array{
if($this->collisionBoxes === null){
$this->collisionBoxes = $this->recalculateCollisionBoxes();
}
return $this->collisionBoxes;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
if($bb = $this->recalculateBoundingBox()){
return [$bb];
}
return [];
}
/** /**
* @return AxisAlignedBB|null * @return AxisAlignedBB|null
*/ */
@ -532,19 +564,36 @@ class Block extends Position implements BlockIds, Metadatable{
* @return MovingObjectPosition|null * @return MovingObjectPosition|null
*/ */
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?MovingObjectPosition{ public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?MovingObjectPosition{
$bb = $this->getBoundingBox(); $bbs = $this->getCollisionBoxes();
if($bb === null){ if(empty($bbs)){
return null; return null;
} }
$result = $bb->calculateIntercept($pos1, $pos2); /** @var MovingObjectPosition|null $currentHit */
if($result !== null){ $currentHit = null;
$result->blockX = $this->x; /** @var int|float $currentDistance */
$result->blockY = $this->y; $currentDistance = PHP_INT_MAX;
$result->blockZ = $this->z;
foreach($bbs as $bb){
$nextHit = $bb->calculateIntercept($pos1, $pos2);
if($nextHit === null){
continue;
} }
return $result; $nextDistance = $nextHit->hitVector->distanceSquared($pos1);
if($nextDistance < $currentDistance){
$currentHit = $nextHit;
$currentDistance = $nextDistance;
}
}
if($currentHit !== null){
$currentHit->blockX = $this->x;
$currentHit->blockY = $this->y;
$currentHit->blockZ = $this->z;
}
return $currentHit;
} }
public function setMetadata(string $metadataKey, MetadataValue $newMetadataValue){ public function setMetadata(string $metadataKey, MetadataValue $newMetadataValue){

View File

@ -31,103 +31,56 @@ use pocketmine\Player;
abstract class Stair extends Transparent{ abstract class Stair extends Transparent{
/* protected function recalculateCollisionBoxes() : array{
public function collidesWithBB(AxisAlignedBB $bb, &$list = []){ //TODO: handle corners
$damage = $this->getDamage();
$j = $damage & 0x03;
$f = 0; $minYSlab = ($this->meta & 0x04) === 0 ? 0 : 0.5;
$f1 = 0.5; $maxYSlab = $minYSlab + 0.5;
$f2 = 0.5;
$f3 = 1;
if(($damage & 0x04) > 0){ $bbs = [
$f = 0.5; new AxisAlignedBB(
$f1 = 1;
$f2 = 0;
$f3 = 0.5;
}
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
$this->x, $this->x,
$this->y + $f, $this->y + $minYSlab,
$this->z, $this->z,
$this->x + 1, $this->x + 1,
$this->y + $f1, $this->y + $maxYSlab,
$this->z + 1 $this->z + 1
))){ )
$list[] = $bb2; ];
$minY = ($this->meta & 0x04) === 0 ? 0.5 : 0;
$maxY = $minY + 0.5;
$rotationMeta = $this->meta & 0x03;
$minX = $minZ = 0;
$maxX = $maxZ = 1;
switch($rotationMeta){
case 0:
$minX = 0.5;
break;
case 1:
$maxX = 0.5;
break;
case 2:
$minZ = 0.5;
break;
case 3:
$maxZ = 0.5;
break;
} }
if($j === 0){ $bbs[] = new AxisAlignedBB(
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool( $this->x + $minX,
$this->x + 0.5, $this->y + $minY,
$this->y + $f2, $this->z + $minZ,
$this->z, $this->x + $maxX,
$this->x + 1, $this->y + $maxY,
$this->y + $f3, $this->z + $maxZ
$this->z + 1
))){
$list[] = $bb2;
}
}elseif($j === 1){
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
$this->x,
$this->y + $f2,
$this->z,
$this->x + 0.5,
$this->y + $f3,
$this->z + 1
))){
$list[] = $bb2;
}
}elseif($j === 2){
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
$this->x,
$this->y + $f2,
$this->z + 0.5,
$this->x + 1,
$this->y + $f3,
$this->z + 1
))){
$list[] = $bb2;
}
}elseif($j === 3){
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
$this->x,
$this->y + $f2,
$this->z,
$this->x + 1,
$this->y + $f3,
$this->z + 0.5
))){
$list[] = $bb2;
}
}
}
*/
protected function recalculateBoundingBox() : ?AxisAlignedBB{
if(($this->getDamage() & 0x04) > 0){
return new AxisAlignedBB(
$this->x,
$this->y + 0.5,
$this->z,
$this->x + 1,
$this->y + 1,
$this->z + 1
); );
}else{
return new AxisAlignedBB( return $bbs;
$this->x,
$this->y,
$this->z,
$this->x + 1,
$this->y + 0.5,
$this->z + 1
);
}
} }
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{ public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{

View File

@ -1497,9 +1497,7 @@ abstract class Entity extends Location implements Metadatable{
public function isInsideOfSolid() : bool{ public function isInsideOfSolid() : bool{
$block = $this->level->getBlock($this->temporalVector->setComponents(Math::floorFloat($this->x), Math::floorFloat($y = ($this->y + $this->getEyeHeight())), Math::floorFloat($this->z))); $block = $this->level->getBlock($this->temporalVector->setComponents(Math::floorFloat($this->x), Math::floorFloat($y = ($this->y + $this->getEyeHeight())), Math::floorFloat($this->z)));
$bb = $block->getBoundingBox(); return $block->isSolid() and !$block->isTransparent() and $block->collidesWithBB($this->getBoundingBox());
return $bb !== null and $block->isSolid() and !$block->isTransparent() and $bb->intersectsWith($this->getBoundingBox());
} }
public function fastMove(float $dx, float $dy, float $dz) : bool{ public function fastMove(float $dx, float $dy, float $dz) : bool{

View File

@ -1188,7 +1188,9 @@ class Level implements ChunkManager, Metadatable{
for($y = $minY; $y <= $maxY; ++$y){ for($y = $minY; $y <= $maxY; ++$y){
$block = $this->getBlock($this->temporalVector->setComponents($x, $y, $z)); $block = $this->getBlock($this->temporalVector->setComponents($x, $y, $z));
if(!$block->canPassThrough() and $block->collidesWithBB($bb)){ if(!$block->canPassThrough() and $block->collidesWithBB($bb)){
$collides[] = $block->getBoundingBox(); foreach($block->getCollisionBoxes() as $blockBB){
$collides[] = $blockBB;
}
} }
} }
} }
@ -1789,8 +1791,9 @@ class Level implements ChunkManager, Metadatable{
return false; return false;
} }
if($hand->isSolid() === true and $hand->getBoundingBox() !== null){ if($hand->isSolid()){
$entities = $this->getCollidingEntities($hand->getBoundingBox()); foreach($hand->getCollisionBoxes() as $collisionBox){
$entities = $this->getCollidingEntities($collisionBox);
foreach($entities as $e){ foreach($entities as $e){
if($e instanceof Arrow or $e instanceof DroppedItem or ($e instanceof Player and $e->isSpectator())){ if($e instanceof Arrow or $e instanceof DroppedItem or ($e instanceof Player and $e->isSpectator())){
continue; continue;
@ -1802,12 +1805,13 @@ class Level implements ChunkManager, Metadatable{
if($player !== null){ if($player !== null){
if(($diff = $player->getNextPosition()->subtract($player->getPosition())) and $diff->lengthSquared() > 0.00001){ if(($diff = $player->getNextPosition()->subtract($player->getPosition())) and $diff->lengthSquared() > 0.00001){
$bb = $player->getBoundingBox()->getOffsetBoundingBox($diff->x, $diff->y, $diff->z); $bb = $player->getBoundingBox()->getOffsetBoundingBox($diff->x, $diff->y, $diff->z);
if($hand->getBoundingBox()->intersectsWith($bb)){ if($collisionBox->intersectsWith($bb)){
return false; //Inside player BB return false; //Inside player BB
} }
} }
} }
} }
}
if($player !== null){ if($player !== null){