Improved trees, improved inventory transactions, improved snowball/bow usage

This commit is contained in:
Shoghi Cervantes 2015-03-28 16:59:15 +01:00
parent 47de616ac5
commit 0a85ad0d1f
No known key found for this signature in database
GPG Key ID: 78464DB0A7837F89
22 changed files with 363 additions and 360 deletions

View File

@ -76,6 +76,7 @@ use pocketmine\level\generator\biome\Biome;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\level\Location; use pocketmine\level\Location;
use pocketmine\level\Position; use pocketmine\level\Position;
use pocketmine\level\sound\LaunchSound;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\metadata\MetadataValue; use pocketmine\metadata\MetadataValue;
@ -172,7 +173,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
protected $username; protected $username;
protected $iusername; protected $iusername;
protected $displayName; protected $displayName;
protected $startAction = false; protected $startAction = -1;
/** @var Vector3 */ /** @var Vector3 */
protected $sleeping = null; protected $sleeping = null;
protected $clientID = null; protected $clientID = null;
@ -1275,7 +1276,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
$pk->eid = $this->getId(); $pk->eid = $this->getId();
$pk->target = $entity->getId(); $pk->target = $entity->getId();
Server::broadcastPacket($entity->getViewers(), $pk); Server::broadcastPacket($entity->getViewers(), $pk);
$this->inventory->addItem(clone $item, $this); $this->inventory->addItem(clone $item);
$entity->kill(); $entity->kill();
} }
}elseif($entity instanceof DroppedItem){ }elseif($entity instanceof DroppedItem){
@ -1305,7 +1306,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
$pk->eid = $this->getId(); $pk->eid = $this->getId();
$pk->target = $entity->getId(); $pk->target = $entity->getId();
Server::broadcastPacket($entity->getViewers(), $pk); Server::broadcastPacket($entity->getViewers(), $pk);
$this->inventory->addItem(clone $item, $this); $this->inventory->addItem(clone $item);
$entity->kill(); $entity->kill();
} }
} }
@ -1687,6 +1688,8 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
$this->inventory->sendHeldItem($this); $this->inventory->sendHeldItem($this);
break; break;
}elseif($packet->face === 0xff){ }elseif($packet->face === 0xff){
$aimPos = (new Vector3($packet->x / 32768, $packet->y / 32768, $packet->z / 32768))->normalize();
if($this->isCreative()){ if($this->isCreative()){
$item = $this->inventory->getItemInHand(); $item = $this->inventory->getItemInHand();
}elseif($this->inventory->getItemInHand()->getId() !== $packet->item or (($damage = $this->inventory->getItemInHand()->getDamage()) !== $packet->meta and $damage !== null)){ }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{ }else{
$item = $this->inventory->getItemInHand(); $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); $this->server->getPluginManager()->callEvent($ev);
@ -1714,9 +1716,9 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
new Double("", $this->z) new Double("", $this->z)
]), ]),
"Motion" => new Enum("Motion", [ "Motion" => new Enum("Motion", [
new Double("", -sin($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI)), new Double("", $aimPos->x),
new Double("", -sin($this->pitch / 180 * M_PI)), new Double("", $aimPos->y),
new Double("", cos($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI)) new Double("", $aimPos->z)
]), ]),
"Rotation" => new Enum("Rotation", [ "Rotation" => new Enum("Rotation", [
new Float("", $this->yaw), 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 = Entity::createEntity("Snowball", $this->chunk, $nbt, $this);
$snowball->setMotion($snowball->getMotion()->multiply($f)); $snowball->setMotion($snowball->getMotion()->multiply($f));
if($this->isSurvival()){ 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){ if($snowball instanceof Projectile){
$this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($snowball)); $this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($snowball));
@ -1736,13 +1739,15 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
$snowball->kill(); $snowball->kill();
}else{ }else{
$snowball->spawnToAll(); $snowball->spawnToAll();
$this->level->addSound(new LaunchSound($this), $this->getViewers());
} }
}else{ }else{
$snowball->spawnToAll(); $snowball->spawnToAll();
} }
} }
$this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, true); $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, true);
$this->startAction = microtime(true); $this->startAction = $this->server->getTick();
} }
break; break;
case ProtocolInfo::PLAYER_ACTION_PACKET: case ProtocolInfo::PLAYER_ACTION_PACKET:
@ -1765,7 +1770,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
$this->lastBreak = microtime(true); $this->lastBreak = microtime(true);
break; break;
case 5: //Shot arrow 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(); $bow = $this->inventory->getItemInHand();
if($this->isSurvival()){ if($this->isSurvival()){
if(!$this->inventory->contains(Item::get(Item::ARROW, 0, 1))){ 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); $ev = new EntityShootBowEvent($this, $bow, Entity::createEntity("Arrow", $this->chunk, $nbt, $this), $f);
$this->server->getPluginManager()->callEvent($ev); $this->server->getPluginManager()->callEvent($ev);
@ -1802,11 +1815,12 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
}else{ }else{
$ev->getProjectile()->setMotion($ev->getProjectile()->getMotion()->multiply($ev->getForce())); $ev->getProjectile()->setMotion($ev->getProjectile()->getMotion()->multiply($ev->getForce()));
if($this->isSurvival()){ 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); $bow->setDamage($bow->getDamage() + 1);
$this->inventory->setItemInHand($bow, $this);
if($bow->getDamage() >= 385){ 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){ if($ev->getProjectile() instanceof Projectile){
@ -1815,20 +1829,21 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
$ev->getProjectile()->kill(); $ev->getProjectile()->kill();
}else{ }else{
$ev->getProjectile()->spawnToAll(); $ev->getProjectile()->spawnToAll();
$this->level->addSound(new LaunchSound($this), $this->getViewers());
} }
}else{ }else{
$ev->getProjectile()->spawnToAll(); $ev->getProjectile()->spawnToAll();
} }
} }
} }
$this->startAction = false;
$this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false);
break; break;
case 6: //get out of the bed case 6: //get out of the bed
$this->stopSleep(); $this->stopSleep();
break; break;
} }
$this->startAction = -1;
$this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false);
break; break;
case ProtocolInfo::REMOVE_BLOCK_PACKET: case ProtocolInfo::REMOVE_BLOCK_PACKET:
if($this->spawned === false or $this->blocked === true or $this->dead === true){ 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; --$slot->count;
$this->inventory->setItemInHand($slot, $this); $this->inventory->setItemInHand($slot, $this);
if($slot->getId() === Item::MUSHROOM_STEW or $slot->getId() === Item::BEETROOT_SOUP){ 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; break;
@ -2263,7 +2278,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
case Item::CAKE: case Item::CAKE:
//TODO: detect complex recipes like cake that leave remains //TODO: detect complex recipes like cake that leave remains
$this->awardAchievement("bakeCake"); $this->awardAchievement("bakeCake");
$this->inventory->addItem(Item::get(Item::BUCKET, 0, 3), $this); $this->inventory->addItem(Item::get(Item::BUCKET, 0, 3));
break; break;
case Item::STONE_PICKAXE: case Item::STONE_PICKAXE:
case Item::GOLD_PICKAXE: case Item::GOLD_PICKAXE:

View File

@ -69,11 +69,12 @@ class Arrow extends Projectile{
$pk->x = $this->x; $pk->x = $this->x;
$pk->y = $this->y; $pk->y = $this->y;
$pk->z = $this->z; $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->dataPacket($pk);
$player->addEntityMotion($this->getId(), $this->motionX, $this->motionY, $this->motionZ);
parent::spawnTo($player); parent::spawnTo($player);
} }
} }

