diff --git a/src/pocketmine/block/Air.php b/src/pocketmine/block/Air.php index f5417031e..28022c79b 100644 --- a/src/pocketmine/block/Air.php +++ b/src/pocketmine/block/Air.php @@ -42,8 +42,8 @@ class Air extends Transparent{ } - public function collidesWithBB(AxisAlignedBB $bb, &$list = array()){ - + public function getBoundingBox(){ + return new AxisAlignedBB(0, 0, 0, 0, 0, 0); } } \ No newline at end of file diff --git a/src/pocketmine/block/Block.php b/src/pocketmine/block/Block.php index 88564889f..d516e8ebc 100644 --- a/src/pocketmine/block/Block.php +++ b/src/pocketmine/block/Block.php @@ -426,6 +426,7 @@ abstract class Block extends Position implements Metadatable{ public $x = 0; public $y = 0; public $z = 0; + public $frictionFactor = 0.6; public static function init(){ if(count(self::$list) === 0){ @@ -720,7 +721,17 @@ abstract class Block extends Position implements Metadatable{ * @param Block[] $list */ public function collidesWithBB(AxisAlignedBB $bb, &$list = array()){ - $bb2 = new AxisAlignedBB( + $bb2 = $this->getBoundingBox(); + if($bb2->intersectsWith($bb)){ + $list[] = $bb2; + } + } + + /** + * @return AxisAlignedBB + */ + public function getBoundingBox(){ + return new AxisAlignedBB( $this->x, $this->y, $this->z, @@ -728,9 +739,6 @@ abstract class Block extends Position implements Metadatable{ $this->y + 1, $this->z + 1 ); - if($bb2->intersectsWith($bb)){ - $list[] = $bb2; - } } /** diff --git a/src/pocketmine/entity/DroppedItem.php b/src/pocketmine/entity/DroppedItem.php index e86c48422..84b49876a 100644 --- a/src/pocketmine/entity/DroppedItem.php +++ b/src/pocketmine/entity/DroppedItem.php @@ -22,6 +22,7 @@ namespace pocketmine\entity; use pocketmine\item\Item; +use pocketmine\math\Vector3; use pocketmine\nbt\tag\Byte; use pocketmine\nbt\tag\Compound; use pocketmine\nbt\tag\Short; @@ -32,7 +33,6 @@ use pocketmine\Player; class DroppedItem extends Entity{ - protected $age = 0; protected $owner = null; protected $thrower = null; protected $pickupDelay = 0; @@ -65,6 +65,41 @@ class DroppedItem extends Entity{ $this->item = Item::get($this->namedtag->Item["id"], $this->namedtag->Item["Damage"], min(64, $this->namedtag->Item["Count"])); } + public function onUpdate(){ + $this->entityBaseTick(); + //TODO: manage pickupDelay + + $this->motionY -= $this->gravity; + $this->inBlock = $this->checkObstruction($this->x, ($this->boundingBox->minY + $this->boundingBox->maxY) / 2, $this->z); + $this->move($this->motionX, $this->motionY, $this->motionZ); + + $friction = 1 - $this->drag; + + if($this->onGround){ + $friction = $this->getLevel()->getBlock(new Vector3($this->getFloorX(), $this->getFloorY() - 1, $this->getFloorZ()))->frictionFactor * $friction; + } + + $this->motionX *= $friction; + $this->motionY *= 1 - $this->drag; + $this->motionZ *= $friction; + + if($this->onGround){ + $this->motionY *= -0.5; + } + + if(abs($this->motionX) < 0.01){ + $this->motionX = 0; + } + if(abs($this->motionZ) < 0.01){ + $this->motionZ = 0; + } + + //TODO: update age in base entity tick + //TODO: kill entity if it's old enough + $this->updateMovement(); + //$this->server->broadcastMessage("{$this->ticksLived}: ".round($this->x, 2).",".round($this->y, 2).",".round($this->z, 2)); + } + public function attack($damage, $source = "generic"){ } diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index 857aef118..db8bad40c 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -78,6 +78,9 @@ abstract class Entity extends Position implements Metadatable{ public $motionX; public $motionY; public $motionZ; + public $lastMotionX; + public $lastMotionY; + public $lastMotionZ; public $yaw; public $pitch; @@ -87,9 +90,11 @@ abstract class Entity extends Position implements Metadatable{ /** @var AxisAlignedBB */ public $boundingBox; public $onGround; + public $inBlock = false; public $positionChanged; public $motionChanged; public $dead; + protected $age = 0; public $height; public $width; @@ -106,7 +111,7 @@ abstract class Entity extends Position implements Metadatable{ public $fireTicks; public $airTicks; public $namedtag; - + protected $isStatic = false; protected $isColliding = false; protected $inWater; @@ -271,24 +276,97 @@ abstract class Entity extends Position implements Metadatable{ $this->health = (int) min($this->health, $this->maxHealth); } - public function onUpdate(){ - if($this->closed !== false){ + protected function checkObstruction($x, $y, $z){ + $i = (int) $x; + $j = (int) $y; + $k = (int) $z; + + $diffX = $x - $i; + $diffY = $y - $j; + $diffZ = $z - $k; + + $start = microtime(true); + $list = $this->getLevel()->getCollisionBlocks($this->boundingBox); + + if(count($list) === 0 and $this->getLevel()->isFullBlock(new Vector3($i, $j, $k))){ return false; - } + }else{ + $flag = !$this->getLevel()->isFullBlock(new Vector3($i - 1, $j, $k)); + $flag1 = !$this->getLevel()->isFullBlock(new Vector3($i + 1, $j, $k)); + //$flag2 = !$this->getLevel()->isFullBlock(new Vector3($i, $j - 1, $k)); + $flag3 = !$this->getLevel()->isFullBlock(new Vector3($i, $j + 1, $k)); + $flag4 = !$this->getLevel()->isFullBlock(new Vector3($i, $j, $k - 1)); + $flag5 = !$this->getLevel()->isFullBlock(new Vector3($i, $j, $k + 1)); - $hasUpdate = false; - $timeNow = microtime(true); - $ticksOffset = min(20, max(1, floor(($timeNow - $this->lastUpdate) * 20))); //Simulate min one tic and max 20 - $this->ticksLived += $ticksOffset; - if(!($this instanceof Player)){ - for($tick = 0; $tick < $ticksOffset; ++$tick){ - $this->move($this->motionX, $this->motionY, $this->motionZ); - if($this->motionX == 0 and $this->motionY == 0 and $this->motionZ == 0){ - break; - } + $direction = 3; //UP! + $limit = 9999; + + if($flag){ + $limit = $diffX; + $direction = 0; } - } + if($flag1 and 1 - $diffX < $limit){ + $limit = 1 - $diffX; + $direction = 1; + } + + if($flag3 and 1 - $diffY < $limit){ + $limit = 1 - $diffY; + $direction = 3; + } + + if($flag4 and $diffZ < $limit){ + $limit = $diffZ; + $direction = 4; + } + + if($flag5 and 1 - $diffZ < $limit){ + $direction = 5; + } + + $force = lcg_value() * 0.2 + 0.1; + + if($direction === 0){ + $this->motionX = -$force; + return true; + } + + if($direction === 1){ + $this->motionX = $force; + return true; + } + + //No direction 2 + + if($direction === 3){ + $this->motionY = $force; + return true; + } + + if($direction === 4){ + $this->motionZ = -$force; + return true; + } + + if($direction === 5){ + $this->motionY = $force; + } + + return true; + + } + } + + public function entityBaseTick(){ + //TODO: check vehicles + $hasUpdate = false; + $this->lastX = $this->x; + $this->lastY = $this->y; + $this->lastZ = $this->z; + $this->lastMotionX = $this->motionX; + $this->lastPitch = $this->pitch; + $this->lastYaw = $this->yaw; if($this->handleWaterMovement()){ $this->fallDistance = 0; @@ -298,8 +376,12 @@ abstract class Entity extends Position implements Metadatable{ $this->inWater = false; } + if($this->y < -64){ + $this->kill(); + } + if($this->fireTicks > 0){ - if($this->fireProof === true){ + if($this->fireProof){ $this->fireTicks -= 4; if($this->fireTicks < 0){ $this->fireTicks = 0; @@ -310,18 +392,21 @@ abstract class Entity extends Position implements Metadatable{ } --$this->fireTicks; } + $hasUpdate = true; } if($this->handleLavaMovement()){ $this->attack(4, "lava"); $this->setOnFire(15); + $hasUpdate = true; $this->fallDistance *= 0.5; } - if($this->y < -64){ - $this->kill(); - } + ++$this->age; + ++$this->ticksLived; + } + public function updateMovement(){ if($this->x !== $this->lastX or $this->y !== $this->lastY or $this->z !== $this->lastZ or $this->yaw !== $this->lastYaw or $this->pitch !== $this->lastPitch){ $this->lastX = $this->x; $this->lastY = $this->y; @@ -351,7 +436,7 @@ abstract class Entity extends Position implements Metadatable{ $this->server->broadcastPacket($this->hasSpawned, $pk); } - if($this->motionChanged === true){ + if(!($this instanceof Player) and ($this->lastMotionX != $this->motionX or $this->lastMotionY != $this->motionY or $this->lastMotionZ != $this->motionZ)){ $this->motionChanged = false; $pk = new SetEntityMotionPacket; @@ -361,10 +446,18 @@ abstract class Entity extends Position implements Metadatable{ $pk->speedZ = $this->motionZ; $this->server->broadcastPacket($this->hasSpawned, $pk); } + } - $this->lastUpdate = $timeNow; + public function onUpdate(){ + if($this->closed !== false){ + return false; + } - return !($this instanceof Player) and ($this->motionX != 0 or $this->motionY == 0 or $this->motionZ == 0 or $hasUpdate); + $hasUpdate = $this->entityBaseTick(); + $this->updateMovement(); + //if($this->isStatic()) + return true; + //return !($this instanceof Player); } public final function scheduleUpdate(){ @@ -605,7 +698,7 @@ abstract class Entity extends Position implements Metadatable{ $cy = $dy; $cz = $dz; $dx = $movX; - $dy = 0.05; + $dy = 0; $dz = $movZ; $oldBB = clone $this->boundingBox; $list = $this->getLevel()->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox($movX, $dy, $movZ)); @@ -648,7 +741,7 @@ abstract class Entity extends Position implements Metadatable{ } if($movY != $dy){ - $dy = -0.05; + $dy = 0; foreach($list as $bb){ $dy = $bb->calculateYOffset($this->boundingBox, $dy); } @@ -667,25 +760,20 @@ abstract class Entity extends Position implements Metadatable{ $this->x = ($this->boundingBox->minX + $this->boundingBox->maxX) / 2; $this->y = $this->boundingBox->minY + $this->height; $this->z = ($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2; + $this->onGround = $movY != $dy and $movY < 0; $this->updateFallState($dy, $this->onGround); if($movX != $dx){ $this->motionX = 0; - }else{ - $this->motionX -= $this->motionX * $this->drag; } if($movY != $dy){ $this->motionY = 0; - }else{ - $this->motionY -= $this->motionY * $this->drag; } if($movZ != $dz){ $this->motionZ = 0; - }else{ - $this->motionY -= $this->motionY * $this->drag; } //$this->boundingBox->addCoord($dx, $dy, $dz); diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index a318b9eb3..eddd3351f 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -511,6 +511,34 @@ class Level{ return Block::get($b[0], $b[1], new Position($pos->x, $pos->y, $pos->z, $this)); } + public function getCollisionBlocks(AxisAlignedBB $bb){ + $minX = floor($bb->minX); + $minY = floor($bb->minY); + $minZ = floor($bb->minZ); + $maxX = floor($bb->maxX + 1); + $maxY = floor($bb->maxY + 1); + $maxZ = floor($bb->maxZ + 1); + + $collides = []; + + for($z = $minZ; $z < $maxZ; ++$z){ + for($x = $minX; $x < $maxX; ++$x){ + if($this->isChunkLoaded($x >> 4, $z >> 4)){ + for($y = $minY - 1; $y < $maxY; ++$y){ + $this->getBlock(new Vector3($x, $y, $z))->collidesWithBB($bb, $collides); + } + } + } + } + + return $collides; + } + + public function isFullBlock(Vector3 $pos){ + $bb = $this->getBlock($pos)->getBoundingBox(); + return $bb instanceof AxisAlignedBB and $bb->getAverageEdgeLength() >= 1; + } + /** * @param Entity $entity * @param AxisAlignedBB $bb @@ -537,9 +565,10 @@ class Level{ } } - foreach($entity->getNearbyEntities($bb->expand(0.25, 0.25, 0.25)) as $ent){ + //TODO: fix this + /*foreach($entity->getNearbyEntities($bb->expand(0.25, 0.25, 0.25)) as $ent){ $collides[] = $ent->boundingBox; - } + }*/ return $collides; } @@ -647,22 +676,27 @@ class Level{ return $ret; } - public function dropItem(Vector3 $pos, Item $item){ + /** + * @param Vector3 $source + * @param Item $item + * @param float $force + */ + public function dropItem(Vector3 $source, Item $item, $force = 1.0){ if($item->getID() !== Item::AIR and $item->getCount() > 0){ $itemEntity = new DroppedItem($this, new Compound("", [ "Pos" => new Enum("Pos", [ - new Double("", $pos->getX()), - new Double("", $pos->getY()), - new Double("", $pos->getZ()) + new Double("", $source->getX()), + new Double("", $source->getY()), + new Double("", $source->getZ()) ]), //TODO: add random motion with physics "Motion" => new Enum("Motion", [ - new Double("", 0), - new Double("", 0.05), - new Double("", 0) + new Double("", (lcg_value() * 0.2 - 0.1) * $force), + new Double("", 0.2 * $force), + new Double("", (lcg_value() * 0.2 - 0.1) * $force) ]), "Rotation" => new Enum("Rotation", [ - new Float("", 0), + new Float("", lcg_value() * 360), new Float("", 0) ]), "Health" => new Short("Health", 5), @@ -730,7 +764,7 @@ class Level{ if(!($player instanceof Player) or ($player->getGamemode() & 0x01) === 0){ foreach($target->getDrops($item) as $drop){ - $this->dropItem($vector->add(0.5, 0.5, 0.5), Item::get($drop[0], $drop[1], $drop[2])); + $this->dropItem($vector->add(0.5, 0.5, 0.5), Item::get($drop[0], $drop[1], $drop[2]), 5); } } return true;