mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-05-14 09:49:50 +00:00
Added base physics
This commit is contained in:
parent
ec055fd8d1
commit
4f2856dc09
@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
namespace pocketmine\block;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
|
||||
|
||||
/**
|
||||
@ -41,4 +42,8 @@ class Air extends Transparent{
|
||||
|
||||
}
|
||||
|
||||
public function collidesWithBB(AxisAlignedBB $bb, &$list = array()){
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -24,8 +24,11 @@
|
||||
*/
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Position;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\metadata\Metadatable;
|
||||
use pocketmine\metadata\MetadataValue;
|
||||
use pocketmine\Player;
|
||||
@ -710,6 +713,26 @@ abstract class Block extends Position implements Metadatable{
|
||||
*/
|
||||
abstract function onBreak(Item $item);
|
||||
|
||||
/**
|
||||
* Checks for collision against an AxisAlignedBB
|
||||
*
|
||||
* @param AxisAlignedBB $bb
|
||||
* @param Block[] $list
|
||||
*/
|
||||
public function collidesWithBB(AxisAlignedBB $bb, &$list = array()){
|
||||
$bb2 = new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + 1,
|
||||
$this->z + 1
|
||||
);
|
||||
if($bb2->intersectsWith($bb)){
|
||||
$list[] = $bb2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Places the Block, using block space and block target, and side. Returns if the block has been placed.
|
||||
*
|
||||
|
@ -21,8 +21,11 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
|
||||
|
@ -27,6 +27,7 @@ use pocketmine\nbt\tag\Compound;
|
||||
use pocketmine\nbt\tag\Short;
|
||||
use pocketmine\nbt\tag\String;
|
||||
use pocketmine\network\protocol\AddItemEntityPacket;
|
||||
use pocketmine\network\protocol\SetEntityMotionPacket;
|
||||
use pocketmine\Player;
|
||||
|
||||
class DroppedItem extends Entity{
|
||||
@ -38,6 +39,12 @@ class DroppedItem extends Entity{
|
||||
/** @var Item */
|
||||
protected $item;
|
||||
|
||||
public $width = 0.25;
|
||||
public $length = 0.25;
|
||||
public $height = 0.25;
|
||||
protected $gravity = 0.04;
|
||||
protected $drag = 0.02;
|
||||
|
||||
protected function initEntity(){
|
||||
//TODO: upgrade old numeric entity ids
|
||||
$this->namedtag->id = new String("id", "Item");
|
||||
@ -156,6 +163,13 @@ class DroppedItem extends Entity{
|
||||
$pk->metadata = $this->getData();
|
||||
$player->dataPacket($pk);
|
||||
|
||||
$pk = new SetEntityMotionPacket;
|
||||
$pk->eid = $this->getID();
|
||||
$pk->speedX = $this->motionX;
|
||||
$pk->speedY = $this->motionY;
|
||||
$pk->speedZ = $this->motionZ;
|
||||
$player->dataPacket($pk);
|
||||
|
||||
parent::spawnTo($player);
|
||||
}
|
||||
}
|
@ -49,6 +49,7 @@ use pocketmine\network\protocol\SetTimePacket;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\plugin\Plugin;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\block\Block;
|
||||
|
||||
abstract class Entity extends Position implements Metadatable{
|
||||
public static $entityCount = 1;
|
||||
@ -83,6 +84,7 @@ abstract class Entity extends Position implements Metadatable{
|
||||
public $lastYaw;
|
||||
public $lastPitch;
|
||||
|
||||
/** @var AxisAlignedBB */
|
||||
public $boundingBox;
|
||||
public $onGround;
|
||||
public $positionChanged;
|
||||
@ -105,6 +107,8 @@ abstract class Entity extends Position implements Metadatable{
|
||||
public $airTicks;
|
||||
public $namedtag;
|
||||
|
||||
protected $isColliding = false;
|
||||
|
||||
protected $inWater;
|
||||
public $noDamageTicks;
|
||||
private $justCreated;
|
||||
@ -113,6 +117,9 @@ abstract class Entity extends Position implements Metadatable{
|
||||
|
||||
protected $spawnTime;
|
||||
|
||||
protected $gravity;
|
||||
protected $drag;
|
||||
|
||||
/** @var Server */
|
||||
protected $server;
|
||||
|
||||
@ -173,6 +180,7 @@ abstract class Entity extends Position implements Metadatable{
|
||||
$this->lastUpdate = $this->spawnTime = microtime(true);
|
||||
$this->justCreated = false;
|
||||
$this->server->getPluginManager()->callEvent(new EntitySpawnEvent($this));
|
||||
$this->scheduleUpdate();
|
||||
}
|
||||
|
||||
public function saveNBT(){
|
||||
@ -268,8 +276,19 @@ abstract class Entity extends Position implements Metadatable{
|
||||
return false;
|
||||
}
|
||||
|
||||
$hasUpdate = false;
|
||||
$timeNow = microtime(true);
|
||||
$this->ticksLived += ($timeNow - $this->lastUpdate) * 20;
|
||||
$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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if($this->handleWaterMovement()){
|
||||
$this->fallDistance = 0;
|
||||
@ -345,7 +364,7 @@ abstract class Entity extends Position implements Metadatable{
|
||||
|
||||
$this->lastUpdate = $timeNow;
|
||||
|
||||
return false;
|
||||
return !($this instanceof Player) and ($this->motionX != 0 or $this->motionY == 0 or $this->motionZ == 0 or $hasUpdate);
|
||||
}
|
||||
|
||||
public final function scheduleUpdate(){
|
||||
@ -469,12 +488,242 @@ abstract class Entity extends Position implements Metadatable{
|
||||
return new Position($this->x, $this->y, $this->z, $this->level);
|
||||
}
|
||||
|
||||
public function move(Vector3 $displacement){
|
||||
if($displacement->x == 0 and $displacement->y == 0 and $displacement->z == 0){
|
||||
public function collision(){
|
||||
$this->isColliding = true;
|
||||
$this->fallDistance = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entities near the current one inside the AxisAlignedBB
|
||||
*
|
||||
* @param AxisAlignedBB $bb
|
||||
*
|
||||
* @return Entity[]
|
||||
*/
|
||||
public function getNearbyEntities(AxisAlignedBB $bb){
|
||||
|
||||
$nearby = [];
|
||||
|
||||
$minX = ($bb->minX - 2) >> 4;
|
||||
$maxX = ($bb->maxX + 2) >> 4;
|
||||
$minZ = ($bb->minZ - 2) >> 4;
|
||||
$maxZ = ($bb->maxX + 2) >> 4;
|
||||
|
||||
for($x = $minX; $x <= $maxX; ++$x){
|
||||
for($z = $minZ; $z <= $maxZ; ++$z){
|
||||
if($this->getLevel()->isChunkLoaded($x, $z)){
|
||||
foreach($this->getLevel()->getChunkEntities($x, $z) as $ent){
|
||||
if($ent !== $this and $ent->boundingBox->intersectsWith($this->boundingBox)){
|
||||
$nearby[] = $ent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $nearby;
|
||||
}
|
||||
|
||||
public function move($dx, $dy, $dz){
|
||||
//$collision = [];
|
||||
//$this->checkBlockCollision($collision);
|
||||
if($dx == 0 and $dz == 0 and $dy == 0){
|
||||
return;
|
||||
}
|
||||
|
||||
$this->scheduleUpdate();
|
||||
$ox = $this->x;
|
||||
$oy = $this->y;
|
||||
$oz = $this->z;
|
||||
|
||||
if($this->isColliding){ //With an entity
|
||||
$this->isColliding = false;
|
||||
$dx *= 0.25;
|
||||
$dy *= 0.05;
|
||||
$dz *= 0.25;
|
||||
$this->motionX = 0;
|
||||
$this->motionY = 0;
|
||||
$this->motionZ = 0;
|
||||
}
|
||||
|
||||
$movX = $dx;
|
||||
$movY = $dy;
|
||||
$movZ = $dz;
|
||||
|
||||
/*$sneakFlag = $this->onGround and $this instanceof Player;
|
||||
|
||||
if($sneakFlag){
|
||||
for($mov = 0.05; $dx != 0.0 and count($this->getLevel()->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox($dx, -1, 0))) === 0; $movX = $dx){
|
||||
if($dx < $mov and $dx >= -$mov){
|
||||
$dx = 0;
|
||||
}elseif($dx > 0){
|
||||
$dx -= $mov;
|
||||
}else{
|
||||
$dx += $mov;
|
||||
}
|
||||
}
|
||||
|
||||
for(; $dz != 0.0 and count($this->getLevel()->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox(0, -1, $dz))) === 0; $movZ = $dz){
|
||||
if($dz < $mov and $dz >= -$mov){
|
||||
$dz = 0;
|
||||
}elseif($dz > 0){
|
||||
$dz -= $mov;
|
||||
}else{
|
||||
$dz += $mov;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: big messy loop
|
||||
}*/
|
||||
|
||||
if(count($this->getLevel()->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox(0, $dy, 0))) > 0){
|
||||
$dy = 0;
|
||||
$dx = 0;
|
||||
$dz = 0;
|
||||
}
|
||||
|
||||
$fallingFlag = $this->onGround or ($dy != $movY and $movY < 0);
|
||||
|
||||
if($dx != 0){
|
||||
if(count($this->getLevel()->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox($dx, 0, 0))) > 0){
|
||||
$dy = 0;
|
||||
$dx = 0;
|
||||
$dz = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if($dz != 0){
|
||||
if(count($this->getLevel()->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox(0, 0, $dz))) > 0){
|
||||
$dy = 0;
|
||||
$dx = 0;
|
||||
$dz = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if($movX != $dx or $movZ != $dz or $fallingFlag){
|
||||
|
||||
$cx = $dx;
|
||||
$cy = $dy;
|
||||
$cz = $dz;
|
||||
$dx = $movX;
|
||||
$dy = 0.05;
|
||||
$dz = $movZ;
|
||||
$oldBB = clone $this->boundingBox;
|
||||
$list = $this->getLevel()->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox($movX, $dy, $movZ));
|
||||
|
||||
|
||||
foreach($list as $bb){
|
||||
$dy = $bb->calculateYOffset($this->boundingBox, $dy);
|
||||
}
|
||||
|
||||
$this->boundingBox->addCoord(0, $dy, 0);
|
||||
|
||||
if($movY != $dy){
|
||||
$dx = 0;
|
||||
$dy = 0;
|
||||
$dz = 0;
|
||||
}
|
||||
|
||||
foreach($list as $bb){
|
||||
$dx = $bb->calculateXOffset($this->boundingBox, $dx);
|
||||
}
|
||||
|
||||
$this->boundingBox->addCoord($dx, 0, 0);
|
||||
|
||||
if($movX != $dx){
|
||||
$dx = 0;
|
||||
$dy = 0;
|
||||
$dz = 0;
|
||||
}
|
||||
|
||||
foreach($list as $bb){
|
||||
$dz = $bb->calculateZOffset($this->boundingBox, $dz);
|
||||
}
|
||||
|
||||
$this->boundingBox->addCoord(0, 0, $dz);
|
||||
|
||||
if($movZ != $dz){
|
||||
$dx = 0;
|
||||
$dy = 0;
|
||||
$dz = 0;
|
||||
}
|
||||
|
||||
if($movY != $dy){
|
||||
$dy = -0.05;
|
||||
foreach($list as $bb){
|
||||
$dy = $bb->calculateYOffset($this->boundingBox, $dy);
|
||||
}
|
||||
|
||||
$this->boundingBox->addCoord(0, $dy, 0);
|
||||
}
|
||||
|
||||
if($cx * $cx + $cz * $cz > $dx * $dx + $dz * $dz){
|
||||
$dx = $cx;
|
||||
$dy = $cy;
|
||||
$dz = $cz;
|
||||
$this->boundingBox->setBB($oldBB);
|
||||
}
|
||||
}
|
||||
|
||||
$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);
|
||||
//$this->x += $dx;
|
||||
//$this->y += $dy;
|
||||
//$this->z += $dz;
|
||||
|
||||
$cx = $this->x - $ox;
|
||||
$cy = $this->y - $oy;
|
||||
$cz = $this->z - $oz;
|
||||
|
||||
//TODO: vehicle collision events (first we need to spawn them!)
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Block[] $list
|
||||
*
|
||||
* @return Block[]
|
||||
*/
|
||||
protected function checkBlockCollision(&$list = array()){
|
||||
$minX = floor($this->boundingBox->minX + 0.001);
|
||||
$minY = floor($this->boundingBox->minY + 0.001);
|
||||
$minZ = floor($this->boundingBox->minZ + 0.001);
|
||||
$maxX = floor($this->boundingBox->maxX + 0.001);
|
||||
$maxY = floor($this->boundingBox->maxY + 0.001);
|
||||
$maxZ = floor($this->boundingBox->maxZ + 0.001);
|
||||
|
||||
for($z = $minZ; $z <= $maxZ; ++$z){
|
||||
for($x = $minX; $x <= $maxX; ++$x){
|
||||
for($y = $minY; $y <= $maxY; ++$y){
|
||||
$this->getLevel()->getBlock(new Vector3($x, $y, $z))->collidesWithBB($this->boundingBox, $list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function setPositionAndRotation(Vector3 $pos, $yaw, $pitch){
|
||||
|
@ -42,6 +42,10 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
||||
/** @var PlayerInventory */
|
||||
protected $inventory;
|
||||
|
||||
public $width = 0.6;
|
||||
public $length = 0.6;
|
||||
public $height = 1.8;
|
||||
|
||||
public function getInventory(){
|
||||
return $this->inventory;
|
||||
}
|
||||
@ -68,9 +72,6 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
||||
}
|
||||
}
|
||||
|
||||
$this->height = 1.8; //Or 1.62?
|
||||
$this->width = 0.6;
|
||||
|
||||
parent::initEntity();
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,10 @@ namespace pocketmine\entity;
|
||||
|
||||
|
||||
abstract class Living extends Entity implements Damageable{
|
||||
|
||||
protected $gravity = 0.08;
|
||||
protected $drag = 0.02;
|
||||
|
||||
protected function initEntity(){
|
||||
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ use pocketmine\item\Item;
|
||||
use pocketmine\level\format\pmf\LevelFormat;
|
||||
use pocketmine\level\generator\Flat;
|
||||
use pocketmine\level\generator\Generator;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector2;
|
||||
use pocketmine\math\Vector3 as Vector3;
|
||||
use pocketmine\nbt\NBT;
|
||||
@ -323,7 +324,7 @@ class Level{
|
||||
|
||||
//Do chunk updates
|
||||
while($this->updateQueue->count() > 0 and $this->updateQueue->current()["priority"] <= $currentTick){
|
||||
$block = $this->getBlockRaw($this->updateQueue->extract()["data"]);
|
||||
$block = $this->getBlock($this->updateQueue->extract()["data"]);
|
||||
$block->onUpdate(self::BLOCK_UPDATE_SCHEDULED);
|
||||
}
|
||||
|
||||
@ -332,7 +333,7 @@ class Level{
|
||||
for($Y = 0; $Y < 8; ++$Y){
|
||||
if(!$this->level->isMiniChunkEmpty($X, $Z, $Y)){
|
||||
for($i = 0; $i < 3; ++$i){
|
||||
$block = $this->getBlockRaw(new Vector3(($X << 4) + mt_rand(0, 15), ($Y << 4) + mt_rand(0, 15), ($Z << 4) + mt_rand(0, 15)));
|
||||
$block = $this->getBlock(new Vector3(($X << 4) + mt_rand(0, 15), ($Y << 4) + mt_rand(0, 15), ($Z << 4) + mt_rand(0, 15)));
|
||||
if($block instanceof Block){
|
||||
if($block->onUpdate(self::BLOCK_UPDATE_RANDOM) === self::BLOCK_UPDATE_NORMAL){
|
||||
$this->updateAround($block, self::BLOCK_UPDATE_NORMAL);
|
||||
@ -510,6 +511,39 @@ class Level{
|
||||
return Block::get($b[0], $b[1], new Position($pos->x, $pos->y, $pos->z, $this));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Entity $entity
|
||||
* @param AxisAlignedBB $bb
|
||||
*
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
public function getCollisionCubes(Entity $entity, 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach($entity->getNearbyEntities($bb->expand(0.25, 0.25, 0.25)) as $ent){
|
||||
$collides[] = $ent->boundingBox;
|
||||
}
|
||||
|
||||
return $collides;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Vector3 $pos
|
||||
* @param Block $block
|
||||
@ -624,7 +658,7 @@ class Level{
|
||||
//TODO: add random motion with physics
|
||||
"Motion" => new Enum("Motion", [
|
||||
new Double("", 0),
|
||||
new Double("", 0),
|
||||
new Double("", 0.05),
|
||||
new Double("", 0)
|
||||
]),
|
||||
"Rotation" => new Enum("Rotation", [
|
||||
@ -991,6 +1025,10 @@ class Level{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function isChunkLoaded($X, $Z){
|
||||
return $this->level->isChunkLoaded($X, $Z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a chunk
|
||||
*
|
||||
|
@ -54,26 +54,25 @@ class AxisAlignedBB{
|
||||
}
|
||||
|
||||
public function addCoord($x, $y, $z){
|
||||
$vec = clone $this;
|
||||
if($x < 0){
|
||||
$vec->minX += $x;
|
||||
$this->minX += $x;
|
||||
}elseif($x > 0){
|
||||
$vec->maxX += $x;
|
||||
$this->maxX += $x;
|
||||
}
|
||||
|
||||
if($y < 0){
|
||||
$vec->minY += $y;
|
||||
$this->minY += $y;
|
||||
}elseif($y > 0){
|
||||
$vec->maxY += $y;
|
||||
$this->maxY += $y;
|
||||
}
|
||||
|
||||
if($z < 0){
|
||||
$vec->minZ += $z;
|
||||
$this->minZ += $z;
|
||||
}elseif($z > 0){
|
||||
$vec->maxZ += $z;
|
||||
$this->maxZ += $z;
|
||||
}
|
||||
|
||||
return $vec;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function expand($x, $y, $z){
|
||||
@ -197,14 +196,13 @@ class AxisAlignedBB{
|
||||
}
|
||||
|
||||
public function intersectsWith(AxisAlignedBB $bb){
|
||||
if($bb->maxX <= $this->minX or $bb->minX >= $this->maxX){
|
||||
return false;
|
||||
}
|
||||
if($bb->maxY <= $this->minY or $bb->minY >= $this->maxY){
|
||||
return false;
|
||||
if($bb->maxX > $this->minX and $bb->minX < $this->maxX){
|
||||
if($bb->maxY > $this->minY and $bb->minY < $this->maxY){
|
||||
return $bb->maxZ > $this->minZ and $bb->minZ < $this->maxZ;
|
||||
}
|
||||
}
|
||||
|
||||
return $bb->maxZ > $this->minZ and $bb->minZ < $this->maxZ;
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isVectorInside(Vector3 $vector){
|
||||
|
Loading…
x
Reference in New Issue
Block a user