View File

@ -87,6 +87,8 @@ abstract class Entity extends Location implements Metadatable{
const DATA_FLAG_ONFIRE = 0; const DATA_FLAG_ONFIRE = 0;
const DATA_FLAG_SNEAKING = 1;
const DATA_FLAG_RIDING = 2;
const DATA_FLAG_ACTION = 4; const DATA_FLAG_ACTION = 4;
const DATA_FLAG_INVISIBLE = 5; const DATA_FLAG_INVISIBLE = 5;

View File

@ -39,6 +39,7 @@ use pocketmine\utils\TextFormat;
class Human extends Creature implements ProjectileSource, InventoryHolder{ class Human extends Creature implements ProjectileSource, InventoryHolder{
const DATA_PLAYER_FLAG_SLEEP = 1; const DATA_PLAYER_FLAG_SLEEP = 1;
const DATA_PLAYER_FLAG_DEAD = 2;
const DATA_PLAYER_FLAGS = 16; const DATA_PLAYER_FLAGS = 16;
const DATA_PLAYER_BED_POSITION = 17; 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 if($item["Slot"] >= 0 and $item["Slot"] < 9){ //Hotbar
$this->inventory->setHotbarSlotIndex($item["Slot"], isset($item["TrueSlot"]) ? $item["TrueSlot"] : -1); $this->inventory->setHotbarSlotIndex($item["Slot"], isset($item["TrueSlot"]) ? $item["TrueSlot"] : -1);
}elseif($item["Slot"] >= 100 and $item["Slot"] < 104){ //Armor }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{ }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

View File

@ -24,6 +24,8 @@ namespace pocketmine\event\player;
use pocketmine\block\Block; use pocketmine\block\Block;
use pocketmine\event\Cancellable; use pocketmine\event\Cancellable;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\level\Position;
use pocketmine\math\Vector3;
use pocketmine\Player; use pocketmine\Player;
/** /**
@ -43,6 +45,8 @@ class PlayerInteractEvent extends PlayerEvent implements Cancellable{
*/ */
protected $blockTouched; protected $blockTouched;
protected $touchVector;
/** @var int */ /** @var int */
protected $blockFace; protected $blockFace;
@ -51,26 +55,51 @@ class PlayerInteractEvent extends PlayerEvent implements Cancellable{
protected $action; protected $action;
public function __construct(Player $player, Item $item, Block $block, $face, $action = PlayerInteractEvent::RIGHT_CLICK){ public function __construct(Player $player, Item $item, Vector3 $block, $face, $action = PlayerInteractEvent::RIGHT_CLICK_BLOCK){
$this->blockTouched = $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->player = $player;
$this->item = $item; $this->item = $item;
$this->blockFace = (int) $face; $this->blockFace = (int) $face;
$this->action = (int) $action; $this->action = (int) $action;
} }
/**
* @return int
*/
public function getAction(){ public function getAction(){
return $this->action; return $this->action;
} }
/**
* @return Item
*/
public function getItem(){ public function getItem(){
return $this->item; return $this->item;
} }
/**
* @return Block
*/
public function getBlock(){ public function getBlock(){
return $this->blockTouched; return $this->blockTouched;
} }
/**
* @return Vector3
*/
public function getTouchVector(){
return $this->touchVector;
}
/**
* @return int
*/
public function getFace(){ public function getFace(){
return $this->blockFace; return $this->blockFace;
} }

View File

@ -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; $item = clone $item;
if($index < 0 or $index >= $this->size){ if($index < 0 or $index >= $this->size){
return false; return false;
}elseif($item->getId() === 0 or $item->getCount() <= 0){ }elseif($item->getId() === 0 or $item->getCount() <= 0){
return $this->clear($index, $source); return $this->clear($index);
} }
$holder = $this->getHolder(); $holder = $this->getHolder();
@ -142,7 +142,7 @@ abstract class BaseInventory implements Inventory{
$old = $this->getItem($index); $old = $this->getItem($index);
$this->slots[$index] = clone $item; $this->slots[$index] = clone $item;
$this->onSlotChange($index, $old, $source); $this->onSlotChange($index, $old);
return true; return true;
} }
@ -227,14 +227,6 @@ abstract class BaseInventory implements Inventory{
} }
public function addItem(...$slots){ 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[] $itemSlots */
/** @var Item[] $slots */ /** @var Item[] $slots */
$itemSlots = []; $itemSlots = [];
@ -258,7 +250,7 @@ abstract class BaseInventory implements Inventory{
if($amount > 0){ if($amount > 0){
$slot->setCount($slot->getCount() - $amount); $slot->setCount($slot->getCount() - $amount);
$item->setCount($item->getCount() + $amount); $item->setCount($item->getCount() + $amount);
$this->setItem($i, $item, $source); $this->setItem($i, $item);
if($slot->getCount() <= 0){ if($slot->getCount() <= 0){
unset($itemSlots[$index]); unset($itemSlots[$index]);
} }
@ -273,12 +265,13 @@ abstract class BaseInventory implements Inventory{
if(count($itemSlots) > 0 and count($emptySlots) > 0){ if(count($itemSlots) > 0 and count($emptySlots) > 0){
foreach($emptySlots as $slotIndex){ foreach($emptySlots as $slotIndex){
//This loop only gets the first item, then goes to the next empty slot
foreach($itemSlots as $index => $slot){ foreach($itemSlots as $index => $slot){
$amount = min($slot->getMaxStackSize(), $slot->getCount(), $this->getMaxStackSize()); $amount = min($slot->getMaxStackSize(), $slot->getCount(), $this->getMaxStackSize());
$slot->setCount($slot->getCount() - $amount); $slot->setCount($slot->getCount() - $amount);
$item = clone $slot; $item = clone $slot;
$item->setCount($amount); $item->setCount($amount);
$this->setItem($slotIndex, $item, $source); $this->setItem($slotIndex, $item);
if($slot->getCount() <= 0){ if($slot->getCount() <= 0){
unset($itemSlots[$index]); unset($itemSlots[$index]);
} }
@ -291,14 +284,6 @@ abstract class BaseInventory implements Inventory{
} }
public function removeItem(...$slots){ 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[] $itemSlots */
/** @var Item[] $slots */ /** @var Item[] $slots */
$itemSlots = []; $itemSlots = [];
@ -319,7 +304,7 @@ abstract class BaseInventory implements Inventory{
$amount = min($item->getCount(), $slot->getCount()); $amount = min($item->getCount(), $slot->getCount());
$slot->setCount($slot->getCount() - $amount); $slot->setCount($slot->getCount() - $amount);
$item->setCount($item->getCount() - $amount); $item->setCount($item->getCount() - $amount);
$this->setItem($i, $item, $source); $this->setItem($i, $item);
if($slot->getCount() <= 0){ if($slot->getCount() <= 0){
unset($itemSlots[$index]); unset($itemSlots[$index]);
} }
@ -334,7 +319,7 @@ abstract class BaseInventory implements Inventory{
return $itemSlots; return $itemSlots;
} }
public function clear($index, $source = null){ public function clear($index){
if(isset($this->slots[$index])){ if(isset($this->slots[$index])){
$item = Item::get(Item::AIR, null, 0); $item = Item::get(Item::AIR, null, 0);
$old = $this->slots[$index]; $old = $this->slots[$index];
@ -353,7 +338,7 @@ abstract class BaseInventory implements Inventory{
unset($this->slots[$index]); unset($this->slots[$index]);
} }
$this->onSlotChange($index, $old, $source); $this->onSlotChange($index, $old);
} }
return true; return true;
@ -366,20 +351,10 @@ abstract class BaseInventory implements Inventory{
} }
/** /**
* @param Player $source
*
* @return Player[] * @return Player[]
*/ */
public function getViewers($source = null){ public function getViewers(){
$viewers = []; return $this->viewers;
foreach($this->viewers as $viewer){
if($viewer === $source){
continue;
}
$viewers[] = $viewer;
}
return $viewers;
} }
public function getHolder(){ public function getHolder(){
@ -412,8 +387,8 @@ abstract class BaseInventory implements Inventory{
unset($this->viewers[spl_object_hash($who)]); unset($this->viewers[spl_object_hash($who)]);
} }
public function onSlotChange($index, $before, $source = null){ public function onSlotChange($index, $before){
$this->sendSlot($index, $this->getViewers($source)); $this->sendSlot($index, $this->getViewers());
} }

View File

@ -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()); return $index < $this->left->getSize() ? $this->left->getItem($index) : $this->right->getItem($index - $this->right->getSize());
} }
public function setItem($index, Item $item, $source = null){ public function setItem($index, Item $item){
return $index < $this->left->getSize() ? $this->left->setItem($index, $item, $source) : $this->right->setItem($index - $this->right->getSize(), $item, $source); return $index < $this->left->getSize() ? $this->left->setItem($index, $item) : $this->right->setItem($index - $this->right->getSize(), $item);
} }
public function clear($index, $source = null){ public function clear($index){
return $index < $this->left->getSize() ? $this->left->clear($index, $source) : $this->right->clear($index - $this->right->getSize(), $source); return $index < $this->left->getSize() ? $this->left->clear($index) : $this->right->clear($index - $this->right->getSize());
} }
public function getContents(){ public function getContents(){

View File

@ -85,8 +85,8 @@ class FurnaceInventory extends ContainerInventory{
return $this->setItem(0, $item); return $this->setItem(0, $item);
} }
public function onSlotChange($index, $before, $source = null){ public function onSlotChange($index, $before){
parent::onSlotChange($index, $before, $source); parent::onSlotChange($index, $before);
$this->getHolder()->scheduleUpdate(); $this->getHolder()->scheduleUpdate();
} }

View File

@ -57,17 +57,16 @@ interface Inventory{
* *
* @param int $index * @param int $index
* @param Item $item * @param Item $item
* @param Player $source
* *
* @return bool * @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 * Stores the given Items in the inventory. This will try to fill
* existing stacks and empty slots as well as it can. * 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 * @param Item ...$item
* *
@ -86,7 +85,7 @@ interface Inventory{
/** /**
* Removes the given Item from the 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 * @param Item ...$item
* *
@ -163,11 +162,10 @@ interface Inventory{
* Will clear a specific slot * Will clear a specific slot
* *
* @param int $index * @param int $index
* @param Player $source
* *
* @return bool * @return bool
*/ */
public function clear($index, $source = null); public function clear($index);
/** /**
* Clears all the slots * Clears all the slots
@ -176,13 +174,11 @@ interface Inventory{
/** /**
* Gets all the Players viewing the inventory * Gets all the Players viewing the inventory
* Players will be viewing their inventory at all times, even when not open. * Players will view their inventory at all times, even when not open.
*
* @param Player $source
* *
* @return Player[] * @return Player[]
*/ */
public function getViewers($source = null); public function getViewers();
/** /**
* @return InventoryType * @return InventoryType
@ -218,7 +214,6 @@ interface Inventory{
/** /**
* @param int $index * @param int $index
* @param Item $before * @param Item $before
* @param Player $source
*/ */
public function onSlotChange($index, $before, $source = null); public function onSlotChange($index, $before);
} }

View File

@ -88,12 +88,11 @@ class PlayerInventory extends BaseInventory{
/** /**
* @param Item $item * @param Item $item
* @param $source
* *
* @return bool * @return bool
*/ */
public function setItemInHand(Item $item, $source = null){ public function setItemInHand(Item $item){
return $this->setItem($this->getHeldItemSlot(), $item, $source); return $this->setItem($this->getHeldItemSlot(), $item);
} }
public function getHeldItemSlot(){ public function getHeldItemSlot(){
@ -153,11 +152,16 @@ class PlayerInventory extends BaseInventory{
} }
} }
public function onSlotChange($index, $before, $source = null){ public function onSlotChange($index, $before){
parent::onSlotChange($index, $before, $source); $holder = $this->getHolder();
if($holder instanceof Player and !$holder->spawned){
return;
}
parent::onSlotChange($index, $before);
if($index >= $this->getSize()){ if($index >= $this->getSize()){
$this->sendArmorSlot($index, $this->getViewers($source)); $this->sendArmorSlot($index, $this->getViewers());
$this->sendArmorSlot($index, $this->getHolder()->getViewers()); $this->sendArmorSlot($index, $this->getHolder()->getViewers());
} }
} }
@ -170,8 +174,8 @@ class PlayerInventory extends BaseInventory{
return $this->getItem($this->getSize() + $index); return $this->getItem($this->getSize() + $index);
} }
public function setArmorItem($index, Item $item, $source = null){ public function setArmorItem($index, Item $item){
return $this->setItem($this->getSize() + $index, $item, $source); return $this->setItem($this->getSize() + $index, $item);
} }
public function getHelmet(){ public function getHelmet(){
@ -206,11 +210,11 @@ class PlayerInventory extends BaseInventory{
return $this->setItem($this->getSize() + 3, $boots); 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){ if($index < 0 or $index >= $this->size){
return false; return false;
}elseif($item->getId() === 0 or $item->getCount() <= 0){ }elseif($item->getId() === 0 or $item->getCount() <= 0){
return $this->clear($index, $source); return $this->clear($index);
} }
if($index >= $this->getSize()){ //Armor change if($index >= $this->getSize()){ //Armor change
@ -240,12 +244,12 @@ class PlayerInventory extends BaseInventory{
$old = $this->getItem($index); $old = $this->getItem($index);
$this->slots[$index] = clone $item; $this->slots[$index] = clone $item;
$this->onSlotChange($index, $old, $source); $this->onSlotChange($index, $old);
return true; return true;
} }
public function clear($index, $source = null){ public function clear($index){
if(isset($this->slots[$index])){ if(isset($this->slots[$index])){
$item = Item::get(Item::AIR, null, 0); $item = Item::get(Item::AIR, null, 0);
$old = $this->slots[$index]; $old = $this->slots[$index];
@ -278,7 +282,7 @@ class PlayerInventory extends BaseInventory{
unset($this->slots[$index]); unset($this->slots[$index]);
} }
$this->onSlotChange($index, $old, $source); $this->onSlotChange($index, $old);
} }
return true; return true;

View File

@ -151,7 +151,7 @@ class SimpleTransactionGroup implements TransactionGroup{
} }
foreach($this->transactions as $transaction){ foreach($this->transactions as $transaction){
$transaction->getInventory()->setItem($transaction->getSlot(), $transaction->getTargetItem(), $this->getSource()); $transaction->getInventory()->setItem($transaction->getSlot(), $transaction->getTargetItem());
} }
$this->hasExecuted = true; $this->hasExecuted = true;

View File

@ -45,11 +45,11 @@ class Perlin extends Noise{
} }
for($i = 0; $i < 256; ++$i){ 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){ for($i = 0; $i < 256; ++$i){
$pos = $random->nextRange(0, 255 - $i) + $i; $pos = $random->nextBoundedInt(256 - $i) + $i;
$old = $this->perm[$i]; $old = $this->perm[$i];
$this->perm[$i] = $this->perm[$pos]; $this->perm[$i] = $this->perm[$pos];

View File

@ -0,0 +1,47 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\level\generator\object;
use pocketmine\block\Block;
use pocketmine\block\Wood;
use pocketmine\level\ChunkManager;
use pocketmine\utils\Random;
class BirchTree extends Tree{
protected $superBirch = false;
public function __construct($superBirch = false){
$this->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);
}
}

View File

@ -0,0 +1,35 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\level\generator\object;
use pocketmine\block\Block;
use pocketmine\block\Wood;
class JungleTree extends Tree{
public function __construct(){
$this->trunkBlock = Block::LOG;
$this->leafBlock = Block::LEAVES;
$this->type = Wood::JUNGLE;
$this->treeHeight = 8;
}
}

View File

@ -0,0 +1,41 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\level\generator\object;
use pocketmine\block\Block;
use pocketmine\block\Wood;
use pocketmine\level\ChunkManager;
use pocketmine\utils\Random;
class OakTree extends Tree{
public function __construct(){
$this->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);
}
}

View File

@ -50,8 +50,8 @@ class Ore{
$x2 = $x + 8 - $offset->x; $x2 = $x + 8 - $offset->x;
$z1 = $z + 8 + $offset->y; $z1 = $z + 8 + $offset->y;
$z2 = $z + 8 - $offset->y; $z2 = $z + 8 - $offset->y;
$y1 = $y + $this->random->nextRange(0, 3) + 2; $y1 = $y + $this->random->nextBoundedInt(3) + 2;
$y2 = $y + $this->random->nextRange(0, 3) + 2; $y2 = $y + $this->random->nextBoundedInt(3) + 2;
for($count = 0; $count <= $clusterSize; ++$count){ for($count = 0; $count <= $clusterSize; ++$count){
$seedX = $x1 + ($x2 - $x1) * $count / $clusterSize; $seedX = $x1 + ($x2 - $x1) * $count / $clusterSize;
$seedY = $y1 + ($y2 - $y1) * $count / $clusterSize; $seedY = $y1 + ($y2 - $y1) * $count / $clusterSize;

View File

@ -1,96 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\level\generator\object;
use pocketmine\block\Block;
use pocketmine\level\ChunkManager;
use pocketmine\utils\Random;
class PineTree extends Tree{
var $type = 1;
private $totalHeight = 8;
private $leavesSizeY = -1;
private $leavesAbsoluteMaxRadius = -1;
public function canPlaceObject(ChunkManager $level, $x, $y, $z, Random $random){
$this->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);
}
}
}

View File

@ -1,98 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\level\generator\object;
use pocketmine\block\Block;
use pocketmine\level\ChunkManager;
use pocketmine\utils\Random;
class SmallTree extends Tree{
public $type = 0;
private $trunkHeight = 5;
private static $leavesHeight = 4; // All trees appear to be 4 tall
private static $leafRadii = [1, 1.41, 2.83, 2.24];
private $addLeavesVines = false;
private $addLogVines = false;
private $addCocoaPlants = false;
public function canPlaceObject(ChunkManager $level, $x, $y, $z, Random $random){
$radiusToCheck = 0;
for($yy = 0; $yy < $this->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);
}
}
}
}

View File

@ -22,64 +22,56 @@
namespace pocketmine\level\generator\object; namespace pocketmine\level\generator\object;
use pocketmine\block\Block; use pocketmine\block\Block;
use pocketmine\block\Wood;
use pocketmine\level\ChunkManager; use pocketmine\level\ChunkManager;
use pocketmine\utils\Random; use pocketmine\utils\Random;
class SpruceTree extends Tree{ 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){ public function __construct(){
$this->findRandomLeavesSize($random); $this->trunkBlock = Block::LOG;
$checkRadius = 0; $this->leafBlock = Block::LEAVES;
for($yy = 0; $yy < $this->totalHeight + 2; ++$yy){ $this->type = Wood::SPRUCE;
if($yy === $this->leavesBottomY){ $this->treeHeight = 10;
$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 placeObject(ChunkManager $level, $x, $y, $z, Random $random){ public function placeObject(ChunkManager $level, $x, $y, $z, Random $random){
if($this->leavesBottomY === -1 or $this->leavesMaxRadius === -1){ $this->treeHeight = $random->nextBoundedInt(4) + 6;
$this->findRandomLeavesSize($random);
} $topSize = $this->treeHeight - (1 + $random->nextBoundedInt(2));
$level->setBlockIdAt($x, $y - 1, $z, Block::DIRT); $lRadius = 2 + $random->nextBoundedInt(2);
$leavesRadius = 0;
for($yy = $this->totalHeight; $yy >= $this->leavesBottomY; --$yy){ $this->placeTrunk($level, $x, $y, $z, $random, $this->treeHeight - $random->nextBoundedInt(3));
for($xx = -$leavesRadius; $xx <= $leavesRadius; ++$xx){
for($zz = -$leavesRadius; $zz <= $leavesRadius; ++$zz){ $radius = $random->nextBoundedInt(2);
if(abs($xx) != $leavesRadius or abs($zz) != $leavesRadius or $leavesRadius <= 0){ $maxR = 1;
$level->setBlockIdAt($x + $xx, $y + $yy, $z + $zz, Block::LEAVES); $minR = 0;
$level->setBlockDataAt($x + $xx, $y + $yy, $z + $zz, $this->type);
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);
} }
} }

View File

@ -26,11 +26,9 @@ use pocketmine\block\Sapling;
use pocketmine\level\ChunkManager; use pocketmine\level\ChunkManager;
use pocketmine\utils\Random; use pocketmine\utils\Random;
class Tree{ abstract class Tree{
public $overridable = [ public $overridable = [
0 => true, Block::AIR => true,
2 => true,
3 => true,
6 => true, 6 => true,
17 => true, 17 => true,
18 => true, 18 => true,
@ -39,29 +37,33 @@ class Tree{
Block::LEAVES2 => true 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){ public static function growTree(ChunkManager $level, $x, $y, $z, Random $random, $type = 0){
switch($type & 0x03){ switch($type){
case Sapling::SPRUCE: case Sapling::SPRUCE:
if($random->nextRange(0, 1) === 1){ $tree = new SpruceTree();
$tree = new SpruceTree();
}else{
$tree = new PineTree();
}
break; break;
case Sapling::BIRCH: case Sapling::BIRCH:
$tree = new SmallTree(); if($random->nextBoundedInt(39) === 0){
$tree->type = Sapling::BIRCH; $tree = new BirchTree(true);
}else{
$tree = new BirchTree();
}
break; break;
case Sapling::JUNGLE: case Sapling::JUNGLE:
$tree = new SmallTree(); $tree = new JungleTree();
$tree->type = Sapling::JUNGLE;
break; break;
case Sapling::OAK: case Sapling::OAK:
default: default:
$tree = new OakTree();
/*if($random->nextRange(0, 9) === 0){ /*if($random->nextRange(0, 9) === 0){
$tree = new BigTree(); $tree = new BigTree();
}else{*/ }else{*/
$tree = new SmallTree();
//} //}
break; break;
} }
@ -69,4 +71,57 @@ class Tree{
$tree->placeObject($level, $x, $y, $z, $random); $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);
}
}
}
} }

View File

@ -33,7 +33,7 @@ class Pond extends Populator{
public function populate(ChunkManager $level, $chunkX, $chunkZ, Random $random){ public function populate(ChunkManager $level, $chunkX, $chunkZ, Random $random){
if($random->nextRange(0, $this->waterOdd) === 0){ if($random->nextRange(0, $this->waterOdd) === 0){
$x = $random->nextRange($chunkX << 4, ($chunkX << 4) + 16); $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); $z = $random->nextRange($chunkZ << 4, ($chunkZ << 4) + 16);
$pond = new \pocketmine\level\generator\object\Pond($random, new Water()); $pond = new \pocketmine\level\generator\object\Pond($random, new Water());
if($pond->canPlaceObject($level, $x, $y, $z)){ if($pond->canPlaceObject($level, $x, $y, $z)){

View File

@ -110,4 +110,8 @@ class Random{
return $start + ($this->nextInt() % ($end + 1 - $start)); return $start + ($this->nextInt() % ($end + 1 - $start));
} }
public function nextBoundedInt($bound){
return $this->nextInt() % $bound;
}
} }