diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 8f3afc8d1..2a905edf7 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -76,6 +76,7 @@ use pocketmine\level\generator\biome\Biome; use pocketmine\level\Level; use pocketmine\level\Location; use pocketmine\level\Position; +use pocketmine\level\sound\LaunchSound; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Vector3; use pocketmine\metadata\MetadataValue; @@ -172,7 +173,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ protected $username; protected $iusername; protected $displayName; - protected $startAction = false; + protected $startAction = -1; /** @var Vector3 */ protected $sleeping = null; protected $clientID = null; @@ -1210,7 +1211,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $this->lastUpdate = $currentTick; - if($this->spawned){ + if($this->spawned){ $this->processMovement($currentTick); $this->entityBaseTick(1); @@ -1275,7 +1276,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $pk->eid = $this->getId(); $pk->target = $entity->getId(); Server::broadcastPacket($entity->getViewers(), $pk); - $this->inventory->addItem(clone $item, $this); + $this->inventory->addItem(clone $item); $entity->kill(); } }elseif($entity instanceof DroppedItem){ @@ -1305,7 +1306,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $pk->eid = $this->getId(); $pk->target = $entity->getId(); Server::broadcastPacket($entity->getViewers(), $pk); - $this->inventory->addItem(clone $item, $this); + $this->inventory->addItem(clone $item); $entity->kill(); } } @@ -1687,6 +1688,8 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $this->inventory->sendHeldItem($this); break; }elseif($packet->face === 0xff){ + $aimPos = (new Vector3($packet->x / 32768, $packet->y / 32768, $packet->z / 32768))->normalize(); + if($this->isCreative()){ $item = $this->inventory->getItemInHand(); }elseif($this->inventory->getItemInHand()->getId() !== $packet->item or (($damage = $this->inventory->getItemInHand()->getDamage()) !== $packet->meta and $damage !== null)){ @@ -1695,9 +1698,8 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ }else{ $item = $this->inventory->getItemInHand(); } - $target = $this->level->getBlock($blockVector); - $ev = new PlayerInteractEvent($this, $item, $target, $packet->face, PlayerInteractEvent::RIGHT_CLICK_AIR); + $ev = new PlayerInteractEvent($this, $item, $aimPos, $packet->face, PlayerInteractEvent::RIGHT_CLICK_AIR); $this->server->getPluginManager()->callEvent($ev); @@ -1714,9 +1716,9 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ new Double("", $this->z) ]), "Motion" => new Enum("Motion", [ - new Double("", -sin($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI)), - new Double("", -sin($this->pitch / 180 * M_PI)), - new Double("", cos($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI)) + new Double("", $aimPos->x), + new Double("", $aimPos->y), + new Double("", $aimPos->z) ]), "Rotation" => new Enum("Rotation", [ new Float("", $this->yaw), @@ -1728,7 +1730,8 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $snowball = Entity::createEntity("Snowball", $this->chunk, $nbt, $this); $snowball->setMotion($snowball->getMotion()->multiply($f)); if($this->isSurvival()){ - $this->inventory->removeItem(Item::get(Item::SNOWBALL, 0, 1), $this); + $item->setCount($item->getCount() - 1); + $this->inventory->setItemInHand($item->getCount() > 0 ? $item : Item::get(Item::AIR)); } if($snowball instanceof Projectile){ $this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($snowball)); @@ -1736,13 +1739,15 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $snowball->kill(); }else{ $snowball->spawnToAll(); + $this->level->addSound(new LaunchSound($this), $this->getViewers()); } }else{ $snowball->spawnToAll(); } } + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, true); - $this->startAction = microtime(true); + $this->startAction = $this->server->getTick(); } break; case ProtocolInfo::PLAYER_ACTION_PACKET: @@ -1765,7 +1770,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $this->lastBreak = microtime(true); break; case 5: //Shot arrow - if($this->inventory->getItemInHand()->getId() === Item::BOW){ + if($this->startAction > -1 and $this->getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION) and $this->inventory->getItemInHand()->getId() === Item::BOW){ $bow = $this->inventory->getItemInHand(); if($this->isSurvival()){ if(!$this->inventory->contains(Item::get(Item::ARROW, 0, 1))){ @@ -1792,7 +1797,15 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ ]), ]); - $f = 1.5; + $diff = ($this->server->getTick() - $this->startAction); + if($diff < 5){ + break; + } + $p = $diff / 20; + $f = min((($p ** 2) + $p * 2) / 3, 1) * 2; + if($f < 0.1){ + break; + } $ev = new EntityShootBowEvent($this, $bow, Entity::createEntity("Arrow", $this->chunk, $nbt, $this), $f); $this->server->getPluginManager()->callEvent($ev); @@ -1802,11 +1815,12 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ }else{ $ev->getProjectile()->setMotion($ev->getProjectile()->getMotion()->multiply($ev->getForce())); if($this->isSurvival()){ - $this->inventory->removeItem(Item::get(Item::ARROW, 0, 1), $this); + $this->inventory->removeItem(Item::get(Item::ARROW, 0, 1)); $bow->setDamage($bow->getDamage() + 1); - $this->inventory->setItemInHand($bow, $this); if($bow->getDamage() >= 385){ - $this->inventory->setItemInHand(Item::get(Item::AIR, 0, 0), $this); + $this->inventory->setItemInHand(Item::get(Item::AIR, 0, 0)); + }else{ + $this->inventory->setItemInHand($bow); } } if($ev->getProjectile() instanceof Projectile){ @@ -1815,20 +1829,21 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $ev->getProjectile()->kill(); }else{ $ev->getProjectile()->spawnToAll(); + $this->level->addSound(new LaunchSound($this), $this->getViewers()); } }else{ $ev->getProjectile()->spawnToAll(); } } } - - $this->startAction = false; - $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false); break; case 6: //get out of the bed $this->stopSleep(); break; } + + $this->startAction = -1; + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false); break; case ProtocolInfo::REMOVE_BLOCK_PACKET: if($this->spawned === false or $this->blocked === true or $this->dead === true){ @@ -2097,7 +2112,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ --$slot->count; $this->inventory->setItemInHand($slot, $this); if($slot->getId() === Item::MUSHROOM_STEW or $slot->getId() === Item::BEETROOT_SOUP){ - $this->inventory->addItem(Item::get(Item::BOWL, 0, 1), $this); + $this->inventory->addItem(Item::get(Item::BOWL, 0, 1)); } } break; @@ -2263,7 +2278,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ case Item::CAKE: //TODO: detect complex recipes like cake that leave remains $this->awardAchievement("bakeCake"); - $this->inventory->addItem(Item::get(Item::BUCKET, 0, 3), $this); + $this->inventory->addItem(Item::get(Item::BUCKET, 0, 3)); break; case Item::STONE_PICKAXE: case Item::GOLD_PICKAXE: diff --git a/src/pocketmine/entity/Arrow.php b/src/pocketmine/entity/Arrow.php index 43d799d3a..fe91b2828 100644 --- a/src/pocketmine/entity/Arrow.php +++ b/src/pocketmine/entity/Arrow.php @@ -69,11 +69,12 @@ class Arrow extends Projectile{ $pk->x = $this->x; $pk->y = $this->y; $pk->z = $this->z; - $pk->did = 0; //TODO: send motion here + $pk->did = $this->shootingEntity !== null ? $this->shootingEntity->getId() : 1; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; $player->dataPacket($pk); - $player->addEntityMotion($this->getId(), $this->motionX, $this->motionY, $this->motionZ); - parent::spawnTo($player); } } \ No newline at end of file diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index aa1a270da..a9e31d8b9 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -87,6 +87,8 @@ abstract class Entity extends Location implements Metadatable{ const DATA_FLAG_ONFIRE = 0; + const DATA_FLAG_SNEAKING = 1; + const DATA_FLAG_RIDING = 2; const DATA_FLAG_ACTION = 4; const DATA_FLAG_INVISIBLE = 5; diff --git a/src/pocketmine/entity/Human.php b/src/pocketmine/entity/Human.php index 43ae6c753..1c31f991e 100644 --- a/src/pocketmine/entity/Human.php +++ b/src/pocketmine/entity/Human.php @@ -39,6 +39,7 @@ use pocketmine\utils\TextFormat; class Human extends Creature implements ProjectileSource, InventoryHolder{ const DATA_PLAYER_FLAG_SLEEP = 1; + const DATA_PLAYER_FLAG_DEAD = 2; const DATA_PLAYER_FLAGS = 16; const DATA_PLAYER_BED_POSITION = 17; @@ -75,9 +76,9 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ if($item["Slot"] >= 0 and $item["Slot"] < 9){ //Hotbar $this->inventory->setHotbarSlotIndex($item["Slot"], isset($item["TrueSlot"]) ? $item["TrueSlot"] : -1); }elseif($item["Slot"] >= 100 and $item["Slot"] < 104){ //Armor - $this->inventory->setItem($this->inventory->getSize() + $item["Slot"] - 100, ItemItem::get($item["id"], $item["Damage"], $item["Count"]), $this); + $this->inventory->setItem($this->inventory->getSize() + $item["Slot"] - 100, ItemItem::get($item["id"], $item["Damage"], $item["Count"])); }else{ - $this->inventory->setItem($item["Slot"] - 9, ItemItem::get($item["id"], $item["Damage"], $item["Count"]), $this); + $this->inventory->setItem($item["Slot"] - 9, ItemItem::get($item["id"], $item["Damage"], $item["Count"])); } } @@ -207,3 +208,4 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ } } +a \ No newline at end of file diff --git a/src/pocketmine/event/player/PlayerInteractEvent.php b/src/pocketmine/event/player/PlayerInteractEvent.php index c35b843bb..07fb457bb 100644 --- a/src/pocketmine/event/player/PlayerInteractEvent.php +++ b/src/pocketmine/event/player/PlayerInteractEvent.php @@ -24,6 +24,8 @@ namespace pocketmine\event\player; use pocketmine\block\Block; use pocketmine\event\Cancellable; use pocketmine\item\Item; +use pocketmine\level\Position; +use pocketmine\math\Vector3; use pocketmine\Player; /** @@ -43,6 +45,8 @@ class PlayerInteractEvent extends PlayerEvent implements Cancellable{ */ protected $blockTouched; + protected $touchVector; + /** @var int */ protected $blockFace; @@ -51,26 +55,51 @@ class PlayerInteractEvent extends PlayerEvent implements Cancellable{ protected $action; - public function __construct(Player $player, Item $item, Block $block, $face, $action = PlayerInteractEvent::RIGHT_CLICK){ - $this->blockTouched = $block; + public function __construct(Player $player, Item $item, Vector3 $block, $face, $action = PlayerInteractEvent::RIGHT_CLICK_BLOCK){ + if($block instanceof Block){ + $this->blockTouched = $block; + $this->touchVector = new Vector3(0, 0, 0); + }else{ + $this->touchVector = $block; + Block::get(0, 0, new Position(0, 0, 0, $player->level)); + } $this->player = $player; $this->item = $item; $this->blockFace = (int) $face; $this->action = (int) $action; } - + + /** + * @return int + */ public function getAction(){ return $this->action; } + /** + * @return Item + */ public function getItem(){ return $this->item; } + /** + * @return Block + */ public function getBlock(){ return $this->blockTouched; } + /** + * @return Vector3 + */ + public function getTouchVector(){ + return $this->touchVector; + } + + /** + * @return int + */ public function getFace(){ return $this->blockFace; } diff --git a/src/pocketmine/inventory/BaseInventory.php b/src/pocketmine/inventory/BaseInventory.php index b0df84533..cbae9ea9c 100644 --- a/src/pocketmine/inventory/BaseInventory.php +++ b/src/pocketmine/inventory/BaseInventory.php @@ -122,12 +122,12 @@ abstract class BaseInventory implements Inventory{ } } - public function setItem($index, Item $item, $source = null){ + public function setItem($index, Item $item){ $item = clone $item; if($index < 0 or $index >= $this->size){ return false; }elseif($item->getId() === 0 or $item->getCount() <= 0){ - return $this->clear($index, $source); + return $this->clear($index); } $holder = $this->getHolder(); @@ -142,7 +142,7 @@ abstract class BaseInventory implements Inventory{ $old = $this->getItem($index); $this->slots[$index] = clone $item; - $this->onSlotChange($index, $old, $source); + $this->onSlotChange($index, $old); return true; } @@ -227,14 +227,6 @@ abstract class BaseInventory implements Inventory{ } public function addItem(...$slots){ - if(isset($slots[$end = count($slots) - 1]) and $slots[$end] instanceof Player){ - /** @var Player $source */ - $source = $slots[$end]; - unset($slots[$end]); - }else{ - $source = null; - } - /** @var Item[] $itemSlots */ /** @var Item[] $slots */ $itemSlots = []; @@ -258,7 +250,7 @@ abstract class BaseInventory implements Inventory{ if($amount > 0){ $slot->setCount($slot->getCount() - $amount); $item->setCount($item->getCount() + $amount); - $this->setItem($i, $item, $source); + $this->setItem($i, $item); if($slot->getCount() <= 0){ unset($itemSlots[$index]); } @@ -273,12 +265,13 @@ abstract class BaseInventory implements Inventory{ if(count($itemSlots) > 0 and count($emptySlots) > 0){ foreach($emptySlots as $slotIndex){ + //This loop only gets the first item, then goes to the next empty slot foreach($itemSlots as $index => $slot){ $amount = min($slot->getMaxStackSize(), $slot->getCount(), $this->getMaxStackSize()); $slot->setCount($slot->getCount() - $amount); $item = clone $slot; $item->setCount($amount); - $this->setItem($slotIndex, $item, $source); + $this->setItem($slotIndex, $item); if($slot->getCount() <= 0){ unset($itemSlots[$index]); } @@ -291,14 +284,6 @@ abstract class BaseInventory implements Inventory{ } public function removeItem(...$slots){ - if(isset($slots[$end = count($slots) - 1]) and $slots[$end] instanceof Player){ - /** @var Player $source */ - $source = $slots[$end]; - unset($slots[$end]); - }else{ - $source = null; - } - /** @var Item[] $itemSlots */ /** @var Item[] $slots */ $itemSlots = []; @@ -319,7 +304,7 @@ abstract class BaseInventory implements Inventory{ $amount = min($item->getCount(), $slot->getCount()); $slot->setCount($slot->getCount() - $amount); $item->setCount($item->getCount() - $amount); - $this->setItem($i, $item, $source); + $this->setItem($i, $item); if($slot->getCount() <= 0){ unset($itemSlots[$index]); } @@ -334,7 +319,7 @@ abstract class BaseInventory implements Inventory{ return $itemSlots; } - public function clear($index, $source = null){ + public function clear($index){ if(isset($this->slots[$index])){ $item = Item::get(Item::AIR, null, 0); $old = $this->slots[$index]; @@ -353,7 +338,7 @@ abstract class BaseInventory implements Inventory{ unset($this->slots[$index]); } - $this->onSlotChange($index, $old, $source); + $this->onSlotChange($index, $old); } return true; @@ -366,20 +351,10 @@ abstract class BaseInventory implements Inventory{ } /** - * @param Player $source - * * @return Player[] */ - public function getViewers($source = null){ - $viewers = []; - foreach($this->viewers as $viewer){ - if($viewer === $source){ - continue; - } - $viewers[] = $viewer; - } - - return $viewers; + public function getViewers(){ + return $this->viewers; } public function getHolder(){ @@ -412,8 +387,8 @@ abstract class BaseInventory implements Inventory{ unset($this->viewers[spl_object_hash($who)]); } - public function onSlotChange($index, $before, $source = null){ - $this->sendSlot($index, $this->getViewers($source)); + public function onSlotChange($index, $before){ + $this->sendSlot($index, $this->getViewers()); } diff --git a/src/pocketmine/inventory/DoubleChestInventory.php b/src/pocketmine/inventory/DoubleChestInventory.php index 2c87ca503..2cbc26cae 100644 --- a/src/pocketmine/inventory/DoubleChestInventory.php +++ b/src/pocketmine/inventory/DoubleChestInventory.php @@ -53,12 +53,12 @@ class DoubleChestInventory extends ChestInventory implements InventoryHolder{ return $index < $this->left->getSize() ? $this->left->getItem($index) : $this->right->getItem($index - $this->right->getSize()); } - public function setItem($index, Item $item, $source = null){ - return $index < $this->left->getSize() ? $this->left->setItem($index, $item, $source) : $this->right->setItem($index - $this->right->getSize(), $item, $source); + public function setItem($index, Item $item){ + return $index < $this->left->getSize() ? $this->left->setItem($index, $item) : $this->right->setItem($index - $this->right->getSize(), $item); } - public function clear($index, $source = null){ - return $index < $this->left->getSize() ? $this->left->clear($index, $source) : $this->right->clear($index - $this->right->getSize(), $source); + public function clear($index){ + return $index < $this->left->getSize() ? $this->left->clear($index) : $this->right->clear($index - $this->right->getSize()); } public function getContents(){ diff --git a/src/pocketmine/inventory/FurnaceInventory.php b/src/pocketmine/inventory/FurnaceInventory.php index 91d322f56..59d755b16 100644 --- a/src/pocketmine/inventory/FurnaceInventory.php +++ b/src/pocketmine/inventory/FurnaceInventory.php @@ -85,8 +85,8 @@ class FurnaceInventory extends ContainerInventory{ return $this->setItem(0, $item); } - public function onSlotChange($index, $before, $source = null){ - parent::onSlotChange($index, $before, $source); + public function onSlotChange($index, $before){ + parent::onSlotChange($index, $before); $this->getHolder()->scheduleUpdate(); } diff --git a/src/pocketmine/inventory/Inventory.php b/src/pocketmine/inventory/Inventory.php index ce3a71751..792e3dded 100644 --- a/src/pocketmine/inventory/Inventory.php +++ b/src/pocketmine/inventory/Inventory.php @@ -57,17 +57,16 @@ interface Inventory{ * * @param int $index * @param Item $item - * @param Player $source * * @return bool */ - public function setItem($index, Item $item, $source = null); + public function setItem($index, Item $item); /** * Stores the given Items in the inventory. This will try to fill * existing stacks and empty slots as well as it can. * - * Returns the Items that did not fit. A Player source can be set at the end + * Returns the Items that did not fit. * * @param Item ...$item * @@ -86,7 +85,7 @@ interface Inventory{ /** * Removes the given Item from the inventory. - * It will return the Items that couldn't be removed. A Player source can be set at the end + * It will return the Items that couldn't be removed. * * @param Item ...$item * @@ -163,11 +162,10 @@ interface Inventory{ * Will clear a specific slot * * @param int $index - * @param Player $source * * @return bool */ - public function clear($index, $source = null); + public function clear($index); /** * Clears all the slots @@ -176,13 +174,11 @@ interface Inventory{ /** * Gets all the Players viewing the inventory - * Players will be viewing their inventory at all times, even when not open. - * - * @param Player $source + * Players will view their inventory at all times, even when not open. * * @return Player[] */ - public function getViewers($source = null); + public function getViewers(); /** * @return InventoryType @@ -218,7 +214,6 @@ interface Inventory{ /** * @param int $index * @param Item $before - * @param Player $source */ - public function onSlotChange($index, $before, $source = null); + public function onSlotChange($index, $before); } diff --git a/src/pocketmine/inventory/PlayerInventory.php b/src/pocketmine/inventory/PlayerInventory.php index 805c95c74..5e33f0cdf 100644 --- a/src/pocketmine/inventory/PlayerInventory.php +++ b/src/pocketmine/inventory/PlayerInventory.php @@ -88,12 +88,11 @@ class PlayerInventory extends BaseInventory{ /** * @param Item $item - * @param $source * * @return bool */ - public function setItemInHand(Item $item, $source = null){ - return $this->setItem($this->getHeldItemSlot(), $item, $source); + public function setItemInHand(Item $item){ + return $this->setItem($this->getHeldItemSlot(), $item); } public function getHeldItemSlot(){ @@ -153,11 +152,16 @@ class PlayerInventory extends BaseInventory{ } } - public function onSlotChange($index, $before, $source = null){ - parent::onSlotChange($index, $before, $source); + public function onSlotChange($index, $before){ + $holder = $this->getHolder(); + if($holder instanceof Player and !$holder->spawned){ + return; + } + + parent::onSlotChange($index, $before); if($index >= $this->getSize()){ - $this->sendArmorSlot($index, $this->getViewers($source)); + $this->sendArmorSlot($index, $this->getViewers()); $this->sendArmorSlot($index, $this->getHolder()->getViewers()); } } @@ -170,8 +174,8 @@ class PlayerInventory extends BaseInventory{ return $this->getItem($this->getSize() + $index); } - public function setArmorItem($index, Item $item, $source = null){ - return $this->setItem($this->getSize() + $index, $item, $source); + public function setArmorItem($index, Item $item){ + return $this->setItem($this->getSize() + $index, $item); } public function getHelmet(){ @@ -206,11 +210,11 @@ class PlayerInventory extends BaseInventory{ return $this->setItem($this->getSize() + 3, $boots); } - public function setItem($index, Item $item, $source = null){ + public function setItem($index, Item $item){ if($index < 0 or $index >= $this->size){ return false; }elseif($item->getId() === 0 or $item->getCount() <= 0){ - return $this->clear($index, $source); + return $this->clear($index); } if($index >= $this->getSize()){ //Armor change @@ -240,12 +244,12 @@ class PlayerInventory extends BaseInventory{ $old = $this->getItem($index); $this->slots[$index] = clone $item; - $this->onSlotChange($index, $old, $source); + $this->onSlotChange($index, $old); return true; } - public function clear($index, $source = null){ + public function clear($index){ if(isset($this->slots[$index])){ $item = Item::get(Item::AIR, null, 0); $old = $this->slots[$index]; @@ -278,7 +282,7 @@ class PlayerInventory extends BaseInventory{ unset($this->slots[$index]); } - $this->onSlotChange($index, $old, $source); + $this->onSlotChange($index, $old); } return true; diff --git a/src/pocketmine/inventory/SimpleTransactionGroup.php b/src/pocketmine/inventory/SimpleTransactionGroup.php index b3f52b27d..672bdcd22 100644 --- a/src/pocketmine/inventory/SimpleTransactionGroup.php +++ b/src/pocketmine/inventory/SimpleTransactionGroup.php @@ -151,7 +151,7 @@ class SimpleTransactionGroup implements TransactionGroup{ } foreach($this->transactions as $transaction){ - $transaction->getInventory()->setItem($transaction->getSlot(), $transaction->getTargetItem(), $this->getSource()); + $transaction->getInventory()->setItem($transaction->getSlot(), $transaction->getTargetItem()); } $this->hasExecuted = true; diff --git a/src/pocketmine/level/generator/noise/Perlin.php b/src/pocketmine/level/generator/noise/Perlin.php index 6abbdc2f3..6b9c76ed9 100644 --- a/src/pocketmine/level/generator/noise/Perlin.php +++ b/src/pocketmine/level/generator/noise/Perlin.php @@ -45,11 +45,11 @@ class Perlin extends Noise{ } for($i = 0; $i < 256; ++$i){ - $this->perm[$i] = $random->nextRange(0, 255); + $this->perm[$i] = $random->nextBoundedInt(256); } for($i = 0; $i < 256; ++$i){ - $pos = $random->nextRange(0, 255 - $i) + $i; + $pos = $random->nextBoundedInt(256 - $i) + $i; $old = $this->perm[$i]; $this->perm[$i] = $this->perm[$pos]; diff --git a/src/pocketmine/level/generator/object/BirchTree.php b/src/pocketmine/level/generator/object/BirchTree.php new file mode 100644 index 000000000..65f846339 --- /dev/null +++ b/src/pocketmine/level/generator/object/BirchTree.php @@ -0,0 +1,47 @@ +trunkBlock = Block::LOG; + $this->leafBlock = Block::LEAVES; + $this->type = Wood::BIRCH; + $this->superBirch = (bool) $superBirch; + } + + public function placeObject(ChunkManager $level, $x, $y, $z, Random $random){ + $this->treeHeight = $random->nextBoundedInt(3) + 5; + if($this->superBirch){ + $this->treeHeight += 5; + } + parent::placeObject($level, $x, $y, $z, $random); + } +} \ No newline at end of file diff --git a/src/pocketmine/level/generator/object/JungleTree.php b/src/pocketmine/level/generator/object/JungleTree.php new file mode 100644 index 000000000..d63a6cee1 --- /dev/null +++ b/src/pocketmine/level/generator/object/JungleTree.php @@ -0,0 +1,35 @@ +trunkBlock = Block::LOG; + $this->leafBlock = Block::LEAVES; + $this->type = Wood::JUNGLE; + $this->treeHeight = 8; + } +} \ No newline at end of file diff --git a/src/pocketmine/level/generator/object/OakTree.php b/src/pocketmine/level/generator/object/OakTree.php new file mode 100644 index 000000000..661e6ad13 --- /dev/null +++ b/src/pocketmine/level/generator/object/OakTree.php @@ -0,0 +1,41 @@ +trunkBlock = Block::LOG; + $this->leafBlock = Block::LEAVES; + $this->type = Wood::OAK; + } + + public function placeObject(ChunkManager $level, $x, $y, $z, Random $random){ + $this->treeHeight = $random->nextBoundedInt(3) + 4; + parent::placeObject($level, $x, $y, $z, $random); + } +} \ No newline at end of file diff --git a/src/pocketmine/level/generator/object/Ore.php b/src/pocketmine/level/generator/object/Ore.php index 262a2e614..0bb4d5f61 100644 --- a/src/pocketmine/level/generator/object/Ore.php +++ b/src/pocketmine/level/generator/object/Ore.php @@ -50,8 +50,8 @@ class Ore{ $x2 = $x + 8 - $offset->x; $z1 = $z + 8 + $offset->y; $z2 = $z + 8 - $offset->y; - $y1 = $y + $this->random->nextRange(0, 3) + 2; - $y2 = $y + $this->random->nextRange(0, 3) + 2; + $y1 = $y + $this->random->nextBoundedInt(3) + 2; + $y2 = $y + $this->random->nextBoundedInt(3) + 2; for($count = 0; $count <= $clusterSize; ++$count){ $seedX = $x1 + ($x2 - $x1) * $count / $clusterSize; $seedY = $y1 + ($y2 - $y1) * $count / $clusterSize; diff --git a/src/pocketmine/level/generator/object/PineTree.php b/src/pocketmine/level/generator/object/PineTree.php deleted file mode 100644 index 49a665c54..000000000 --- a/src/pocketmine/level/generator/object/PineTree.php +++ /dev/null @@ -1,96 +0,0 @@ -findRandomLeavesSize($random); - $checkRadius = 0; - for($yy = 0; $yy < $this->totalHeight; ++$yy){ - if($yy === $this->leavesSizeY){ - $checkRadius = $this->leavesAbsoluteMaxRadius; - } - for($xx = -$checkRadius; $xx < ($checkRadius + 1); ++$xx){ - for($zz = -$checkRadius; $zz < ($checkRadius + 1); ++$zz){ - if(!isset($this->overridable[$level->getBlockIdAt($x + $xx, $y + $yy, $z + $zz)])){ - return false; - } - } - } - } - - return true; - } - - private function findRandomLeavesSize(Random $random){ - $this->totalHeight += $random->nextRange(-1, 2); - $this->leavesSizeY = 1 + $random->nextRange(0, 2); - $this->leavesAbsoluteMaxRadius = 2 + $random->nextRange(0, 1); - } - - public function placeObject(ChunkManager $level, $x, $y, $z, Random $random){ - if($this->leavesSizeY === -1 or $this->leavesAbsoluteMaxRadius === -1){ - $this->findRandomLeavesSize($random); - } - $level->setBlockIdAt($x, $y - 1, $z, Block::DIRT); - $leavesRadius = 0; - $leavesMaxRadius = 1; - $leavesBottomY = $this->totalHeight - $this->leavesSizeY; - $firstMaxedRadius = false; - for($leavesY = 0; $leavesY <= $leavesBottomY; ++$leavesY){ - $yy = $this->totalHeight - $leavesY; - for($xx = -$leavesRadius; $xx <= $leavesRadius; ++$xx){ - for($zz = -$leavesRadius; $zz <= $leavesRadius; ++$zz){ - if(abs($xx) != $leavesRadius or abs($zz) != $leavesRadius or $leavesRadius <= 0){ - $level->setBlockIdAt($x + $xx, $y + $yy, $z + $zz, Block::LEAVES); - $level->setBlockDataAt($x + $xx, $y + $yy, $z + $zz, $this->type); - } - } - } - if($leavesRadius >= $leavesMaxRadius){ - $leavesRadius = $firstMaxedRadius ? 1 : 0; - $firstMaxedRadius = true; - if(++$leavesMaxRadius > $this->leavesAbsoluteMaxRadius){ - $leavesMaxRadius = $this->leavesAbsoluteMaxRadius; - } - }else{ - ++$leavesRadius; - } - } - $trunkHeightReducer = $random->nextRange(0, 3); - for($yy = 0; $yy < ($this->totalHeight - $trunkHeightReducer); ++$yy){ - $level->setBlockIdAt($x, $y + $yy, $z, Block::TRUNK); - $level->setBlockDataAt($x, $y + $yy, $z, $this->type); - } - } - - -} \ No newline at end of file diff --git a/src/pocketmine/level/generator/object/SmallTree.php b/src/pocketmine/level/generator/object/SmallTree.php deleted file mode 100644 index ee83efb63..000000000 --- a/src/pocketmine/level/generator/object/SmallTree.php +++ /dev/null @@ -1,98 +0,0 @@ -trunkHeight + 3; ++$yy){ - if($yy == 1 or $yy === $this->trunkHeight){ - ++$radiusToCheck; - } - for($xx = -$radiusToCheck; $xx < ($radiusToCheck + 1); ++$xx){ - for($zz = -$radiusToCheck; $zz < ($radiusToCheck + 1); ++$zz){ - if(!isset($this->overridable[$level->getBlockIdAt($x + $xx, $y + $yy, $z + $zz)])){ - return false; - } - } - } - } - - return true; - } - - public function placeObject(ChunkManager $level, $x, $y, $z, Random $random){ - // The base dirt block - $level->setBlockIdAt($x, $y, $z, Block::DIRT); - - // Adjust the tree trunk's height randomly - // plot [-14:11] int( x / 8 ) + 5 - // - min=4 (all leaves are 4 tall, some trunk must show) - // - max=6 (top leaves are within ground-level whacking range - // on all small trees) - $heightPre = $random->nextRange(-14, 11); - $this->trunkHeight = intval($heightPre / 8) + 5; - - // Adjust the starting leaf density using the trunk height as a - // starting position (tall trees with skimpy leaves don't look - // too good) - $leafPre = $random->nextRange($this->trunkHeight, 10) / 20; // (TODO: seed may apply) - - // Now build the tree (from the top down) - $leaflevel = 0; - for($yy = ($this->trunkHeight + 1); $yy >= 0; --$yy){ - if($leaflevel < self::$leavesHeight){ - // The size is a slight variation on the trunkheight - $radius = self::$leafRadii[$leaflevel] + $leafPre; - $bRadius = 3; - for($xx = -$bRadius; $xx <= $bRadius; ++$xx){ - for($zz = -$bRadius; $zz <= $bRadius; ++$zz){ - if(sqrt($xx ** 2 + $zz ** 2) <= $radius){ - $level->setBlockIdAt($x + $xx, $y + $yy, $z + $zz, Block::LEAVES); - $level->setBlockDataAt($x + $xx, $y + $yy, $z + $zz, $this->type); - } - } - } - $leaflevel++; - } - - // Place the trunk last - if($leaflevel > 1){ - $level->setBlockIdAt($x, $y + $yy, $z, Block::TRUNK); - $level->setBlockDataAt($x, $y + $yy, $z, $this->type); - } - } - } -} \ No newline at end of file diff --git a/src/pocketmine/level/generator/object/SpruceTree.php b/src/pocketmine/level/generator/object/SpruceTree.php index 950081762..59301020e 100644 --- a/src/pocketmine/level/generator/object/SpruceTree.php +++ b/src/pocketmine/level/generator/object/SpruceTree.php @@ -22,64 +22,56 @@ namespace pocketmine\level\generator\object; use pocketmine\block\Block; +use pocketmine\block\Wood; use pocketmine\level\ChunkManager; use pocketmine\utils\Random; class SpruceTree extends Tree{ - var $type = 1; - private $totalHeight = 8; - private $leavesBottomY = -1; - private $leavesMaxRadius = -1; - public function canPlaceObject(ChunkManager $level, $x, $y, $z, Random $random){ - $this->findRandomLeavesSize($random); - $checkRadius = 0; - for($yy = 0; $yy < $this->totalHeight + 2; ++$yy){ - if($yy === $this->leavesBottomY){ - $checkRadius = $this->leavesMaxRadius; - } - for($xx = -$checkRadius; $xx < ($checkRadius + 1); ++$xx){ - for($zz = -$checkRadius; $zz < ($checkRadius + 1); ++$zz){ - if(!isset($this->overridable[$level->getBlockIdAt($x + $xx, $y + $yy, $z + $zz)])){ - return false; - } - } - } - } - - return true; - } - - private function findRandomLeavesSize(Random $random){ - $this->totalHeight += $random->nextRange(-1, 2); - $this->leavesBottomY = (int) ($this->totalHeight - $random->nextRange(1, 2) - 3); - $this->leavesMaxRadius = 1 + $random->nextRange(0, 1); + public function __construct(){ + $this->trunkBlock = Block::LOG; + $this->leafBlock = Block::LEAVES; + $this->type = Wood::SPRUCE; + $this->treeHeight = 10; } public function placeObject(ChunkManager $level, $x, $y, $z, Random $random){ - if($this->leavesBottomY === -1 or $this->leavesMaxRadius === -1){ - $this->findRandomLeavesSize($random); - } - $level->setBlockIdAt($x, $y - 1, $z, Block::DIRT); - $leavesRadius = 0; - for($yy = $this->totalHeight; $yy >= $this->leavesBottomY; --$yy){ - for($xx = -$leavesRadius; $xx <= $leavesRadius; ++$xx){ - for($zz = -$leavesRadius; $zz <= $leavesRadius; ++$zz){ - if(abs($xx) != $leavesRadius or abs($zz) != $leavesRadius or $leavesRadius <= 0){ - $level->setBlockIdAt($x + $xx, $y + $yy, $z + $zz, Block::LEAVES); - $level->setBlockDataAt($x + $xx, $y + $yy, $z + $zz, $this->type); + $this->treeHeight = $random->nextBoundedInt(4) + 6; + + $topSize = $this->treeHeight - (1 + $random->nextBoundedInt(2)); + $lRadius = 2 + $random->nextBoundedInt(2); + + $this->placeTrunk($level, $x, $y, $z, $random, $this->treeHeight - $random->nextBoundedInt(3)); + + $radius = $random->nextBoundedInt(2); + $maxR = 1; + $minR = 0; + + for($yy = 0; $yy <= $topSize; ++$yy){ + $yyy = $y + $this->treeHeight - $yy; + + for($xx = $x - $radius; $xx <= $x + $radius; ++$xx){ + $xOff = $xx - $x; + for($zz = $z - $radius; $zz <= $z + $radius; ++$zz){ + $zOff = $zz - $z; + if(abs($xOff) === $radius and abs($zOff) === $radius and $radius > 0){ + continue; } + + $level->setBlockIdAt($xx, $yyy, $zz, $this->leafBlock); + $level->setBlockDataAt($xx, $yyy, $zz, $this->type); + } + } + + if($radius >= $maxR){ + $radius = $minR; + $minR = 1; + if(++$maxR > $lRadius){ + $maxR = $lRadius; } + }else{ + ++$radius; } - if($leavesRadius > 0 and $yy === ($y + $this->leavesBottomY + 1)){ - --$leavesRadius; - }elseif($leavesRadius < $this->leavesMaxRadius){ - ++$leavesRadius; - } - } - for($yy = 0; $yy < ($this->totalHeight - 1); ++$yy){ - $level->setBlockIdAt($x, $y + $yy, $z, Block::TRUNK); - $level->setBlockDataAt($x, $y + $yy, $z, $this->type); } } diff --git a/src/pocketmine/level/generator/object/Tree.php b/src/pocketmine/level/generator/object/Tree.php index 15b6a013e..331436836 100644 --- a/src/pocketmine/level/generator/object/Tree.php +++ b/src/pocketmine/level/generator/object/Tree.php @@ -26,11 +26,9 @@ use pocketmine\block\Sapling; use pocketmine\level\ChunkManager; use pocketmine\utils\Random; -class Tree{ +abstract class Tree{ public $overridable = [ - 0 => true, - 2 => true, - 3 => true, + Block::AIR => true, 6 => true, 17 => true, 18 => true, @@ -39,29 +37,33 @@ class Tree{ Block::LEAVES2 => true ]; + public $type = 0; + public $trunkBlock = Block::LOG; + public $leafBlock = Block::LEAVES; + public $treeHeight = 7; + public static function growTree(ChunkManager $level, $x, $y, $z, Random $random, $type = 0){ - switch($type & 0x03){ + switch($type){ case Sapling::SPRUCE: - if($random->nextRange(0, 1) === 1){ - $tree = new SpruceTree(); - }else{ - $tree = new PineTree(); - } + $tree = new SpruceTree(); break; case Sapling::BIRCH: - $tree = new SmallTree(); - $tree->type = Sapling::BIRCH; + if($random->nextBoundedInt(39) === 0){ + $tree = new BirchTree(true); + }else{ + $tree = new BirchTree(); + } break; case Sapling::JUNGLE: - $tree = new SmallTree(); - $tree->type = Sapling::JUNGLE; + $tree = new JungleTree(); break; case Sapling::OAK: default: + $tree = new OakTree(); /*if($random->nextRange(0, 9) === 0){ $tree = new BigTree(); }else{*/ - $tree = new SmallTree(); + //} break; } @@ -69,4 +71,57 @@ class Tree{ $tree->placeObject($level, $x, $y, $z, $random); } } + + + public function canPlaceObject(ChunkManager $level, $x, $y, $z, Random $random){ + $radiusToCheck = 0; + for($yy = 0; $yy < $this->treeHeight + 3; ++$yy){ + if($yy == 1 or $yy === $this->treeHeight){ + ++$radiusToCheck; + } + for($xx = -$radiusToCheck; $xx < ($radiusToCheck + 1); ++$xx){ + for($zz = -$radiusToCheck; $zz < ($radiusToCheck + 1); ++$zz){ + if(!isset($this->overridable[$level->getBlockIdAt($x + $xx, $y + $yy, $z + $zz)])){ + return false; + } + } + } + } + + return true; + } + + public function placeObject(ChunkManager $level, $x, $y, $z, Random $random){ + + $this->placeTrunk($level, $x, $y, $z, $random, $this->treeHeight - 1); + + for($yy = $y - 3 + $this->treeHeight; $yy <= $y + $this->treeHeight; ++$yy){ + $yOff = $yy - ($y + $this->treeHeight); + $mid = (int) (1 - $yOff / 2); + for($xx = $x - $mid; $xx <= $x + $mid; ++$xx){ + $xOff = $xx - $x; + for($zz = $z - $mid; $zz <= $z + $mid; ++$zz){ + $zOff = $zz - $z; + if(abs($xOff) === $mid and abs($zOff) === $mid and ($yOff === 0 or $random->nextBoundedInt(2) === 0)){ + continue; + } + $level->setBlockIdAt($xx, $yy, $zz, $this->leafBlock); + $level->setBlockDataAt($xx, $yy, $zz, $this->type); + } + } + } + } + + protected function placeTrunk(ChunkManager $level, $x, $y, $z, Random $random, $trunkHeight){ + // The base dirt block + $level->setBlockIdAt($x, $y - 1, $z, Block::DIRT); + + for($yy = 0; $yy <= $trunkHeight; ++$yy){ + $blockId = $level->getBlockIdAt($x, $y + $yy, $z); + if(isset($this->overridable[$blockId])){ + $level->setBlockIdAt($x, $y + $yy, $z, $this->trunkBlock); + $level->setBlockDataAt($x, $y + $yy, $z, $this->type); + } + } + } } \ No newline at end of file diff --git a/src/pocketmine/level/generator/populator/Pond.php b/src/pocketmine/level/generator/populator/Pond.php index 03c110ebe..a660715a4 100644 --- a/src/pocketmine/level/generator/populator/Pond.php +++ b/src/pocketmine/level/generator/populator/Pond.php @@ -33,7 +33,7 @@ class Pond extends Populator{ public function populate(ChunkManager $level, $chunkX, $chunkZ, Random $random){ if($random->nextRange(0, $this->waterOdd) === 0){ $x = $random->nextRange($chunkX << 4, ($chunkX << 4) + 16); - $y = $random->nextRange(0, 128); + $y = $random->nextBoundedInt(128); $z = $random->nextRange($chunkZ << 4, ($chunkZ << 4) + 16); $pond = new \pocketmine\level\generator\object\Pond($random, new Water()); if($pond->canPlaceObject($level, $x, $y, $z)){ diff --git a/src/pocketmine/utils/Random.php b/src/pocketmine/utils/Random.php index 288472986..087f9666c 100644 --- a/src/pocketmine/utils/Random.php +++ b/src/pocketmine/utils/Random.php @@ -110,4 +110,8 @@ class Random{ return $start + ($this->nextInt() % ($end + 1 - $start)); } + public function nextBoundedInt($bound){ + return $this->nextInt() % $bound; + } + } \ No newline at end of file