Implemented new Inventory windows on Player, Chest and Furnace

This commit is contained in:
Shoghi Cervantes 2014-05-23 20:53:06 +02:00
parent 27e82ea60a
commit 53749483c3
71 changed files with 1189 additions and 1009 deletions

View File

@ -28,7 +28,6 @@ use pocketmine\event\player\PlayerAchievementAwardedEvent;
use pocketmine\event\player\PlayerChatEvent; use pocketmine\event\player\PlayerChatEvent;
use pocketmine\event\player\PlayerCommandPreprocessEvent; use pocketmine\event\player\PlayerCommandPreprocessEvent;
use pocketmine\event\player\PlayerGameModeChangeEvent; use pocketmine\event\player\PlayerGameModeChangeEvent;
use pocketmine\event\player\PlayerItemHeldEvent;
use pocketmine\event\player\PlayerJoinEvent; use pocketmine\event\player\PlayerJoinEvent;
use pocketmine\event\player\PlayerKickEvent; use pocketmine\event\player\PlayerKickEvent;
use pocketmine\event\player\PlayerLoginEvent; use pocketmine\event\player\PlayerLoginEvent;
@ -37,7 +36,10 @@ use pocketmine\event\player\PlayerQuitEvent;
use pocketmine\event\player\PlayerRespawnEvent; use pocketmine\event\player\PlayerRespawnEvent;
use pocketmine\event\server\DataPacketReceiveEvent; use pocketmine\event\server\DataPacketReceiveEvent;
use pocketmine\event\server\DataPacketSendEvent; use pocketmine\event\server\DataPacketSendEvent;
use pocketmine\inventory\Inventory;
use pocketmine\inventory\InventoryHolder;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\level\format\pmf\LevelFormat;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\level\Position; use pocketmine\level\Position;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
@ -48,9 +50,6 @@ use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\String; use pocketmine\nbt\tag\String;
use pocketmine\network\protocol\AdventureSettingsPacket; use pocketmine\network\protocol\AdventureSettingsPacket;
use pocketmine\network\protocol\ChunkDataPacket; use pocketmine\network\protocol\ChunkDataPacket;
use pocketmine\network\protocol\ContainerClosePacket;
use pocketmine\network\protocol\ContainerSetContentPacket;
use pocketmine\network\protocol\ContainerSetSlotPacket;
use pocketmine\network\protocol\DataPacket; use pocketmine\network\protocol\DataPacket;
use pocketmine\network\protocol\DisconnectPacket; use pocketmine\network\protocol\DisconnectPacket;
use pocketmine\network\protocol\Info as ProtocolInfo; use pocketmine\network\protocol\Info as ProtocolInfo;
@ -61,7 +60,6 @@ use pocketmine\network\protocol\ServerHandshakePacket;
use pocketmine\network\protocol\SetSpawnPositionPacket; use pocketmine\network\protocol\SetSpawnPositionPacket;
use pocketmine\network\protocol\SetTimePacket; use pocketmine\network\protocol\SetTimePacket;
use pocketmine\network\protocol\StartGamePacket; use pocketmine\network\protocol\StartGamePacket;
use pocketmine\network\protocol\TileEventPacket;
use pocketmine\network\protocol\UnknownPacket; use pocketmine\network\protocol\UnknownPacket;
use pocketmine\network\protocol\UpdateBlockPacket; use pocketmine\network\protocol\UpdateBlockPacket;
use pocketmine\network\raknet\Info; use pocketmine\network\raknet\Info;
@ -69,11 +67,8 @@ use pocketmine\network\raknet\Packet;
use pocketmine\permission\PermissibleBase; use pocketmine\permission\PermissibleBase;
use pocketmine\permission\PermissionAttachment; use pocketmine\permission\PermissionAttachment;
use pocketmine\plugin\Plugin; use pocketmine\plugin\Plugin;
use pocketmine\level\format\pmf\LevelFormat;
use pocketmine\recipes\Crafting; use pocketmine\recipes\Crafting;
use pocketmine\scheduler\CallbackTask; use pocketmine\scheduler\CallbackTask;
use pocketmine\tile\Chest;
use pocketmine\tile\Furnace;
use pocketmine\tile\Sign; use pocketmine\tile\Sign;
use pocketmine\tile\Spawnable; use pocketmine\tile\Spawnable;
use pocketmine\tile\Tile; use pocketmine\tile\Tile;
@ -84,7 +79,7 @@ use pocketmine\utils\TextFormat;
* Main class that handles networking, recovery, and packet sending to the server part * Main class that handles networking, recovery, and packet sending to the server part
* TODO: Move reliability layer * TODO: Move reliability layer
*/ */
class Player extends Human implements CommandSender, IPlayer{ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
const SURVIVAL = 0; const SURVIVAL = 0;
const CREATIVE = 1; const CREATIVE = 1;
@ -102,8 +97,13 @@ class Player extends Human implements CommandSender, IPlayer{
public $loggedIn = false; public $loggedIn = false;
public $gamemode; public $gamemode;
public $lastBreak; public $lastBreak;
public $windowCnt = 2;
public $windows = []; protected $windowCnt = 2;
/** @var \SplObjectStorage<Inventory> */
protected $windows;
/** @var Inventory[] */
protected $windowIndex = [];
public $blocked = true; public $blocked = true;
public $achievements = []; public $achievements = [];
public $chunksLoaded = []; public $chunksLoaded = [];
@ -358,6 +358,7 @@ class Player extends Human implements CommandSender, IPlayer{
* @param integer $MTU * @param integer $MTU
*/ */
public function __construct($clientID, $ip, $port, $MTU){ public function __construct($clientID, $ip, $port, $MTU){
$this->windows = new \SplObjectStorage();
$this->perm = new PermissibleBase($this); $this->perm = new PermissibleBase($this);
$this->namedtag = new Compound(); $this->namedtag = new Compound();
$this->bigCnt = 0; $this->bigCnt = 0;
@ -1322,6 +1323,7 @@ class Player extends Human implements CommandSender, IPlayer{
if($p !== $this and strtolower($p->getName()) === strtolower($this->getName())){ if($p !== $this and strtolower($p->getName()) === strtolower($this->getName())){
if($p->kick("logged in from another location") === false){ if($p->kick("logged in from another location") === false){
$this->close($this->getName() . " has left the game", "already logged in"); $this->close($this->getName() . " has left the game", "already logged in");
return; return;
}else{ }else{
break; break;
@ -1432,9 +1434,9 @@ class Player extends Human implements CommandSender, IPlayer{
$this->spawned = true; $this->spawned = true;
$this->spawnToAll(); $this->spawnToAll();
$this->sendInventory();
$this->sendSettings(); $this->sendSettings();
$this->sendArmor(); $this->getInventory()->sendContents($this);
$this->getInventory()->sendArmorContents($this);
$this->tasks[] = $this->server->getScheduler()->scheduleDelayedTask(new CallbackTask(array($this, "orderChunks")), 30); $this->tasks[] = $this->server->getScheduler()->scheduleDelayedTask(new CallbackTask(array($this, "orderChunks")), 30);
$this->blocked = false; $this->blocked = false;
@ -1510,26 +1512,13 @@ class Player extends Human implements CommandSender, IPlayer{
} }
} }
}else{ }else{
$item = $this->getSlot($packet->slot); $item = $this->inventory->getItem($packet->slot);
} }
if(!isset($item) or $packet->slot === false){ if(!isset($item) or $packet->slot === false){
$this->sendInventorySlot($packet->slot); $this->inventory->sendSlot($packet->slot, $this);
}else{ }else{
$this->server->getPluginManager()->callEvent($ev = new PlayerItemHeldEvent($this, $item, $packet->slot, 0)); $this->inventory->setHeldItemSlot($packet->slot);
if($ev->isCancelled()){
$this->sendInventorySlot($packet->slot);
}elseif($item instanceof Item){
$this->setEquipmentSlot(0, $packet->slot);
$this->setCurrentEquipmentSlot(0);
if(($this->gamemode & 0x01) === 0){
if(!in_array($this->slot, $this->hotbar)){
array_pop($this->hotbar);
array_unshift($this->hotbar, $this->slot);
}
}
}
} }
if($this->inAction === true){ if($this->inAction === true){
@ -1576,18 +1565,21 @@ class Player extends Human implements CommandSender, IPlayer{
if($blockVector->distance($this) > 10){ if($blockVector->distance($this) > 10){
}elseif(($this->gamemode & 0x01) === 1){ }elseif(($this->gamemode & 0x01) === 1){
$item = Item::get(Block::$creative[$this->getCurrentEquipment()][0], Block::$creative[$this->getCurrentEquipment()][1], 1); $item = Item::get(
Block::$creative[$this->inventory->getHeldItemSlot()][0],
Block::$creative[$this->inventory->getHeldItemSlot()][1],
1
);
if($this->getLevel()->useItemOn($blockVector, $item, $packet->face, $packet->fx, $packet->fy, $packet->fz, $this) === true){ if($this->getLevel()->useItemOn($blockVector, $item, $packet->face, $packet->fx, $packet->fy, $packet->fz, $this) === true){
break; break;
} }
}elseif($this->getSlot($this->getCurrentEquipment())->getID() !== $packet->item or ($this->getSlot($this->getCurrentEquipment())->isTool() === false and $this->getSlot($this->getCurrentEquipment())->getDamage() !== $packet->meta)){ }elseif($this->inventory->getItemInHand()->getID() !== $packet->item or ($this->inventory->getItemInHand()->isTool() === false and $this->inventory->getItemInHand()->getDamage() !== $packet->meta)){
$this->sendInventorySlot($this->getCurrentEquipment()); $this->inventory->sendHeldItem($this);
}else{ }else{
$item = clone $this->getSlot($this->getCurrentEquipment()); $item = clone $this->inventory->getItemInHand();
//TODO: Implement adventure mode checks //TODO: Implement adventure mode checks
if($this->getLevel()->useItemOn($blockVector, $item, $packet->face, $packet->fx, $packet->fy, $packet->fz, $this) === true){ if($this->getLevel()->useItemOn($blockVector, $item, $packet->face, $packet->fx, $packet->fy, $packet->fz, $this) === true){
$this->setSlot($this->getCurrentEquipment(), $item); $this->inventory->setItemInHand($item);
$this->sendInventorySlot($this->getCurrentEquipment());
break; break;
} }
} }
@ -1704,15 +1696,19 @@ class Player extends Human implements CommandSender, IPlayer{
if(($this->gamemode & 0x01) === 1){ if(($this->gamemode & 0x01) === 1){
$item = Item::get(Block::$creative[$this->getCurrentEquipment()][0], Block::$creative[$this->getCurrentEquipment()][1], 1); $item = Item::get(
Block::$creative[$this->inventory->getHeldItemSlot()][0],
Block::$creative[$this->inventory->getHeldItemSlot()][1],
1
);
}else{ }else{
$item = clone $this->getSlot($this->getCurrentEquipment()); $item = clone $this->inventory->getItemInHand();
} }
if(($drops = $this->getLevel()->useBreakOn($vector, $item)) !== true){ if(($drops = $this->getLevel()->useBreakOn($vector, $item)) !== true){
if(($this->gamemode & 0x01) === 0){ if(($this->gamemode & 0x01) === 0){
//TODO: drop items //TODO: drop items
$this->setSlot($this->getCurrentEquipment(), $item); $this->inventory->setItemInHand($item);
} }
break; break;
} }
@ -1739,33 +1735,22 @@ class Player extends Human implements CommandSender, IPlayer{
}else{ }else{
$s = Item::get($s + 256, 0, 1); $s = Item::get($s + 256, 0, 1);
} }
$slot = $this->getArmorSlot($i); $slot = $this->inventory->getArmorItem($i);
if($slot->getID() !== Item::AIR and $s->getID() === Item::AIR){ if($slot->getID() !== Item::AIR and $s->getID() === Item::AIR){
if($this->setArmorSlot($i, Item::get(Item::AIR, 0, 0)) === false){ $this->inventory->setArmorItem($i, Item::get(Item::AIR, 0, 0));
$this->sendArmor(); }elseif($s->getID() !== Item::AIR and $slot->getID() === Item::AIR and ($sl = $this->inventory->first($s)) !== -1){
$this->sendInventory(); if($this->inventory->setArmorItem($i, $this->inventory->getItem($sl)) === false){
$this->inventory->sendContents($this);
}else{ }else{
$this->addItem($slot); $this->inventory->setItem($sl, Item::get(Item::AIR, 0, 0));
$packet->slots[$i] = 255;
} }
}elseif($s->getID() !== Item::AIR and $slot->getID() === Item::AIR and ($sl = $this->hasItem($s, false)) !== false){ }elseif($s->getID() !== Item::AIR and $slot->getID() !== Item::AIR and ($slot->getID() !== $s->getID() or $slot->getDamage() !== $s->getDamage()) and ($sl = $this->inventory->first($s)) !== -1){
if($this->setArmorSlot($i, $this->getSlot($sl)) === false){ if($this->inventory->setArmorItem($i, $this->inventory->getItem($sl)) === false){
$this->sendArmor(); $this->inventory->sendContents($this);
$this->sendInventory();
}else{ }else{
$this->setSlot($sl, Item::get(Item::AIR, 0, 0)); $this->inventory->setItem($sl, $slot);
} }
}elseif($s->getID() !== Item::AIR and $slot->getID() !== Item::AIR and ($slot->getID() !== $s->getID() or $slot->getDamage() !== $s->getDamage()) and ($sl = $this->hasItem($s, false)) !== false){
if($this->setArmorSlot($i, $this->getSlot($sl)) === false){
$this->sendArmor();
$this->sendInventory();
}else{
$this->setSlot($sl, $slot);
} }
}else{
$packet->slots[$i] = 255;
}
} }
if($this->inAction === true){ if($this->inAction === true){
@ -1884,7 +1869,10 @@ class Player extends Human implements CommandSender, IPlayer{
//$this->entity->setHealth(20, "respawn", true); //$this->entity->setHealth(20, "respawn", true);
//$this->entity->updateMetadata(); //$this->entity->updateMetadata();
$this->sendInventory(); $this->sendSettings();
$this->inventory->sendContents($this);
$this->inventory->sendArmorContents($this);
$this->blocked = false; $this->blocked = false;
break; break;
case ProtocolInfo::SET_HEALTH_PACKET: //Not used case ProtocolInfo::SET_HEALTH_PACKET: //Not used
@ -1989,37 +1977,16 @@ class Player extends Human implements CommandSender, IPlayer{
} }
break; break;
case ProtocolInfo::CONTAINER_CLOSE_PACKET: case ProtocolInfo::CONTAINER_CLOSE_PACKET:
if($this->spawned === false){ if($this->spawned === false or $packet->windowid === 0){
break; break;
} }
$this->craftingItems = []; $this->craftingItems = [];
$this->toCraft = []; $this->toCraft = [];
if(isset($this->windows[$packet->windowid])){ if(isset($this->windowIndex[$packet->windowid])){
if(is_array($this->windows[$packet->windowid])){ $this->removeWindow($this->windowIndex[$packet->windowid]);
foreach($this->windows[$packet->windowid] as $ob){ }else{
$pk = new TileEventPacket; unset($this->windowIndex[$packet->windowid]);
$pk->x = $ob->x;
$pk->y = $ob->y;
$pk->z = $ob->z;
$pk->case1 = 1;
$pk->case2 = 0;
Player::broadcastPacket($this->getLevel()->players, $pk);
} }
}elseif($this->windows[$packet->windowid] instanceof Chest){
$pk = new TileEventPacket;
$pk->x = $this->windows[$packet->windowid]->x;
$pk->y = $this->windows[$packet->windowid]->y;
$pk->z = $this->windows[$packet->windowid]->z;
$pk->case1 = 1;
$pk->case2 = 0;
Player::broadcastPacket($this->getLevel()->players, $pk);
}
}
unset($this->windows[$packet->windowid]);
$pk = new ContainerClosePacket;
$pk->windowid = $packet->windowid;
$this->dataPacket($pk);
break; break;
case ProtocolInfo::CONTAINER_SET_SLOT_PACKET: case ProtocolInfo::CONTAINER_SET_SLOT_PACKET:
if($this->spawned === false or $this->blocked === true){ if($this->spawned === false or $this->blocked === true){
@ -2035,9 +2002,9 @@ class Player extends Human implements CommandSender, IPlayer{
$this->craftingItems = []; $this->craftingItems = [];
} }
if($packet->windowid === 0){ if($packet->windowid === 0){ //Crafting!
$craft = false; $craft = false;
$slot = $this->getSlot($packet->slot); $slot = $this->inventory->getItem($packet->slot);
if($slot->getCount() >= $packet->item->getCount() and (($slot->getID() === $packet->item->getID() and $slot->getDamage() === $packet->item->getDamage()) or ($packet->item->getID() === Item::AIR and $packet->item->getCount() === 0)) and !isset($this->craftingItems[$packet->slot])){ //Crafting recipe if($slot->getCount() >= $packet->item->getCount() and (($slot->getID() === $packet->item->getID() and $slot->getDamage() === $packet->item->getDamage()) or ($packet->item->getID() === Item::AIR and $packet->item->getCount() === 0)) and !isset($this->craftingItems[$packet->slot])){ //Crafting recipe
$use = Item::get($slot->getID(), $slot->getDamage(), $slot->getCount() - $packet->item->getCount()); $use = Item::get($slot->getID(), $slot->getDamage(), $slot->getCount() - $packet->item->getCount());
$this->craftingItems[$packet->slot] = $use; $this->craftingItems[$packet->slot] = $use;
@ -2066,7 +2033,7 @@ class Player extends Human implements CommandSender, IPlayer{
if($craft === true and count($this->craftingItems) > 0 and count($this->toCraft) > 0 and ($recipe = $this->craftItems($this->toCraft, $this->craftingItems, $this->toCraft[-1])) !== true){ if($craft === true and count($this->craftingItems) > 0 and count($this->toCraft) > 0 and ($recipe = $this->craftItems($this->toCraft, $this->craftingItems, $this->toCraft[-1])) !== true){
if($recipe === false){ if($recipe === false){
$this->sendInventory(); $this->inventory->sendContents($this);
$this->toCraft = []; $this->toCraft = [];
}else{ }else{
$this->toCraft = array(-1 => $this->toCraft[-1]); $this->toCraft = array(-1 => $this->toCraft[-1]);
@ -2077,129 +2044,57 @@ class Player extends Human implements CommandSender, IPlayer{
$this->toCraft = []; $this->toCraft = [];
$this->craftingItems = []; $this->craftingItems = [];
} }
if(!isset($this->windows[$packet->windowid])){ if(!isset($this->windowIndex[$packet->windowid])){
break; break;
} }
if(is_array($this->windows[$packet->windowid])){ $inv = $this->windowIndex[$packet->windowid];
/** @var \pocketmine\tile\Container[] $tiles */ if($packet->slot < 0 or $packet->slot >= $inv->getSize()){
$tiles = $this->windows[$packet->windowid];
if($packet->slot >= 0 and $packet->slot < Chest::SLOTS){
$tile = $tiles[0];
$slotn = $packet->slot;
$offset = 0;
}elseif($packet->slot >= Chest::SLOTS and $packet->slot <= (Chest::SLOTS << 1)){
$tile = $tiles[1];
$slotn = $packet->slot - Chest::SLOTS;
$offset = Chest::SLOTS;
}else{
break; break;
} }
$item = Item::get($packet->item->getID(), $packet->item->getDamage(), $packet->item->getCount());
$slot = $tile->getSlot($slotn); /** @var Item $item */
//TODO: container access events? $item = clone $packet->item;
/*if($this->server->api->dhandle("player.container.slot", array(
"tile" => $tile, $slot = $inv->getItem($packet->slot);
"slot" => $packet->slot,
"offset" => $offset, if($item->getID() !== Item::AIR and $slot->equals($item, true)){
"slotdata" => $slot,
"itemdata" => $item,
"player" => $this,
)) === false
){
$pk = new ContainerSetSlotPacket;
$pk->windowid = $packet->windowid;
$pk->slot = $packet->slot;
$pk->item = $slot;
$this->dataPacket($pk);
break;
}*/
if($item->getID() !== Item::AIR and $slot->getID() == $item->getID()){
if($slot->getCount() < $item->getCount()){ if($slot->getCount() < $item->getCount()){
$it = clone $item; $it = clone $item;
$it->setCount($item->getCount() - $slot->getCount()); $it->setCount($item->getCount() - $slot->getCount());
if($this->removeItem($it) === false){ $remaining = $this->inventory->removeItem($it);
$this->sendInventory(); if(count($remaining) > 0){
break; /** @var Item $it */
$it = array_pop($remaining);
$item->setCount($item->getCount() - $it->getCount());
} }
}elseif($slot->getCount() > $item->getCount()){ }elseif($slot->getCount() > $item->getCount()){
$it = clone $item; $it = clone $item;
$it->setCount($slot->getCount() - $item->getCount()); $it->setCount($slot->count - $item->count);
$this->addItem($it); $remaining = $this->inventory->addItem($it);
if(count($remaining) > 0){
/** @var Item $it */
$it = array_pop($remaining);
$item->setCount($item->getCount() + $it->getCount());
} }
}else{
if($this->removeItem($item) === false){
$this->sendInventory();
break;
} }
$this->addItem($slot); if($inv->getType()->getDefaultTitle() === "Furnace" and $packet->slot == 2){
}
$tile->setSlot($slotn, $item, true, $offset);
}else{
$tile = $this->windows[$packet->windowid];
if(
!($tile instanceof Chest or $tile instanceof Furnace)
or $packet->slot < 0
or (
$tile instanceof Chest
and $packet->slot >= Chest::SLOTS
) or (
$tile instanceof Furnace and $packet->slot >= Furnace::SLOTS
)
){
break;
}
$item = Item::get($packet->item->getID(), $packet->item->getDamage(), $packet->item->getCount());
$slot = $tile->getSlot($packet->slot);
//TODO: container access events?
/*if($this->server->api->dhandle("player.container.slot", array(
"tile" => $tile,
"slot" => $packet->slot,
"slotdata" => $slot,
"itemdata" => $item,
"player" => $this,
)) === false
){
$pk = new ContainerSetSlotPacket;
$pk->windowid = $packet->windowid;
$pk->slot = $packet->slot;
$pk->item = $slot;
$this->dataPacket($pk);
break;
}*/
if($tile instanceof Furnace and $packet->slot == 2){
switch($slot->getID()){ switch($slot->getID()){
case Item::IRON_INGOT: case Item::IRON_INGOT:
$this->awardAchievement("acquireIron"); $this->awardAchievement("acquireIron");
break; break;
} }
} }
}else{ //TODO: check this. I don't know what is this for
$remaining = $this->inventory->removeItem($item);
if(count($remaining) > 0){
$this->inventory->removeItem();
break;
}
$this->inventory->addItem($slot);
}
$inv->setItem($packet->slot, $item);
if($item->getID() !== Item::AIR and $slot->getID() == $item->getID()){
if($slot->getCount() < $item->getCount()){
$it = clone $item;
$it->setCount($item->getCount() - $slot->getCount());
if($this->removeItem($it) === false){
$this->sendInventory();
break;
}
}elseif($slot->getCount() > $item->getCount()){
$it = clone $item;
$it->setCount($slot->count - $item->count);
$this->addItem($it);
}
}else{
if($this->removeItem($item) === false){
$this->sendInventory();
break;
}
$this->addItem($slot);
}
$tile->setSlot($packet->slot, $item);
}
break; break;
case ProtocolInfo::SEND_INVENTORY_PACKET: //TODO, Mojang, enable this ´^_^` case ProtocolInfo::SEND_INVENTORY_PACKET: //TODO, Mojang, enable this ´^_^`
if($this->spawned === false){ if($this->spawned === false){
@ -2323,9 +2218,8 @@ class Player extends Human implements CommandSender, IPlayer{
$this->server->getPluginManager()->unsubscribeFromPermission(Server::BROADCAST_CHANNEL_USERS, $this); $this->server->getPluginManager()->unsubscribeFromPermission(Server::BROADCAST_CHANNEL_USERS, $this);
$this->spawned = false; $this->spawned = false;
console("[INFO] " . TextFormat::AQUA . $this->username . TextFormat::RESET . "[/" . $this->ip . ":" . $this->port . "] logged out due to " . $reason); console("[INFO] " . TextFormat::AQUA . $this->username . TextFormat::RESET . "[/" . $this->ip . ":" . $this->port . "] logged out due to " . $reason);
$this->windows = []; $this->windows = new \SplObjectStorage();
$this->armor = []; $this->windowIndex = [];
$this->inventory = [];
$this->chunksLoaded = []; $this->chunksLoaded = [];
$this->chunksOrder = []; $this->chunksOrder = [];
$this->chunkCount = []; $this->chunkCount = [];
@ -2465,18 +2359,18 @@ class Player extends Human implements CommandSender, IPlayer{
//} //}
foreach($recipe as $slot => $item){ foreach($recipe as $slot => $item){
$s = $this->getSlot($slot); $s = $this->inventory->getItem($slot);
$s->setCount($s->getCount() - $item->getCount()); $s->setCount($s->getCount() - $item->getCount());
if($s->getCount() <= 0){ if($s->getCount() <= 0){
$this->setSlot($slot, Item::get(Item::AIR, 0, 0)); $this->inventory->setItem($slot, Item::get(Item::AIR, 0, 0));
} }
} }
foreach($craft as $slot => $item){ foreach($craft as $slot => $item){
$s = $this->getSlot($slot); $s = $this->inventory->getItem($slot);
if($s->getCount() <= 0 or $s->getID() === Item::AIR){ if($s->getCount() <= 0 or $s->getID() === Item::AIR){
$this->setSlot($slot, Item::get($item->getID(), $item->getDamage(), $item->getCount())); $this->inventory->setItem($slot, Item::get($item->getID(), $item->getDamage(), $item->getCount()));
}else{ }else{
$this->setSlot($slot, Item::get($item->getID(), $item->getDamage(), $s->getCount() + $item->getCount())); $this->inventory->setItem($slot, Item::get($item->getID(), $item->getDamage(), $s->getCount() + $item->getCount()));
} }
switch($item->getID()){ switch($item->getID()){
@ -2497,7 +2391,7 @@ class Player extends Human implements CommandSender, IPlayer{
break; break;
case Item::CAKE: case Item::CAKE:
$this->awardAchievement("bakeCake"); $this->awardAchievement("bakeCake");
$this->addItem(Item::get(Item::BUCKET, 0, 3)); $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:
@ -2519,59 +2413,46 @@ class Player extends Human implements CommandSender, IPlayer{
return $res; return $res;
} }
public function setSlot($slot, Item $item){
parent::setSlot($slot, $item); /**
$this->sendInventorySlot($slot); * @param Inventory $inventory
*
* @return int
*/
public function getWindowId(Inventory $inventory){
if($this->windows->contains($inventory)){
return $this->windows[$inventory];
}
return -1;
} }
/** /**
* Sends a single slot * Returns the created/existing window id
* TODO: Check if Mojang has implemented this on Minecraft: PE 0.9.0
* *
* @param int $s * @param Inventory $inventory
* *
* @return bool * @return int
*/ */
public function sendInventorySlot($s){ public function addWindow(Inventory $inventory){
$this->sendInventory(); if($this->windows->contains($inventory)){
return $this->windows[$inventory];
}
$this->windowCnt = $cnt = max(2, ++$this->windowCnt % 99);
$this->windowIndex[$cnt] = $inventory;
$this->windows->attach($inventory, $cnt);
$this->inventory->onOpen($this);
return; //TODO: Check if Mojang adds this return $cnt;
$s = (int) $s;
if(!isset($this->inventory[$s])){
$pk = new ContainerSetSlotPacket;
$pk->windowid = 0;
$pk->slot = (int) $s;
$pk->item = Item::get(Item::AIR, 0, 0);
$this->dataPacket($pk);
} }
$slot = $this->inventory[$s]; public function removeWindow(Inventory $inventory){
$pk = new ContainerSetSlotPacket; $inventory->onClose($this);
$pk->windowid = 0; if($this->windows->contains($inventory)){
$pk->slot = (int) $s; $inventory->onClose($this);
$pk->item = $slot; $id = $this->windows[$inventory];
$this->dataPacket($pk); unset($this->windowIndex[$id]);
return true;
} }
/**
* Sends the full inventory
*/
public function sendInventory(){
if(($this->gamemode & 0x01) === 1){
return;
}
$hotbar = [];
foreach($this->hotbar as $slot){
$hotbar[] = $slot <= -1 ? -1 : $slot + 9;
}
$pk = new ContainerSetContentPacket;
$pk->windowid = 0;
$pk->slots = $this->inventory;
$pk->hotbar = $hotbar;
$this->dataPacket($pk);
} }
public function setMetadata($metadataKey, MetadataValue $metadataValue){ public function setMetadata($metadataKey, MetadataValue $metadataValue){

View File

@ -89,7 +89,7 @@ namespace pocketmine {
const PHP_VERSION = "5.5"; const PHP_VERSION = "5.5";
if(\Phar::running(true) !== ""){ if(\Phar::running(true) !== ""){
@define("pocketmine\\PATH", \Phar::running(true)."/"); @define("pocketmine\\PATH", \Phar::running(true) . "/");
}else{ }else{
@define("pocketmine\\PATH", \getcwd() . DIRECTORY_SEPARATOR); @define("pocketmine\\PATH", \getcwd() . DIRECTORY_SEPARATOR);
} }

View File

@ -31,7 +31,6 @@ use pocketmine\block\Furnace;
use pocketmine\command\CommandReader; use pocketmine\command\CommandReader;
use pocketmine\command\CommandSender; use pocketmine\command\CommandSender;
use pocketmine\command\ConsoleCommandSender; use pocketmine\command\ConsoleCommandSender;
use pocketmine\command\PluginCommand;
use pocketmine\command\PluginIdentifiableCommand; use pocketmine\command\PluginIdentifiableCommand;
use pocketmine\command\SimpleCommandMap; use pocketmine\command\SimpleCommandMap;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
@ -41,6 +40,7 @@ use pocketmine\event\server\PacketSendEvent;
use pocketmine\event\server\ServerCommandEvent; use pocketmine\event\server\ServerCommandEvent;
use pocketmine\inventory\InventoryType; use pocketmine\inventory\InventoryType;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\level\format\pmf\LevelFormat;
use pocketmine\level\generator\Flat; use pocketmine\level\generator\Flat;
use pocketmine\level\generator\Generator; use pocketmine\level\generator\Generator;
use pocketmine\level\generator\Normal; use pocketmine\level\generator\Normal;
@ -73,7 +73,6 @@ use pocketmine\permission\DefaultPermissions;
use pocketmine\plugin\Plugin; use pocketmine\plugin\Plugin;
use pocketmine\plugin\PluginLoadOrder; use pocketmine\plugin\PluginLoadOrder;
use pocketmine\plugin\PluginManager; use pocketmine\plugin\PluginManager;
use pocketmine\level\format\pmf\LevelFormat;
use pocketmine\recipes\Crafting; use pocketmine\recipes\Crafting;
use pocketmine\scheduler\CallbackTask; use pocketmine\scheduler\CallbackTask;
use pocketmine\scheduler\SendUsageTask; use pocketmine\scheduler\SendUsageTask;
@ -795,6 +794,7 @@ class Server{
return true; return true;
}elseif(!$this->isLevelGenerated($name)){ }elseif(!$this->isLevelGenerated($name)){
console("[NOTICE] Level \"" . $name . "\" not found"); console("[NOTICE] Level \"" . $name . "\" not found");
return false; return false;
} }
@ -1830,7 +1830,7 @@ class Server{
} }
$this->lastSendUsage = new SendUsageTask("http://stats.pocketmine.net/usage.php", array( $this->lastSendUsage = new SendUsageTask("http://stats.pocketmine.net/usage.php", array(
"serverid" => Binary::readLong(substr(Utils::getUniqueID(true, $this->getIp() .":". $this->getPort()), 0, 8)), "serverid" => Binary::readLong(substr(Utils::getUniqueID(true, $this->getIp() . ":" . $this->getPort()), 0, 8)),
"port" => $this->getPort(), "port" => $this->getPort(),
"os" => Utils::getOS(), "os" => Utils::getOS(),
"memory_total" => $this->getConfigString("memory-limit"), "memory_total" => $this->getConfigString("memory-limit"),

View File

@ -24,7 +24,6 @@ namespace pocketmine\block;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\network\protocol\ChatPacket; use pocketmine\network\protocol\ChatPacket;
use pocketmine\Player; use pocketmine\Player;
use pocketmine\Server;
class Bed extends Transparent{ class Bed extends Transparent{
public function __construct($type = 0){ public function __construct($type = 0){

View File

@ -25,7 +25,6 @@
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\level\Position; use pocketmine\level\Position;
use pocketmine\metadata\Metadatable; use pocketmine\metadata\Metadatable;
use pocketmine\metadata\MetadataValue; use pocketmine\metadata\MetadataValue;
@ -753,11 +752,11 @@ abstract class Block extends Position implements Metadatable{
} }
public function getMetadata($metadataKey){ public function getMetadata($metadataKey){
return null;//return $this->server->getPlayerMetadata()->getMetadata($this, $metadataKey); return null; //return $this->server->getPlayerMetadata()->getMetadata($this, $metadataKey);
} }
public function hasMetadata($metadataKey){ public function hasMetadata($metadataKey){
return false;//return $this->server->getPlayerMetadata()->hasMetadata($this, $metadataKey); return false; //return $this->server->getPlayerMetadata()->hasMetadata($this, $metadataKey);
} }
public function removeMetadata($metadataKey, Plugin $plugin){ public function removeMetadata($metadataKey, Plugin $plugin){

View File

@ -118,8 +118,8 @@ class BurningFurnace extends Solid{
} }
$t = $this->getLevel()->getTile($this); $t = $this->getLevel()->getTile($this);
if($t instanceof Furnace){ if($t instanceof Furnace){
for($s = 0; $s < Furnace::SLOTS; ++$s){ for($s = 0; $s < $t->getInventory()->getSize(); ++$s){
$slot = $t->getSlot($s); $slot = $t->getInventory()->getItem($s);
if($slot->getID() > Item::AIR and $slot->getCount() > 0){ if($slot->getID() > Item::AIR and $slot->getCount() > 0){
$drops[] = array($slot->getID(), $slot->getDamage(), $slot->getCount()); $drops[] = array($slot->getID(), $slot->getDamage(), $slot->getCount());
} }

View File

@ -59,8 +59,9 @@ class Chest extends Transparent{
continue; continue;
} }
$c = $this->getSide($side); $c = $this->getSide($side);
if(($c instanceof TileChest) and $c->getDamage() === $this->meta){ if($c instanceof Chest and $c->getDamage() === $this->meta){
if((($tile = $this->getLevel()->getTile($c)) instanceof TileChest) and !$tile->isPaired()){ $tile = $this->getLevel()->getTile($c);
if($tile instanceof TileChest and !$tile->isPaired()){
$chest = $tile; $chest = $tile;
break; break;
} }
@ -104,7 +105,7 @@ class Chest extends Transparent{
} }
$t = $this->getLevel()->getTile($this); $t = $this->getLevel()->getTile($this);
$chest = false; $chest = null;
if($t instanceof TileChest){ if($t instanceof TileChest){
$chest = $t; $chest = $t;
}else{ }else{
@ -123,8 +124,7 @@ class Chest extends Transparent{
if(($player->gamemode & 0x01) === 0x01){ if(($player->gamemode & 0x01) === 0x01){
return true; return true;
} }
$player->addWindow($chest->getInventory());
$chest->openInventory($player);
} }
return true; return true;
@ -135,9 +135,9 @@ class Chest extends Transparent{
array($this->id, 0, 1), array($this->id, 0, 1),
); );
$t = $this->getLevel()->getTile($this); $t = $this->getLevel()->getTile($this);
if($t instanceof Chest){ if($t instanceof TileChest){
for($s = 0; $s < Chest::SLOTS; ++$s){ for($s = 0; $s < $t->getInventory()->getSize(); ++$s){
$slot = $t->getSlot($s); $slot = $t->getInventory()->getItem($s);
if($slot->getID() > Item::AIR and $slot->getCount() > 0){ if($slot->getID() > Item::AIR and $slot->getCount() > 0){
$drops[] = array($slot->getID(), $slot->getDamage(), $slot->getCount()); $drops[] = array($slot->getID(), $slot->getDamage(), $slot->getCount());
} }

View File

@ -28,7 +28,7 @@ class RemoteConsoleCommandSender extends ConsoleCommandSender{
private $messages = ""; private $messages = "";
public function sendMessage($message){ public function sendMessage($message){
$this->messages .= trim($message, "\r\n")."\n"; $this->messages .= trim($message, "\r\n") . "\n";
} }
public function getMessage(){ public function getMessage(){

View File

@ -50,10 +50,10 @@ use pocketmine\command\defaults\StatusCommand;
use pocketmine\command\defaults\StopCommand; use pocketmine\command\defaults\StopCommand;
use pocketmine\command\defaults\TeleportCommand; use pocketmine\command\defaults\TeleportCommand;
use pocketmine\command\defaults\TellCommand; use pocketmine\command\defaults\TellCommand;
use pocketmine\command\defaults\TimeCommand;
use pocketmine\command\defaults\VanillaCommand; use pocketmine\command\defaults\VanillaCommand;
use pocketmine\command\defaults\VersionCommand; use pocketmine\command\defaults\VersionCommand;
use pocketmine\command\defaults\WhitelistCommand; use pocketmine\command\defaults\WhitelistCommand;
use pocketmine\command\defaults\TimeCommand;
use pocketmine\Server; use pocketmine\Server;
class SimpleCommandMap implements CommandMap{ class SimpleCommandMap implements CommandMap{

View File

@ -21,10 +21,8 @@
namespace pocketmine\command\defaults; namespace pocketmine\command\defaults;
use pocketmine\command\Command;
use pocketmine\command\CommandSender; use pocketmine\command\CommandSender;
use pocketmine\Player; use pocketmine\Player;
use pocketmine\Server;
use pocketmine\utils\TextFormat; use pocketmine\utils\TextFormat;
class KillCommand extends VanillaCommand{ class KillCommand extends VanillaCommand{

View File

@ -23,7 +23,6 @@ namespace pocketmine\command\defaults;
use pocketmine\command\Command; use pocketmine\command\Command;
use pocketmine\command\CommandSender; use pocketmine\command\CommandSender;
use pocketmine\event\HandlerList;
use pocketmine\Server; use pocketmine\Server;
use pocketmine\utils\TextFormat; use pocketmine\utils\TextFormat;

View File

@ -23,8 +23,6 @@ namespace pocketmine\command\defaults;
use pocketmine\command\Command; use pocketmine\command\Command;
use pocketmine\command\CommandSender; use pocketmine\command\CommandSender;
use pocketmine\command\ConsoleCommandSender;
use pocketmine\level\Position;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\Player; use pocketmine\Player;
use pocketmine\Server; use pocketmine\Server;
@ -52,19 +50,22 @@ class SetWorldSpawnCommand extends VanillaCommand{
$pos = $sender->round(); $pos = $sender->round();
}else{ }else{
$sender->sendMessage(TextFormat::RED . "You can only perform this command as a player"); $sender->sendMessage(TextFormat::RED . "You can only perform this command as a player");
return true; return true;
} }
}elseif(count($args) === 3){ }elseif(count($args) === 3){
$level = Server::getInstance()->getDefaultLevel(); $level = Server::getInstance()->getDefaultLevel();
$pos = new Vector3($this->getInteger($sender, $args[0]), $this->getInteger($sender, $args[1]), $this->getInteger($sender, $args[2])); $pos = new Vector3($this->getInteger($sender, $args[0]), $this->getInteger($sender, $args[1]), $this->getInteger($sender, $args[2]));
}else{ }else{
$sender->sendMessage(TextFormat::RED . "Usage: ".$this->usageMessage); $sender->sendMessage(TextFormat::RED . "Usage: " . $this->usageMessage);
return true; return true;
} }
$level->setSpawn($pos); $level->setSpawn($pos);
Command::broadcastCommandMessage($sender, "Set world ".$level->getName()."'s spawnpoint to ".$pos->x.", ".$pos->y.", ".$pos->z); Command::broadcastCommandMessage($sender, "Set world " . $level->getName() . "'s spawnpoint to " . $pos->x . ", " . $pos->y . ", " . $pos->z);
return true; return true;
} }
} }

View File

@ -51,12 +51,14 @@ class SpawnpointCommand extends VanillaCommand{
$target = $sender; $target = $sender;
}else{ }else{
$sender->sendMessage(TextFormat::RED . "Please provide a player!"); $sender->sendMessage(TextFormat::RED . "Please provide a player!");
return true; return true;
} }
}else{ }else{
$target = Server::getInstance()->getPlayer($args[0]); $target = Server::getInstance()->getPlayer($args[0]);
if($target === null){ if($target === null){
$sender->sendMessage(TextFormat::RED . "Can't find player ".$args[0]); $sender->sendMessage(TextFormat::RED . "Can't find player " . $args[0]);
return true; return true;
} }
} }
@ -69,22 +71,26 @@ class SpawnpointCommand extends VanillaCommand{
$y = (int) $this->getRelativeDouble($sender->y, $sender, $args[2], 0, 128); $y = (int) $this->getRelativeDouble($sender->y, $sender, $args[2], 0, 128);
$z = (int) $this->getRelativeDouble($sender->z, $sender, $args[3]); $z = (int) $this->getRelativeDouble($sender->z, $sender, $args[3]);
$target->setSpawn(new Position($x, $y, $z, $level)); $target->setSpawn(new Position($x, $y, $z, $level));
Command::broadcastCommandMessage($sender, "Set ".$target->getName()."'s spawnpoint to ".$x.", ".$y.", ".$z); Command::broadcastCommandMessage($sender, "Set " . $target->getName() . "'s spawnpoint to " . $x . ", " . $y . ", " . $z);
return true; return true;
} }
}elseif(count($args) <= 1){ }elseif(count($args) <= 1){
if($sender instanceof Player) { if($sender instanceof Player){
$pos = new Position((int) $sender->x, (int) $sender->y, (int) $sender->z, $sender->getLevel()); $pos = new Position((int) $sender->x, (int) $sender->y, (int) $sender->z, $sender->getLevel());
$target->setSpawn($pos); $target->setSpawn($pos);
Command::broadcastCommandMessage($sender, "Set ".$target->getName()."'s spawnpoint to ".$pos->x.", ".$pos->y.", ".$pos->z); Command::broadcastCommandMessage($sender, "Set " . $target->getName() . "'s spawnpoint to " . $pos->x . ", " . $pos->y . ", " . $pos->z);
return true; return true;
}else{ }else{
$sender->sendMessage(TextFormat::RED . "Please provide a player!"); $sender->sendMessage(TextFormat::RED . "Please provide a player!");
return true; return true;
} }
} }
$sender->sendMessage(TextFormat::RED . "Usage: ".$this->usageMessage); $sender->sendMessage(TextFormat::RED . "Usage: " . $this->usageMessage);
return true; return true;
} }
} }

View File

@ -22,7 +22,6 @@
namespace pocketmine\command\defaults; namespace pocketmine\command\defaults;
use pocketmine\command\CommandSender; use pocketmine\command\CommandSender;
use pocketmine\Player;
use pocketmine\Server; use pocketmine\Server;
use pocketmine\utils\TextFormat; use pocketmine\utils\TextFormat;
@ -43,11 +42,12 @@ class StatusCommand extends VanillaCommand{
} }
$server = Server::getInstance(); $server = Server::getInstance();
$sender->sendMessage(TextFormat::GREEN . "---- ".TextFormat::WHITE . "Server status".TextFormat::GREEN. " ----"); $sender->sendMessage(TextFormat::GREEN . "---- " . TextFormat::WHITE . "Server status" . TextFormat::GREEN . " ----");
$sender->sendMessage(TextFormat::GOLD . "TPS: ".TextFormat::WHITE.$server->getTicksPerSecond()); $sender->sendMessage(TextFormat::GOLD . "TPS: " . TextFormat::WHITE . $server->getTicksPerSecond());
$sender->sendMessage(TextFormat::GOLD . "Upload: ".TextFormat::WHITE . round($server->getNetwork()->getUploadSpeed() / 1024, 2) . " kB/s"); $sender->sendMessage(TextFormat::GOLD . "Upload: " . TextFormat::WHITE . round($server->getNetwork()->getUploadSpeed() / 1024, 2) . " kB/s");
$sender->sendMessage(TextFormat::GOLD . "Download: ".TextFormat::WHITE . round($server->getNetwork()->getDownloadSpeed() / 1024, 2) . " kB/s"); $sender->sendMessage(TextFormat::GOLD . "Download: " . TextFormat::WHITE . round($server->getNetwork()->getDownloadSpeed() / 1024, 2) . " kB/s");
$sender->sendMessage(TextFormat::GOLD . "Memory: ".TextFormat::WHITE . round((memory_get_usage() / 1024) / 1024, 2) . TextFormat::YELLOW . "/" . TextFormat::WHITE . round((memory_get_usage(true) / 1024) / 1024, 2) . " MB"); $sender->sendMessage(TextFormat::GOLD . "Memory: " . TextFormat::WHITE . round((memory_get_usage() / 1024) / 1024, 2) . TextFormat::YELLOW . "/" . TextFormat::WHITE . round((memory_get_usage(true) / 1024) / 1024, 2) . " MB");
return true; return true;
} }
} }

View File

@ -46,7 +46,8 @@ class TeleportCommand extends VanillaCommand{
} }
if(count($args) < 1 or count($args) > 4){ if(count($args) < 1 or count($args) > 4){
$sender->sendMessage(TextFormat::RED . "Usage: ".$this->usageMessage); $sender->sendMessage(TextFormat::RED . "Usage: " . $this->usageMessage);
return true; return true;
} }
@ -58,19 +59,22 @@ class TeleportCommand extends VanillaCommand{
$target = $sender; $target = $sender;
}else{ }else{
$sender->sendMessage(TextFormat::RED . "Please provide a player!"); $sender->sendMessage(TextFormat::RED . "Please provide a player!");
return true; return true;
} }
}else{ }else{
$target = Server::getInstance()->getPlayer($args[0]); $target = Server::getInstance()->getPlayer($args[0]);
if($target === null){ if($target === null){
$sender->sendMessage(TextFormat::RED . "Can't find player ".$args[0]); $sender->sendMessage(TextFormat::RED . "Can't find player " . $args[0]);
return true; return true;
} }
if(count($args) === 2){ if(count($args) === 2){
$origin = $target; $origin = $target;
$target = Server::getInstance()->getPlayer($args[1]); $target = Server::getInstance()->getPlayer($args[1]);
if($target === null){ if($target === null){
$sender->sendMessage(TextFormat::RED . "Can't find player ".$args[1]); $sender->sendMessage(TextFormat::RED . "Can't find player " . $args[1]);
return true; return true;
} }
} }
@ -79,19 +83,22 @@ class TeleportCommand extends VanillaCommand{
if(count($args) < 3){ if(count($args) < 3){
$pos = new Position($target->x, $target->y, $target->z, $target->getLevel()); $pos = new Position($target->x, $target->y, $target->z, $target->getLevel());
$origin->teleport($pos); $origin->teleport($pos);
Command::broadcastCommandMessage($sender, "Teleported ".$origin->getName()." to ".$target->getName()); Command::broadcastCommandMessage($sender, "Teleported " . $origin->getName() . " to " . $target->getName());
return true; return true;
}elseif($target->getLevel() !== null){ }elseif($target->getLevel() !== null){
$pos = count($args) === 4 ? 1:0; $pos = count($args) === 4 ? 1 : 0;
$x = $this->getRelativeDouble($target->x, $sender, $args[$pos++]); $x = $this->getRelativeDouble($target->x, $sender, $args[$pos++]);
$y = $this->getRelativeDouble($target->y, $sender, $args[$pos++], 0, 128); $y = $this->getRelativeDouble($target->y, $sender, $args[$pos++], 0, 128);
$z = $this->getRelativeDouble($target->z, $sender, $args[$pos]); $z = $this->getRelativeDouble($target->z, $sender, $args[$pos]);
$target->teleport(new Vector3($x, $y, $z)); $target->teleport(new Vector3($x, $y, $z));
Command::broadcastCommandMessage($sender, "Teleported ".$target->getName()." to ".round($x, 2).", ".round($y, 2).", ".round($z, 2)); Command::broadcastCommandMessage($sender, "Teleported " . $target->getName() . " to " . round($x, 2) . ", " . round($y, 2) . ", " . round($z, 2));
return true; return true;
} }
$sender->sendMessage(TextFormat::RED . "Usage: ".$this->usageMessage); $sender->sendMessage(TextFormat::RED . "Usage: " . $this->usageMessage);
return true; return true;
} }
} }

View File

@ -6,7 +6,6 @@ use pocketmine\command\Command;
use pocketmine\command\CommandSender; use pocketmine\command\CommandSender;
use pocketmine\Server; use pocketmine\Server;
use pocketmine\utils\TextFormat; use pocketmine\utils\TextFormat;
use pocketmine\network\protocol\SetTimePacket;
class TimeCommand extends VanillaCommand{ class TimeCommand extends VanillaCommand{
public function __construct($name){ public function __construct($name){
@ -19,15 +18,17 @@ class TimeCommand extends VanillaCommand{
} }
public function execute(CommandSender $sender, $label, array $args){ public function execute(CommandSender $sender, $label, array $args){
if (count($args) < 2) { if(count($args) < 2){
$sender->sendMessage(TextFormat::RED."Incorrect usage. Correct usage:\n".$this->getUsage()); $sender->sendMessage(TextFormat::RED . "Incorrect usage. Correct usage:\n" . $this->getUsage());
return false; return false;
} }
switch(strtolower($args[0])){ switch(strtolower($args[0])){
case "set": case "set":
if(!$sender->hasPermission("pocketmine.command.time.add")){ if(!$sender->hasPermission("pocketmine.command.time.add")){
$sender->sendMessage(TextFormat::RED."You don't have permission to set the time"); $sender->sendMessage(TextFormat::RED . "You don't have permission to set the time");
return true; return true;
} }
@ -42,12 +43,13 @@ class TimeCommand extends VanillaCommand{
foreach(Server::getInstance()->getLevels() as $level){ foreach(Server::getInstance()->getLevels() as $level){
$level->setTime($value); $level->setTime($value);
} }
Command::broadcastCommandMessage($sender, "Set time to ".$value); Command::broadcastCommandMessage($sender, "Set time to " . $value);
return true; return true;
case "add": case "add":
if (!$sender->hasPermission("pocketmine.command.time.add")){ if(!$sender->hasPermission("pocketmine.command.time.add")){
$sender->sendMessage(TextFormat::RED."You don't have permission to set the time"); $sender->sendMessage(TextFormat::RED . "You don't have permission to set the time");
return true; return true;
} }
@ -57,11 +59,11 @@ class TimeCommand extends VanillaCommand{
$level->setTime($level->getTime() + $value); $level->setTime($level->getTime() + $value);
} }
Command::broadcastCommandMessage($sender, "Added ".$value." to time"); Command::broadcastCommandMessage($sender, "Added " . $value . " to time");
return true; return true;
default: default:
$sender->sendMessage("Unknown method. Usage: ".$this->getUsage()); $sender->sendMessage("Unknown method. Usage: " . $this->getUsage());
} }
} }
} }

View File

@ -29,6 +29,7 @@ use pocketmine\event\entity\EntityLevelChangeEvent;
use pocketmine\event\entity\EntityMotionEvent; use pocketmine\event\entity\EntityMotionEvent;
use pocketmine\event\entity\EntityMoveEvent; use pocketmine\event\entity\EntityMoveEvent;
use pocketmine\event\entity\EntitySpawnEvent; use pocketmine\event\entity\EntitySpawnEvent;
use pocketmine\level\format\pmf\LevelFormat;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\level\Position; use pocketmine\level\Position;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
@ -36,14 +37,13 @@ use pocketmine\math\Vector3 as Vector3;
use pocketmine\metadata\Metadatable; use pocketmine\metadata\Metadatable;
use pocketmine\metadata\MetadataValue; use pocketmine\metadata\MetadataValue;
use pocketmine\nbt\tag\Compound; use pocketmine\nbt\tag\Compound;
use pocketmine\Network;
use pocketmine\network\protocol\MoveEntityPacket_PosRot; use pocketmine\network\protocol\MoveEntityPacket_PosRot;
use pocketmine\network\protocol\MovePlayerPacket; use pocketmine\network\protocol\MovePlayerPacket;
use pocketmine\network\protocol\RemoveEntityPacket; use pocketmine\network\protocol\RemoveEntityPacket;
use pocketmine\network\protocol\SetEntityMotionPacket; use pocketmine\network\protocol\SetEntityMotionPacket;
use pocketmine\network\protocol\SetTimePacket; use pocketmine\network\protocol\SetTimePacket;
use pocketmine\Network;
use pocketmine\Player; use pocketmine\Player;
use pocketmine\level\format\pmf\LevelFormat;
use pocketmine\plugin\Plugin; use pocketmine\plugin\Plugin;
use pocketmine\Server; use pocketmine\Server;
@ -176,6 +176,10 @@ abstract class Entity extends Position implements Metadatable{
protected abstract function initEntity(); protected abstract function initEntity();
public function getViewers(){
return $this->hasSpawned;
}
public function spawnTo(Player $player){ public function spawnTo(Player $player){
if(!isset($this->hasSpawned[$player->getID()]) and $player->chunksLoaded[$this->chunkIndex] !== 0xff){ if(!isset($this->hasSpawned[$player->getID()]) and $player->chunksLoaded[$this->chunkIndex] !== 0xff){
$this->hasSpawned[$player->getID()] = $player; $this->hasSpawned[$player->getID()] = $player;

View File

@ -21,54 +21,46 @@
namespace pocketmine\entity; namespace pocketmine\entity;
use pocketmine\event\entity\EntityArmorChangeEvent; use pocketmine\inventory\InventoryHolder;
use pocketmine\event\entity\EntityInventoryChangeEvent; use pocketmine\inventory\PlayerInventory;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\Byte; use pocketmine\nbt\tag\Byte;
use pocketmine\nbt\tag\Compound; use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\Enum; use pocketmine\nbt\tag\Enum;
use pocketmine\nbt\tag\Short; use pocketmine\nbt\tag\Short;
use pocketmine\Network;
use pocketmine\network\protocol\AddPlayerPacket; use pocketmine\network\protocol\AddPlayerPacket;
use pocketmine\network\protocol\ContainerSetContentPacket;
use pocketmine\network\protocol\PlayerArmorEquipmentPacket;
use pocketmine\network\protocol\PlayerEquipmentPacket;
use pocketmine\network\protocol\RemovePlayerPacket; use pocketmine\network\protocol\RemovePlayerPacket;
use pocketmine\network\protocol\SetEntityMotionPacket; use pocketmine\network\protocol\SetEntityMotionPacket;
use pocketmine\Network;
use pocketmine\Player; use pocketmine\Player;
use pocketmine\Server;
class Human extends Creature implements ProjectileSource, InventorySource{ class Human extends Creature implements ProjectileSource, InventoryHolder{
protected $nameTag = "TESTIFICATE"; protected $nameTag = "TESTIFICATE";
protected $inventory = []; /** @var PlayerInventory */
public $slot; protected $inventory;
protected $hotbar = [];
protected $armor = []; public function getInventory(){
return $this->inventory;
}
protected function initEntity(){ protected function initEntity(){
$this->inventory = new PlayerInventory($this);
if(isset($this->namedtag->NameTag)){ if(isset($this->namedtag->NameTag)){
$this->nameTag = $this->namedtag["NameTag"]; $this->nameTag = $this->namedtag["NameTag"];
} }
$this->hotbar = array(-1, -1, -1, -1, -1, -1, -1, -1, -1);
$this->armor = array(
0 => Item::get(Item::AIR, 0, 0),
1 => Item::get(Item::AIR, 0, 0),
2 => Item::get(Item::AIR, 0, 0),
3 => Item::get(Item::AIR, 0, 0)
);
foreach($this->namedtag->Inventory as $item){ foreach($this->namedtag->Inventory as $item){
if($item["Slot"] >= 0 and $item["Slot"] < 9){ //Hotbar if($item["Slot"] >= 0 and $item["Slot"] < 9){ //Hotbar
$this->hotbar[$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->armor[$item["Slot"] - 100] = Item::get($item["id"], $item["Damage"], $item["Count"]); $this->inventory->setItem($this->inventory->getSize() + $item["Slot"] - 100, Item::get($item["id"], $item["Damage"], $item["Count"]));
}else{ }else{
$this->inventory[$item["Slot"] - 9] = Item::get($item["id"], $item["Damage"], $item["Count"]); $this->inventory->setItem($item["Slot"] - 9, Item::get($item["id"], $item["Damage"], $item["Count"]));
} }
} }
$this->slot = $this->hotbar[0];
$this->height = 1.8; //Or 1.62? $this->height = 1.8; //Or 1.62?
$this->width = 0.6; $this->width = 0.6;
@ -79,14 +71,15 @@ class Human extends Creature implements ProjectileSource, InventorySource{
$this->namedtag->Inventory = new Enum("Inventory", []); $this->namedtag->Inventory = new Enum("Inventory", []);
$this->namedtag->Inventory->setTagType(NBT::TAG_Compound); $this->namedtag->Inventory->setTagType(NBT::TAG_Compound);
for($slot = 0; $slot < 9; ++$slot){ for($slot = 0; $slot < 9; ++$slot){
if(isset($this->hotbar[$slot]) and $this->hotbar[$slot] !== -1){ $hotbarSlot = $this->inventory->getHotbarSlotIndex($slot);
$item = $this->getSlot($this->hotbar[$slot]); if($hotbarSlot !== -1){
$item = $this->inventory->getItem($hotbarSlot);
if($item->getID() !== 0 and $item->getCount() > 0){ if($item->getID() !== 0 and $item->getCount() > 0){
$this->namedtag->Inventory[$slot] = new Compound(false, array( $this->namedtag->Inventory[$slot] = new Compound(false, array(
new Byte("Count", $item->getCount()), new Byte("Count", $item->getCount()),
new Short("Damage", $item->getDamage()), new Short("Damage", $item->getDamage()),
new Byte("Slot", $slot), new Byte("Slot", $slot),
new Byte("TrueSlot", $this->hotbar[$slot]), new Byte("TrueSlot", $hotbarSlot),
new Short("id", $item->getID()), new Short("id", $item->getID()),
)); ));
continue; continue;
@ -105,7 +98,7 @@ class Human extends Creature implements ProjectileSource, InventorySource{
$slotCount = Player::SURVIVAL_SLOTS + 9; $slotCount = Player::SURVIVAL_SLOTS + 9;
//$slotCount = (($this instanceof Player and ($this->gamemode & 0x01) === 1) ? Player::CREATIVE_SLOTS : Player::SURVIVAL_SLOTS) + 9; //$slotCount = (($this instanceof Player and ($this->gamemode & 0x01) === 1) ? Player::CREATIVE_SLOTS : Player::SURVIVAL_SLOTS) + 9;
for($slot = 9; $slot < $slotCount; ++$slot){ for($slot = 9; $slot < $slotCount; ++$slot){
$item = $this->getSlot($slot - 9); $item = $this->inventory->getItem($slot - 9);
$this->namedtag->Inventory[$slot] = new Compound(false, array( $this->namedtag->Inventory[$slot] = new Compound(false, array(
new Byte("Count", $item->getCount()), new Byte("Count", $item->getCount()),
new Short("Damage", $item->getDamage()), new Short("Damage", $item->getDamage()),
@ -116,8 +109,8 @@ class Human extends Creature implements ProjectileSource, InventorySource{
//Armor //Armor
for($slot = 100; $slot < 104; ++$slot){ for($slot = 100; $slot < 104; ++$slot){
$item = $this->armor[$slot - 100]; $item = $this->inventory->getItem($this->inventory->getSize() + $slot - 100);
if($item instanceof Item){ if($item instanceof Item and $item->getID() !== Item::AIR){
$this->namedtag->Inventory[$slot] = new Compound(false, array( $this->namedtag->Inventory[$slot] = new Compound(false, array(
new Byte("Count", $item->getCount()), new Byte("Count", $item->getCount()),
new Short("Damage", $item->getDamage()), new Short("Damage", $item->getDamage()),
@ -135,7 +128,7 @@ class Human extends Creature implements ProjectileSource, InventorySource{
$pk = new AddPlayerPacket; $pk = new AddPlayerPacket;
$pk->clientID = 0; $pk->clientID = 0;
$pk->username = $this->nameTag; $pk->username = $this->nameTag;
$pk->eid = $this->id; $pk->eid = $this->getID();
$pk->x = $this->x; $pk->x = $this->x;
$pk->y = $this->y; $pk->y = $this->y;
$pk->z = $this->z; $pk->z = $this->z;
@ -147,15 +140,15 @@ class Human extends Creature implements ProjectileSource, InventorySource{
$player->dataPacket($pk); $player->dataPacket($pk);
$pk = new SetEntityMotionPacket; $pk = new SetEntityMotionPacket;
$pk->eid = $this->id; $pk->eid = $this->getID();
$pk->speedX = $this->motionX; $pk->speedX = $this->motionX;
$pk->speedY = $this->motionY; $pk->speedY = $this->motionY;
$pk->speedZ = $this->motionZ; $pk->speedZ = $this->motionZ;
$player->dataPacket($pk); $player->dataPacket($pk);
$this->sendCurrentEquipmentSlot($player); $this->inventory->sendHeldItem($player);
$this->sendArmor($player); $this->inventory->sendArmorContents($player);
} }
} }
@ -169,104 +162,6 @@ class Human extends Creature implements ProjectileSource, InventorySource{
} }
} }
public function setEquipmentSlot($equipmentSlot, $inventorySlot){
$this->hotbar[$equipmentSlot] = $inventorySlot;
if($equipmentSlot === $this->slot){
foreach($this->hasSpawned as $p){
$this->sendCurrentEquipmentSlot($p);
}
}
}
public function getEquipmentSlot($equipmentSlot){
if(isset($this->hotbar[$equipmentSlot])){
return $this->hotbar[$equipmentSlot];
}
return -1;
}
public function setCurrentEquipmentSlot($slot){
if(isset($this->hotbar[$slot])){
$this->slot = (int) $slot;
foreach($this->hasSpawned as $p){
$this->sendCurrentEquipmentSlot($p);
}
}
}
public function getCurrentEquipmentSlot(){
return $this->slot;
}
public function getCurrentEquipment(){
if($this->slot > -1) {
return $this->hotbar[$this->slot];
}
}
public function sendCurrentEquipmentSlot(Player $player){
$pk = new PlayerEquipmentPacket;
$pk->eid = $this->id;
$pk->item = $this->getSlot($this->slot)->getID();
$pk->meta = $this->getSlot($this->slot)->getDamage();
$pk->slot = 0;
$player->dataPacket($pk);
}
public function setArmorSlot($slot, Item $item){
Server::getInstance()->getPluginManager()->callEvent($ev = new EntityArmorChangeEvent($this, $this->getArmorSlot($slot), $item, $slot));
if($ev->isCancelled()){
return false;
}
$this->armor[(int) $slot] = $ev->getNewItem();
foreach($this->hasSpawned as $p){
$this->sendArmor($p);
}
if($this instanceof Player){
$this->sendArmor();
}
return true;
}
/**
* @param int $slot
*
* @return Item
*/
public function getArmorSlot($slot){
$slot = (int) $slot;
if(!isset($this->armor[$slot])){
$this->armor[$slot] = Item::get(Item::AIR, 0, 0);
}
return $this->armor[$slot];
}
public function sendArmor($player = null){
$slots = [];
for($i = 0; $i < 4; ++$i){
if(isset($this->armor[$i]) and ($this->armor[$i] instanceof Item) and $this->armor[$i]->getID() > Item::AIR){
$slots[$i] = $this->armor[$i]->getID() !== Item::AIR ? $this->armor[$i]->getID() - 256 : 0;
}else{
$this->armor[$i] = Item::get(Item::AIR, 0, 0);
$slots[$i] = 255;
}
}
if($player instanceof Player){
$pk = new PlayerArmorEquipmentPacket();
$pk->eid = $this->id;
$pk->slots = $slots;
$player->dataPacket($pk);
}elseif($this instanceof Player){
$pk = new ContainerSetContentPacket;
$pk->windowid = 0x78; //Armor window id
$pk->slots = $this->armor;
$this->dataPacket($pk);
}
}
public function getData(){ //TODO public function getData(){ //TODO
$flags = 0; $flags = 0;
$flags |= $this->fireTicks > 0 ? 1 : 0; $flags |= $this->fireTicks > 0 ? 1 : 0;
@ -305,132 +200,4 @@ class Human extends Creature implements ProjectileSource, InventorySource{
} }
public function hasItem(Item $item, $checkDamage = true){
foreach($this->inventory as $s => $i){
if($i->equals($item, $checkDamage)){
return $i;
}
}
return false;
}
public function canAddItem(Item $item){
$inv = $this->inventory;
while($item->getCount() > 0){
$add = 0;
foreach($inv as $s => $i){
if($i->getID() === Item::AIR){
$add = min($i->getMaxStackSize(), $item->getCount());
$inv[$s] = clone $item;
$inv[$s]->setCount($add);
break;
}elseif($i->equals($item)){
$add = min($i->getMaxStackSize() - $i->getCount(), $item->getCount());
if($add <= 0){
continue;
}
$inv[$s] = clone $item;
$inv[$s]->setCount($i->getCount() + $add);
break;
}
}
if($add <= 0){
return false;
}
$item->setCount($item->getCount() - $add);
}
return true;
}
public function addItem(Item $item){
while($item->getCount() > 0){
$add = 0;
foreach($this->inventory as $s => $i){
if($i->getID() === Item::AIR){
$add = min($i->getMaxStackSize(), $item->getCount());
$i2 = clone $item;
$i2->setCount($add);
$this->setSlot($s, $i2);
break;
}elseif($i->equals($item)){
$add = min($i->getMaxStackSize() - $i->getCount(), $item->getCount());
if($add <= 0){
continue;
}
$i2 = clone $item;
$i2->setCount($i->getCount() + $add);
$this->setSlot($s, $i2);
break;
}
}
if($add <= 0){
return false;
}
$item->setCount($item->getCount() - $add);
}
return true;
}
public function canRemoveItem(Item $item, $checkDamage = true){
return $this->hasItem($item, $checkDamage);
}
public function removeItem(Item $item, $checkDamage = true){
while($item->getCount() > 0){
$remove = 0;
foreach($this->inventory as $s => $i){
if($i->equals($item, $checkDamage)){
$remove = min($item->getCount(), $i->getCount());
if($item->getCount() < $i->getCount()){
$i->setCount($i->getCount() - $item->getCount());
$this->setSlot($s, $i);
}else{
$this->setSlot($s, Item::get(Item::AIR, 0, 0));
}
break;
}
}
if($remove <= 0){
return false;
}
$item->setCount($item->getCount() - $remove);
}
return true;
}
public function setSlot($slot, Item $item){
Server::getInstance()->getPluginManager()->callEvent($ev = new EntityInventoryChangeEvent($this, $this->getSlot($slot), $item, $slot));
if($ev->isCancelled()){
return false;
}
$this->inventory[(int) $slot] = $ev->getNewItem();
return true;
}
/**
* @param int $slot
*
* @return Item
*/
public function getSlot($slot){
$slot = (int) $slot;
if(!isset($this->inventory[$slot])){
$this->inventory[$slot] = Item::get(Item::AIR, 0, 0);
}
return $this->inventory[$slot];
}
public function getAllSlots(){
return $this->inventory;
}
public function getSlotCount(){
return count($this->inventory);
}
} }

View File

@ -21,8 +21,8 @@
namespace pocketmine\event\player; namespace pocketmine\event\player;
use pocketmine\event\Cancellable;
use pocketmine\Event; use pocketmine\Event;
use pocketmine\event\Cancellable;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\Player; use pocketmine\Player;

View File

@ -21,8 +21,8 @@
namespace pocketmine\event\server; namespace pocketmine\event\server;
use pocketmine\event;
use pocketmine\event\Cancellable; use pocketmine\event\Cancellable;
use pocketmine\event;
use pocketmine\network\protocol\DataPacket; use pocketmine\network\protocol\DataPacket;
use pocketmine\Player; use pocketmine\Player;

View File

@ -21,8 +21,8 @@
namespace pocketmine\event\server; namespace pocketmine\event\server;
use pocketmine\event;
use pocketmine\event\Cancellable; use pocketmine\event\Cancellable;
use pocketmine\event;
use pocketmine\network\protocol\DataPacket; use pocketmine\network\protocol\DataPacket;
use pocketmine\Player; use pocketmine\Player;

View File

@ -1,35 +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/
*
*
*/
/**
* Events used by Tiles
*/
namespace pocketmine\event\tile;
use pocketmine\event\Event;
abstract class TileEvent extends Event{
protected $tile;
public function getTile(){
return $this->tile;
}
}

View File

@ -1,60 +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\event\tile;
use pocketmine\Event;
use pocketmine\event\Cancellable;
use pocketmine\item\Item;
use pocketmine\tile\Tile;
class TileInventoryChangeEvent extends TileEvent implements Cancellable{
public static $handlerList = null;
private $oldItem;
private $newItem;
private $slot;
public function __construct(Tile $tile, Item $oldItem, Item $newItem, $slot){
$this->tile = $tile;
$this->oldItem = $oldItem;
$this->newItem = $newItem;
$this->slot = (int) $slot;
}
public function getSlot(){
return $this->slot;
}
public function getNewItem(){
return $this->newItem;
}
public function setNewItem(Item $item){
$this->newItem = $item;
}
public function getOldItem(){
return $this->oldItem;
}
}

View File

@ -21,9 +21,13 @@
namespace pocketmine\inventory; namespace pocketmine\inventory;
use pocketmine\entity\Entity;
use pocketmine\event\entity\EntityInventoryChangeEvent;
use pocketmine\item\Item;
use pocketmine\network\protocol\ContainerSetContentPacket;
use pocketmine\network\protocol\ContainerSetSlotPacket; use pocketmine\network\protocol\ContainerSetSlotPacket;
use pocketmine\Player; use pocketmine\Player;
use pocketmine\item\Item; use pocketmine\Server;
abstract class BaseInventory implements Inventory{ abstract class BaseInventory implements Inventory{
@ -57,7 +61,7 @@ abstract class BaseInventory implements Inventory{
//A holder can be a plugin, or an entity //A holder can be a plugin, or an entity
if($this->holder instanceof Player){ if($this->holder instanceof Player){
$this->viewers->attach($this->holder); $this->holder->addWindow($this, 0);
} }
@ -123,18 +127,34 @@ abstract class BaseInventory implements Inventory{
} }
public function setItem($index, Item $item){ public function setItem($index, Item $item){
if($index < 0 or $index >= $this->size or $item->getID() === 0){ if($index < 0 or $index >= $this->size){
return; return false;
}elseif($item->getID() === 0){
$this->clear($index);
} }
$holder = $this->getHolder();
if($holder instanceof Entity){
Server::getInstance()->getPluginManager()->callEvent($ev = new EntityInventoryChangeEvent($holder, $this->getItem($index), $item, $index));
if($ev->isCancelled()){
$this->sendContents($this->getViewers());
return false;
}
$item = $ev->getNewItem();
}
$old = $this->slots[$index]; $old = $this->slots[$index];
$this->slots[$index] = clone $item; $this->slots[$index] = clone $item;
$this->onSlotChange($index, $old); $this->onSlotChange($index, $old);
return true;
} }
public function contains(Item $item){ public function contains(Item $item){
$count = max(1, $item->getCount()); $count = max(1, $item->getCount());
$checkDamage = $item->getDamage() === null ? false : true; $checkDamage = $item->getDamage() === null ? false : true;
foreach($this->slots as $i){ foreach($this->getContents() as $i){
if($item->equals($i, $checkDamage)){ if($item->equals($i, $checkDamage)){
$count -= $i->getCount(); $count -= $i->getCount();
if($count <= 0){ if($count <= 0){
@ -149,7 +169,7 @@ abstract class BaseInventory implements Inventory{
public function all(Item $item){ public function all(Item $item){
$slots = []; $slots = [];
$checkDamage = $item->getDamage() === null ? false : true; $checkDamage = $item->getDamage() === null ? false : true;
foreach($this->slots as $index => $i){ foreach($this->getContents() as $index => $i){
if($item->equals($i, $checkDamage)){ if($item->equals($i, $checkDamage)){
$slots[$index] = $i; $slots[$index] = $i;
} }
@ -160,7 +180,7 @@ abstract class BaseInventory implements Inventory{
public function remove(Item $item){ public function remove(Item $item){
$checkDamage = $item->getDamage() === null ? false : true; $checkDamage = $item->getDamage() === null ? false : true;
foreach($this->slots as $index => $i){ foreach($this->getContents() as $index => $i){
if($item->equals($i, $checkDamage)){ if($item->equals($i, $checkDamage)){
$this->clear($index); $this->clear($index);
} }
@ -170,7 +190,7 @@ abstract class BaseInventory implements Inventory{
public function first(Item $item){ public function first(Item $item){
$count = max(1, $item->getCount()); $count = max(1, $item->getCount());
$checkDamage = $item->getDamage() === null ? false : true; $checkDamage = $item->getDamage() === null ? false : true;
foreach($this->slots as $index => $i){ foreach($this->getContents() as $index => $i){
if($item->equals($i, $checkDamage) and $i->getCount() >= $count){ if($item->equals($i, $checkDamage) and $i->getCount() >= $count){
return $index; return $index;
} }
@ -181,10 +201,7 @@ abstract class BaseInventory implements Inventory{
public function firstEmpty(){ public function firstEmpty(){
for($i = 0; $i < $this->size; ++$i){ for($i = 0; $i < $this->size; ++$i){
if(!isset($this->slots[$i])){ if($this->getItem($i)->getID() === Item::AIR){
return $i;
}elseif(!($this->slots[$i] instanceof Item) or $this->slots[$i]->getID() === 0 or $this->slots[$i]->getCount() <= 0){
unset($this->slots[$i]);
return $i; return $i;
} }
} }
@ -196,11 +213,10 @@ abstract class BaseInventory implements Inventory{
/** @var Item[] $slots */ /** @var Item[] $slots */
$slots = func_get_args(); $slots = func_get_args();
for($i = 0; $i < $this->size; ++$i){ for($i = 0; $i < $this->size; ++$i){
if(!isset($this->slots[$i])){ $item = $this->getItem($i);
$item = $this->slots[$i] = array_shift($slots); if($item->getID() === Item::AIR){
$this->onSlotChange($i, null); $item = array_shift($slots);
}else{ $this->setItem($i, $item);
$item = $this->slots[$i];
} }
foreach($slots as $index => $slot){ foreach($slots as $index => $slot){
@ -230,10 +246,9 @@ abstract class BaseInventory implements Inventory{
/** @var Item[] $slots */ /** @var Item[] $slots */
$slots = func_get_args(); $slots = func_get_args();
for($i = 0; $i < $this->size; ++$i){ for($i = 0; $i < $this->size; ++$i){
if(!isset($this->slots[$i])){ $item = $this->getItem($i);
if($item->getID() === Item::AIR){
continue; continue;
}else{
$item = $this->slots[$i];
} }
foreach($slots as $index => $slot){ foreach($slots as $index => $slot){
@ -263,14 +278,32 @@ abstract class BaseInventory implements Inventory{
public function clear($index){ public function clear($index){
if(isset($this->slots[$index])){ if(isset($this->slots[$index])){
$item = Item::get(Item::AIR, null, 0);
$old = $this->slots[$index]; $old = $this->slots[$index];
$holder = $this->getHolder();
if($holder instanceof Entity){
Server::getInstance()->getPluginManager()->callEvent($ev = new EntityInventoryChangeEvent($holder, $old, $item, $index));
if($ev->isCancelled()){
$this->sendContents($this->getViewers());
return false;
}
$item = $ev->getNewItem();
}
if($item->getID() !== Item::AIR){
$this->slots[$index] = clone $item;
}else{
unset($this->slots[$index]); unset($this->slots[$index]);
}
$this->onSlotChange($index, $old); $this->onSlotChange($index, $old);
} }
return true;
} }
public function clearAll(){ public function clearAll(){
foreach($this->slots as $index => $i){ foreach($this->getContents() as $index => $i){
$this->clear($index); $this->clear($index);
} }
} }
@ -280,6 +313,7 @@ abstract class BaseInventory implements Inventory{
foreach($this->viewers as $viewer){ foreach($this->viewers as $viewer){
$viewers[] = $viewer; $viewers[] = $viewer;
} }
return $viewers; return $viewers;
} }
@ -300,12 +334,44 @@ abstract class BaseInventory implements Inventory{
} }
public function onSlotChange($index, $before){ public function onSlotChange($index, $before){
$this->sendSlot($index, $this->getViewers());
}
/**
* @param Player|Player[] $target
*/
public function sendContents($target){
if($target instanceof Player){
$target = [$target];
}
$pk = new ContainerSetContentPacket();
$pk->slots = [];
for($i = 0; $i < $this->getSize(); ++$i){
$pk->slots[$i] = $this->getItem($i);
}
foreach($target as $player){
$pk->windowid = $player->getWindowId($this);
$player->dataPacket(clone $pk);
}
}
/**
* @param int $index
* @param Player|Player[] $target
*/
public function sendSlot($index, $target){
if($target instanceof Player){
$target = [$target];
}
$pk = new ContainerSetSlotPacket; $pk = new ContainerSetSlotPacket;
$pk->slot = $index; $pk->slot = $index;
$pk->item = clone $this->getItem($index); $pk->item = clone $this->getItem($index);
/** @var Player $player */ foreach($target as $player){
foreach($this->getViewers() as $player){
$pk->windowid = $player->getWindowId($this); $pk->windowid = $player->getWindowId($this);
$player->dataPacket(clone $pk); $player->dataPacket(clone $pk);
} }

View File

@ -0,0 +1,67 @@
<?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\inventory;
use pocketmine\network\protocol\TileEventPacket;
use pocketmine\Player;
use pocketmine\tile\Chest;
class ChestInventory extends ContainerInventory{
public function __construct(Chest $tile){
parent::__construct($tile, InventoryType::get(InventoryType::CHEST));
}
/**
* @return Chest
*/
public function getHolder(){
return $this->holder;
}
public function onOpen(Player $who){
parent::onOpen($who);
if(count($this->getViewers()) === 1){
$pk = new TileEventPacket;
$pk->x = $this->getHolder()->getX();
$pk->y = $this->getHolder()->getY();
$pk->z = $this->getHolder()->getZ();
$pk->case1 = 1;
$pk->case2 = 2;
Player::broadcastPacket($this->getHolder()->getLevel()->getPlayers(), $pk);
}
}
public function onClose(Player $who){
parent::onClose($who);
if(count($this->getViewers()) === 1){
$pk = new TileEventPacket;
$pk->x = $this->getHolder()->getX();
$pk->y = $this->getHolder()->getY();
$pk->z = $this->getHolder()->getZ();
$pk->case1 = 1;
$pk->case2 = 0;
Player::broadcastPacket($this->getHolder()->getLevel()->getPlayers(), $pk);
}
}
}

View File

@ -0,0 +1,55 @@
<?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\inventory;
use pocketmine\network\protocol\ContainerClosePacket;
use pocketmine\network\protocol\ContainerOpenPacket;
use pocketmine\Player;
use pocketmine\tile\Chest;
use pocketmine\tile\Furnace;
abstract class ContainerInventory extends BaseInventory{
/**
* @return Chest|Furnace
*/
public function getHolder(){
return $this->holder;
}
public function onOpen(Player $who){
$pk = new ContainerOpenPacket;
$pk->windowid = $who->getWindowId($this);
$pk->type = 0;
$pk->slots = $this->getSize();
$pk->x = $this->getHolder()->getX();
$pk->y = $this->getHolder()->getY();
$pk->z = $this->getHolder()->getZ();
$who->dataPacket($pk);
}
public function onClose(Player $who){
$pk = new ContainerClosePacket;
$pk->windowid = $who->getWindowId($this);
$who->dataPacket($pk);
}
}

View File

@ -0,0 +1,101 @@
<?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\inventory;
use pocketmine\item\Item;
use pocketmine\tile\Chest;
class DoubleChestInventory extends ChestInventory implements InventoryHolder{
/** @var ChestInventory */
private $left;
/** @var ChestInventory */
private $right;
public function __construct(Chest $left, Chest $right){
$this->left = $left->getRealInventory();
$this->right = $right->getRealInventory();
BaseInventory::__construct($this, InventoryType::get(InventoryType::DOUBLE_CHEST));
}
//TODO
public function getInventory(){
return $this;
}
//TODO
public function getHolder(){
return $this->left;
}
public function getItem($index){
return $index < $this->left->getSize() ? $this->left->getItem($index) : $this->right->getItem($index - $this->right->getSize());
}
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){
return $index < $this->left->getSize() ? $this->left->clear($index) : $this->right->clear($index - $this->right->getSize());
}
public function getContents(){
$contents = [];
for($i = 0; $i < $this->getSize(); ++$i){
$contents[$i] = $this->getItem($i);
}
return $contents;
}
/**
* @param Item[] $items
*/
public function setContents(array $items){
if(count($items) > $this->size){
$items = array_slice($items, 0, $this->size, true);
}
parent::setContents($items);
$leftItems = array_slice($items, 0, $this->left->getSize(), true);
$this->left->setContents($leftItems);
if(count($items) > $this->left->getSize()){
$rightItems = array_slice($items, $this->left->getSize() - 1, $this->right->getSize(), true);
$this->right->setContents($rightItems);
}
}
/**
* @return ChestInventory
*/
public function getLeftSide(){
return $this->left;
}
/**
* @return ChestInventory
*/
public function getRightSide(){
return $this->right;
}
}

View File

@ -0,0 +1,92 @@
<?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\inventory;
use pocketmine\item\Item;
use pocketmine\tile\Furnace;
class FurnaceInventory extends ContainerInventory{
public function __construct(Furnace $tile){
parent::__construct($tile, InventoryType::get(InventoryType::FURNACE));
}
/**
* @return Furnace
*/
public function getHolder(){
return $this->holder;
}
/**
* @return Item
*/
public function getResult(){
return $this->getItem(2);
}
/**
* @return Item
*/
public function getFuel(){
return $this->getItem(1);
}
/**
* @return Item
*/
public function getSmelting(){
return $this->getItem(0);
}
/**
* @param Item $item
*
* @return bool
*/
public function setResult(Item $item){
return $this->setItem(2, $item);
}
/**
* @param Item $item
*
* @return bool
*/
public function setFuel(Item $item){
return $this->setItem(1, $item);
}
/**
* @param Item $item
*
* @return bool
*/
public function setSmelting(Item $item){
return $this->setItem(0, $item);
}
public function onSlotChange($index, $before){
parent::onSlotChange($index, $before);
//TODO: implement Furnace scheduled update
}
}

View File

@ -50,6 +50,15 @@ interface Inventory{
*/ */
public function getItem($index); public function getItem($index);
/**
* Puts an Item in a slot.
* If a plugin refuses the update or $index is invalid, it'll return false
*
* @param int $index
* @param Item $item
*
* @return bool
*/
public function setItem($index, Item $item); public function setItem($index, Item $item);
/** /**
@ -127,6 +136,8 @@ interface Inventory{
* Will clear a specific slot * Will clear a specific slot
* *
* @param int $index * @param int $index
*
* @return bool
*/ */
public function clear($index); public function clear($index);

View File

@ -26,10 +26,11 @@ namespace pocketmine\inventory;
*/ */
class InventoryType{ class InventoryType{
const CHEST = 0; const CHEST = 0;
const PLAYER = 1; const DOUBLE_CHEST = 1;
const FURNACE = 2; const PLAYER = 2;
const CRAFTING = 3; const FURNACE = 3;
const WORKBENCH = 4; const CRAFTING = 4;
const WORKBENCH = 5;
private static $default = []; private static $default = [];
@ -46,6 +47,7 @@ class InventoryType{
} }
static::$default[static::CHEST] = new InventoryType(27, "Chest"); static::$default[static::CHEST] = new InventoryType(27, "Chest");
static::$default[static::DOUBLE_CHEST] = new InventoryType(27 + 27, "Double Chest");
static::$default[static::PLAYER] = new InventoryType(31, "Player"); //27 CONTAINER, 4 ARMOR (9 reference HOTBAR slots) static::$default[static::PLAYER] = new InventoryType(31, "Player"); //27 CONTAINER, 4 ARMOR (9 reference HOTBAR slots)
static::$default[static::FURNACE] = new InventoryType(3, "Furnace"); static::$default[static::FURNACE] = new InventoryType(3, "Furnace");
static::$default[static::CRAFTING] = new InventoryType(5, "Crafting"); //4 CRAFTING slots, 1 RESULT static::$default[static::CRAFTING] = new InventoryType(5, "Crafting"); //4 CRAFTING slots, 1 RESULT

View File

@ -22,11 +22,15 @@
namespace pocketmine\inventory; namespace pocketmine\inventory;
use pocketmine\entity\Human; use pocketmine\entity\Human;
use pocketmine\event\entity\EntityArmorChangeEvent;
use pocketmine\event\player\PlayerItemHeldEvent;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\network\protocol\ContainerSetContentPacket; use pocketmine\network\protocol\ContainerSetContentPacket;
use pocketmine\network\protocol\ContainerSetSlotPacket;
use pocketmine\network\protocol\PlayerArmorEquipmentPacket; use pocketmine\network\protocol\PlayerArmorEquipmentPacket;
use pocketmine\network\protocol\PlayerEquipmentPacket; use pocketmine\network\protocol\PlayerEquipmentPacket;
use pocketmine\Player; use pocketmine\Player;
use pocketmine\Server;
class PlayerInventory extends BaseInventory{ class PlayerInventory extends BaseInventory{
@ -83,8 +87,13 @@ class PlayerInventory extends BaseInventory{
} }
} }
/**
* @param Item $item
*
* @return bool
*/
public function setItemInHand(Item $item){ public function setItemInHand(Item $item){
$this->setItem($this->getHeldItemSlot(), $item); return $this->setItem($this->getHeldItemSlot(), $item);
} }
public function getHeldItemSlot(){ public function getHeldItemSlot(){
@ -93,7 +102,33 @@ class PlayerInventory extends BaseInventory{
public function setHeldItemSlot($slot){ public function setHeldItemSlot($slot){
if($slot >= 0 and $slot < $this->getSize()){ if($slot >= 0 and $slot < $this->getSize()){
$item = $this->getItem($slot);
if($this->getHolder() instanceof Player){
Server::getInstance()->getPluginManager()->callEvent($ev = new PlayerItemHeldEvent($this->getHolder(), $item, $slot, 0));
if($ev->isCancelled()){
$this->sendHeldItem($this->getHolder());
return;
}
}
$this->setHotbarSlotIndex($this->itemInHandIndex, $slot); $this->setHotbarSlotIndex($this->itemInHandIndex, $slot);
$this->sendHeldItem($this->getHolder()->getViewers());
if($this->getHolder() instanceof Player){
$this->sendHeldItem($this->getHolder());
}
}
}
/**
* @param Player|Player[] $target
*/
public function sendHeldItem($target){
if($target instanceof Player){
$target = [$target];
}
$item = $this->getItemInHand(); $item = $this->getItemInHand();
$pk = new PlayerEquipmentPacket; $pk = new PlayerEquipmentPacket;
@ -102,7 +137,12 @@ class PlayerInventory extends BaseInventory{
$pk->meta = $item->getDamage(); $pk->meta = $item->getDamage();
$pk->slot = 0; $pk->slot = 0;
foreach($this->getHolder()->getViewers() as $player){ foreach($target as $player){
if($player === $this->getHolder()){
//TODO: Check if Mojang enabled sending a single slot this
//$this->sendSlot($this->getHeldItemSlot());
$this->sendContents($this->getHolder());
}else{
$player->dataPacket(clone $pk); $player->dataPacket(clone $pk);
} }
} }
@ -112,34 +152,11 @@ class PlayerInventory extends BaseInventory{
parent::onSlotChange($index, $before); parent::onSlotChange($index, $before);
if($index >= $this->getSize()){ if($index >= $this->getSize()){
$armor = $this->getArmorContents(); $this->sendArmorContents($this->getHolder()->getViewers());
$slots = [];
foreach($armor as $i => $slot){
if($slot->getID() === Item::AIR){
$slots[$i] = 255;
}else{
$slots[$i] = $slot->getID();
}
} }
$pk = new PlayerArmorEquipmentPacket; if($this->getHolder() instanceof Player){
$pk->eid = $this->getHolder()->getID(); $this->sendArmorContents($this->getHolder());
$pk->slots = $slots;
if($index >= $this->getSize()){ //Armor change
foreach($this->getHolder()->getViewers() as $player){
if($player === $this->getHolder()){
/** @var Player $player */
$pk2 = new ContainerSetContentPacket;
$pk2->windowid = 0x78; //Armor window id constant
$pk2->slots = $armor;
$player->dataPacket($pk2);
}else{
$player->dataPacket(clone $pk);
}
}
}
} }
} }
@ -147,6 +164,14 @@ class PlayerInventory extends BaseInventory{
return 9; return 9;
} }
public function getArmorItem($index){
return $this->getItem($this->getSize() + $index);
}
public function setArmorItem($index, Item $item){
return $this->setItem($this->getSize() + $index, $item);
}
public function getHelmet(){ public function getHelmet(){
return $this->getItem($this->getSize() + 3); return $this->getItem($this->getSize() + 3);
} }
@ -164,19 +189,66 @@ class PlayerInventory extends BaseInventory{
} }
public function setHelmet(Item $helmet){ public function setHelmet(Item $helmet){
$this->setItem($this->getSize() + 3, $helmet); return $this->setItem($this->getSize() + 3, $helmet);
} }
public function setChestplate(Item $chestplate){ public function setChestplate(Item $chestplate){
$this->setItem($this->getSize() + 2, $chestplate); return $this->setItem($this->getSize() + 2, $chestplate);
} }
public function setLeggings(Item $leggings){ public function setLeggings(Item $leggings){
$this->setItem($this->getSize() + 1, $leggings); return $this->setItem($this->getSize() + 1, $leggings);
} }
public function setBoots(Item $boots){ public function setBoots(Item $boots){
$this->setItem($this->getSize(), $boots); return $this->setItem($this->getSize(), $boots);
}
public function setItem($index, Item $item){
if($index < 0 or $index >= $this->size){
return false;
}
if($index >= $this->getSize()){ //Armor change
Server::getInstance()->getPluginManager()->callEvent($ev = new EntityArmorChangeEvent($this->getHolder(), $this->getItem($index), $item, $index));
if($ev->isCancelled()){
$this->sendArmorContents($this);
$this->sendContents($this);
return false;
}
$item = $ev->getNewItem();
}
$old = $this->slots[$index];
$this->slots[$index] = clone $item;
$this->onSlotChange($index, $old);
return true;
}
public function clear($index){
if(isset($this->slots[$index])){
$item = Item::get(Item::AIR, null, 0);
$old = $this->slots[$index];
if($index >= $this->getSize() and $index < $this->size){ //Armor change
Server::getInstance()->getPluginManager()->callEvent($ev = new EntityArmorChangeEvent($this->getHolder(), $old, $item, $index));
if($ev->isCancelled()){
$this->sendArmorContents($this);
$this->sendContents($this);
return;
}
$item = $ev->getNewItem();
}
if($item->getID() !== Item::AIR){
$this->slots[$index] = clone $item;
}else{
unset($this->slots[$index]);
}
$this->onSlotChange($index, $old);
}
} }
/** /**
@ -192,6 +264,41 @@ class PlayerInventory extends BaseInventory{
return $armor; return $armor;
} }
/**
* @param Player|Player[] $target
*/
public function sendArmorContents($target){
if($target instanceof Player){
$target = [$target];
}
$armor = $this->getArmorContents();
$slots = [];
foreach($armor as $i => $slot){
if($slot->getID() === Item::AIR){
$slots[$i] = 255;
}else{
$slots[$i] = $slot->getID();
}
}
$pk = new PlayerArmorEquipmentPacket;
$pk->eid = $this->getHolder()->getID();
$pk->slots = $slots;
foreach($target as $player){
if($player === $this->getHolder()){
/** @var Player $player */
$pk2 = new ContainerSetContentPacket;
$pk2->windowid = 0x78; //Armor window id constant
$pk2->slots = $armor;
$player->dataPacket($pk2);
}else{
$player->dataPacket(clone $pk);
}
}
}
/** /**
* @param Item[] $items * @param Item[] $items
*/ */
@ -209,6 +316,62 @@ class PlayerInventory extends BaseInventory{
} }
} }
/**
* @param Player|Player[] $target
*/
public function sendContents($target){
if($target instanceof Player){
$target = [$target];
}
$holder = $this->getHolder();
if($holder instanceof Player and ($holder->getGamemode() & 0x01) === 1){
return;
}
$pk = new ContainerSetContentPacket();
$pk->slots = [];
for($i = 0; $i < $this->getSize(); ++$i){ //Do not send armor by error here
$pk->slots[$i] = $this->getItem($i);
}
foreach($target as $player){
$pk->hotbar = [];
if($player === $this->getHolder()){
for($i = 0; $i < $this->getHotbarSize(); ++$i){
$index = $this->getHotbarSlotIndex($i);
$pk->hotbar[] = $index <= -1 ? -1 : $index + 9;
}
}
$pk->windowid = $player->getWindowId($this);
$player->dataPacket(clone $pk);
}
}
/**
* @param int $index
* @param Player|Player[] $target
*/
public function sendSlot($index, $target){
if($target instanceof Player){
$target = [$target];
}
$pk = new ContainerSetSlotPacket;
$pk->slot = $index;
$pk->item = clone $this->getItem($index);
foreach($target as $player){
if($player === $this->getHolder()){
//TODO: Check if Mojang has implemented this (for the player inventory) on Minecraft: PE 0.9.0
$this->sendContents($player);
}else{
$pk->windowid = $player->getWindowId($this);
$player->dataPacket(clone $pk);
}
}
}
/** /**
* @return Human * @return Human
*/ */

View File

@ -31,6 +31,7 @@ use pocketmine\event\block\BlockBreakEvent;
use pocketmine\event\block\BlockPlaceEvent; use pocketmine\event\block\BlockPlaceEvent;
use pocketmine\event\player\PlayerInteractEvent; use pocketmine\event\player\PlayerInteractEvent;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\level\format\pmf\LevelFormat;
use pocketmine\level\generator\Generator; use pocketmine\level\generator\Generator;
use pocketmine\math\Vector2; use pocketmine\math\Vector2;
use pocketmine\math\Vector3 as Vector3; use pocketmine\math\Vector3 as Vector3;
@ -42,7 +43,6 @@ use pocketmine\nbt\tag\String;
use pocketmine\network\protocol\SetTimePacket; use pocketmine\network\protocol\SetTimePacket;
use pocketmine\network\protocol\UpdateBlockPacket; use pocketmine\network\protocol\UpdateBlockPacket;
use pocketmine\Player; use pocketmine\Player;
use pocketmine\level\format\pmf\LevelFormat;
use pocketmine\Server; use pocketmine\Server;
use pocketmine\tile\Chest; use pocketmine\tile\Chest;
use pocketmine\tile\Furnace; use pocketmine\tile\Furnace;

View File

@ -21,9 +21,9 @@
namespace pocketmine\level; namespace pocketmine\level;
use pocketmine\level\format\pmf\LevelFormat;
use pocketmine\level\format\PocketChunkParser; use pocketmine\level\format\PocketChunkParser;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\level\format\pmf\LevelFormat;
use pocketmine\utils\Config; use pocketmine\utils\Config;
class LevelImport{ class LevelImport{

View File

@ -106,6 +106,7 @@ class Position extends Vector3{
if(!$this->isValid()){ if(!$this->isValid()){
throw new \RuntimeException("Undefined Level reference"); throw new \RuntimeException("Undefined Level reference");
} }
return Position::fromObject(parent::getSide($side, $step), $this->getLevel()); return Position::fromObject(parent::getSide($side, $step), $this->getLevel());
} }

View File

@ -21,8 +21,8 @@
namespace pocketmine\level; namespace pocketmine\level;
use pocketmine\level\generator\Generator;
use pocketmine\level\format\pmf\LevelFormat; use pocketmine\level\format\pmf\LevelFormat;
use pocketmine\level\generator\Generator;
use pocketmine\Server; use pocketmine\Server;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\Random; use pocketmine\utils\Random;

View File

@ -55,7 +55,7 @@ interface Chunk{
* @param int $x 0-15 * @param int $x 0-15
* @param int $y 0-127 * @param int $y 0-127
* @param int $z 0-15 * @param int $z 0-15
* @param int $blockId, if null, do not change * @param int $blockId , if null, do not change
* @param int $meta 0-15, if null, do not change * @param int $meta 0-15, if null, do not change
*/ */
public function setBlock($x, $y, $z, $blockId = null, $meta = null); public function setBlock($x, $y, $z, $blockId = null, $meta = null);

View File

@ -72,7 +72,7 @@ interface ChunkSection{
* @param int $x 0-15 * @param int $x 0-15
* @param int $y 0-15 * @param int $y 0-15
* @param int $z 0-15 * @param int $z 0-15
* @param int $blockId, if null, do not change * @param int $blockId , if null, do not change
* @param int $meta 0-15, if null, do not change * @param int $meta 0-15, if null, do not change
*/ */
public function setBlock($x, $y, $z, $blockId = null, $meta = null); public function setBlock($x, $y, $z, $blockId = null, $meta = null);

View File

@ -20,8 +20,9 @@
*/ */
namespace pocketmine\level\format; namespace pocketmine\level\format;
use pocketmine\Server;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\Server;
/** /**
* All Level formats must implement this interface * All Level formats must implement this interface

View File

@ -22,7 +22,6 @@
namespace pocketmine\level\format; namespace pocketmine\level\format;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\Utils;
/** /**
* WARNING: This code is old, and only supports the file format partially (reverse engineering) * WARNING: This code is old, and only supports the file format partially (reverse engineering)

View File

@ -138,6 +138,7 @@ class ChunkSection implements \pocketmine\level\format\ChunkSection{
for($y = 15; $y >= 0; --$y){ for($y = 15; $y >= 0; --$y){
$column{15 - $y} = $this->blocks{($y << 8) + $i}; $column{15 - $y} = $this->blocks{($y << 8) + $i};
} }
return $column; return $column;
} }
@ -147,6 +148,7 @@ class ChunkSection implements \pocketmine\level\format\ChunkSection{
for($y = 7; $y >= 0; --$y){ for($y = 7; $y >= 0; --$y){
$column{7 - $y} = $this->data{($y << 7) + $i}; $column{7 - $y} = $this->data{($y << 7) + $i};
} }
return $column; return $column;
} }

View File

@ -21,7 +21,6 @@
namespace pocketmine\level\format\anvil; namespace pocketmine\level\format\anvil;
use pocketmine\level\Level;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\Byte; use pocketmine\nbt\tag\Byte;
use pocketmine\nbt\tag\ByteArray; use pocketmine\nbt\tag\ByteArray;
@ -45,10 +44,12 @@ class RegionLoader{
protected $lastSector; protected $lastSector;
protected $locationTable = []; protected $locationTable = [];
public function __construct($path,/*Level $level, */$regionX, $regionZ){ public function __construct($path, /*Level $level, */
$regionX, $regionZ){
$this->x = $regionX; $this->x = $regionX;
$this->z = $regionZ; $this->z = $regionZ;
$this->filePath = /*$level->getPath()*/$path . "region/r.$regionX.$regionZ.mca"; $this->filePath = /*$level->getPath()*/
$path . "region/r.$regionX.$regionZ.mca";
touch($this->filePath); touch($this->filePath);
$this->filePointer = fopen($this->filePath, "r+b"); $this->filePointer = fopen($this->filePath, "r+b");
flock($this->filePointer, LOCK_EX); flock($this->filePointer, LOCK_EX);
@ -103,6 +104,7 @@ class RegionLoader{
$this->writeLocationIndex($index); $this->writeLocationIndex($index);
}elseif($compression !== self::COMPRESSION_ZLIB and $compression !== self::COMPRESSION_GZIP){ }elseif($compression !== self::COMPRESSION_ZLIB and $compression !== self::COMPRESSION_GZIP){
trigger_error("Invalid compression type", E_USER_WARNING); trigger_error("Invalid compression type", E_USER_WARNING);
return false; return false;
} }
@ -113,6 +115,7 @@ class RegionLoader{
if(!$chunk instanceof Compound){ if(!$chunk instanceof Compound){
return false; return false;
} }
return $chunk; return $chunk;
//$chunk = new Chunk($level, $chunk); //$chunk = new Chunk($level, $chunk);
} }
@ -183,6 +186,7 @@ class RegionLoader{
$this->writeLocationTable(); $this->writeLocationTable();
$n = $this->cleanGarbage(); $n = $this->cleanGarbage();
$this->writeLocationTable(); $this->writeLocationTable();
return $n; return $n;
} }

View File

@ -20,6 +20,7 @@
*/ */
namespace pocketmine\level\format\generic; namespace pocketmine\level\format\generic;
use pocketmine\level\format\Chunk; use pocketmine\level\format\Chunk;
use pocketmine\level\format\ChunkSection; use pocketmine\level\format\ChunkSection;
use pocketmine\level\Level; use pocketmine\level\Level;
@ -48,11 +49,13 @@ abstract class BaseChunk implements Chunk{
$this->sections[$Y] = $section; $this->sections[$Y] = $section;
}else{ }else{
trigger_error("Received invalid ChunkSection instance", E_USER_ERROR); trigger_error("Received invalid ChunkSection instance", E_USER_ERROR);
return; return;
} }
if($section >= self::SECTION_COUNT){ if($section >= self::SECTION_COUNT){
trigger_error("Invalid amount of chunks", E_USER_WARNING); trigger_error("Invalid amount of chunks", E_USER_WARNING);
return; return;
} }
} }

View File

@ -20,6 +20,7 @@
*/ */
namespace pocketmine\level\format\generic; namespace pocketmine\level\format\generic;
use pocketmine\level\format\ChunkSection; use pocketmine\level\format\ChunkSection;
/** /**

View File

@ -32,6 +32,7 @@ class ChunkSection implements \pocketmine\level\format\ChunkSection{
if($section !== null){ if($section !== null){
if(strlen($section) !== 8192){ if(strlen($section) !== 8192){
trigger_error("Invalid ChunkSection generated", E_USER_WARNING); trigger_error("Invalid ChunkSection generated", E_USER_WARNING);
return; return;
} }
$this->section = $section; $this->section = $section;

View File

@ -26,7 +26,6 @@ use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\Compound; use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\Enum; use pocketmine\nbt\tag\Enum;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\Utils;
class LevelFormat extends PMF{ class LevelFormat extends PMF{
const VERSION = 2; const VERSION = 2;

View File

@ -41,6 +41,7 @@ abstract class MetadataStore{
$owningPlugin = $newMetadataValue->getOwningPlugin(); $owningPlugin = $newMetadataValue->getOwningPlugin();
if($owningPlugin === null){ if($owningPlugin === null){
trigger_error("Plugin cannot be null", E_USER_WARNING); trigger_error("Plugin cannot be null", E_USER_WARNING);
return; return;
} }

View File

@ -39,7 +39,6 @@ use pocketmine\nbt\tag\Short;
use pocketmine\nbt\tag\String; use pocketmine\nbt\tag\String;
use pocketmine\nbt\tag\Tag; use pocketmine\nbt\tag\Tag;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\Utils;
/** /**
* Named Binary Tag encoder/decoder * Named Binary Tag encoder/decoder

View File

@ -22,7 +22,6 @@
namespace pocketmine\network\protocol; namespace pocketmine\network\protocol;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\Utils;
class AddMobPacket extends DataPacket{ class AddMobPacket extends DataPacket{
public $eid; public $eid;

View File

@ -22,7 +22,6 @@
namespace pocketmine\network\protocol; namespace pocketmine\network\protocol;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\Utils;
class AddPlayerPacket extends DataPacket{ class AddPlayerPacket extends DataPacket{
public $clientID; public $clientID;

View File

@ -23,7 +23,6 @@ namespace pocketmine\network\protocol;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\Utils;
abstract class DataPacket extends \stdClass{ abstract class DataPacket extends \stdClass{
private $offset = 0; private $offset = 0;

View File

@ -22,7 +22,6 @@
namespace pocketmine\network\protocol; namespace pocketmine\network\protocol;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\Utils;
class SetEntityDataPacket extends DataPacket{ class SetEntityDataPacket extends DataPacket{
public $eid; public $eid;

View File

@ -23,7 +23,6 @@ namespace pocketmine\network\query;
use pocketmine\network\Packet; use pocketmine\network\Packet;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\Utils;
class QueryPacket extends Packet{ class QueryPacket extends Packet{
const HANDSHAKE = 9; const HANDSHAKE = 9;

View File

@ -79,7 +79,6 @@ use pocketmine\network\protocol\UnknownPacket;
use pocketmine\network\protocol\UpdateBlockPacket; use pocketmine\network\protocol\UpdateBlockPacket;
use pocketmine\network\protocol\UseItemPacket; use pocketmine\network\protocol\UseItemPacket;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\Utils;
class Packet extends NetworkPacket{ class Packet extends NetworkPacket{
private $packetID; private $packetID;

View File

@ -22,7 +22,6 @@
namespace pocketmine\network\rcon; namespace pocketmine\network\rcon;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\Utils;
class RCONInstance extends \Thread{ class RCONInstance extends \Thread{
public $stop; public $stop;

View File

@ -23,6 +23,7 @@
* Plugin related classes * Plugin related classes
*/ */
namespace pocketmine\plugin; namespace pocketmine\plugin;
use pocketmine\command\CommandExecutor; use pocketmine\command\CommandExecutor;

View File

@ -30,7 +30,7 @@ class PluginLogger{
*/ */
public function __construct(Plugin $context){ public function __construct(Plugin $context){
$prefix = $context->getDescription()->getPrefix(); $prefix = $context->getDescription()->getPrefix();
$this->pluginName = $prefix != null ? "[$prefix] " : "[".$context->getDescription()->getName()."] "; $this->pluginName = $prefix != null ? "[$prefix] " : "[" . $context->getDescription()->getName() . "] ";
} }
/** /**

View File

@ -148,6 +148,7 @@ class PluginManager{
if(count($pluginCommands) > 0){ if(count($pluginCommands) > 0){
$this->commandMap->registerAll($plugin->getDescription()->getName(), $pluginCommands); $this->commandMap->registerAll($plugin->getDescription()->getName(), $pluginCommands);
} }
return $plugin; return $plugin;
} }
} }

View File

@ -52,8 +52,9 @@ abstract class AsyncTask extends \Threaded{
* @return mixed * @return mixed
*/ */
public function getResult(){ public function getResult(){
return $this->synchronized(function(){ return $this->synchronized(function (){
$this->finished = true; $this->finished = true;
return @unserialize($this->result); return @unserialize($this->result);
}); });
} }

View File

@ -26,6 +26,7 @@ class AsyncWorker extends \Worker{
public function start($options = PTHREADS_INHERIT_CLASSES){ public function start($options = PTHREADS_INHERIT_CLASSES){
$this->path = \pocketmine\PATH; $this->path = \pocketmine\PATH;
return parent::start($options & ~PTHREADS_INHERIT_CLASSES); return parent::start($options & ~PTHREADS_INHERIT_CLASSES);
} }

View File

@ -205,11 +205,13 @@ class ServerScheduler{
} }
if($this->asyncTasks > 0){ //Garbage collector if($this->asyncTasks > 0){ //Garbage collector
$this->asyncPool->collect(function(AsyncTask $task){ $this->asyncPool->collect(function (AsyncTask $task){
if($task->isCompleted() or ($task->isFinished() and !$task->hasResult())){ if($task->isCompleted() or ($task->isFinished() and !$task->hasResult())){
--$this->asyncTasks; --$this->asyncTasks;
return true; return true;
} }
return false; return false;
}); });
} }

View File

@ -21,23 +21,134 @@
namespace pocketmine\tile; namespace pocketmine\tile;
use pocketmine\inventory\ChestInventory;
use pocketmine\inventory\DoubleChestInventory;
use pocketmine\inventory\InventoryHolder;
use pocketmine\item\Item;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\math\Vector3 as Vector3; use pocketmine\math\Vector3 as Vector3;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\Byte;
use pocketmine\nbt\tag\Compound; use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\Int; use pocketmine\nbt\tag\Int;
use pocketmine\nbt\tag\Short;
use pocketmine\nbt\tag\String; use pocketmine\nbt\tag\String;
use pocketmine\network\protocol\EntityDataPacket; use pocketmine\network\protocol\EntityDataPacket;
use pocketmine\Player; use pocketmine\Player;
class Chest extends Spawnable{ class Chest extends Spawnable implements InventoryHolder, Container{
use Container;
const SLOTS = 27; /** @var ChestInventory */
protected $inventory;
/** @var DoubleChestInventory */
protected $doubleInventory = null;
public function __construct(Level $level, Compound $nbt){ public function __construct(Level $level, Compound $nbt){
$nbt["id"] = Tile::CHEST; $nbt["id"] = Tile::CHEST;
parent::__construct($level, $nbt); parent::__construct($level, $nbt);
$this->inventory = new ChestInventory($this);
for($i = 0; $i < $this->getSize(); ++$i){
$this->inventory->setItem($i, $this->getItem($i));
}
$this->checkPairing();
}
/**
* @return int
*/
public function getSize(){
return 27;
}
/**
* @param $index
*
* @return int
*/
protected function getSlotIndex($index){
foreach($this->namedtag->Items as $i => $slot){
if($slot["Slot"] === $s){
return $i;
}
}
return -1;
}
/**
* This method should not be used by plugins, use the Inventory
*
* @param int $index
*
* @return Item
*/
public function getItem($index){
$i = $this->getSlotIndex($index);
if($i < 0){
return Item::get(Item::AIR, 0, 0);
}else{
return Item::get($this->namedtag->Items[$i]["id"], $this->namedtag->Items[$i]["Damage"], $this->namedtag->Items[$i]["Count"]);
}
}
/**
* This method should not be used by plugins, use the Inventory
*
* @param int $index
* @param Item $item
*
* @return bool
*/
public function setItem($index, Item $item){
$i = $this->getSlotIndex($index);
if($i < 0){
return false;
}
$d = new Compound(false, array(
new Byte("Count", $item->getCount()),
new Byte("Slot", $index),
new Short("id", $item->getID()),
new Short("Damage", $item->getDamage()),
));
if($item->getID() === Item::AIR or $item->getCount() <= 0){
if($i >= 0){
unset($this->namedtag->Items[$i]);
}
}elseif($i < 0){
$this->namedtag->Items[] = $d;
}else{
$this->namedtag->Items[$i] = $d;
}
return true;
}
/**
* @return ChestInventory|DoubleChestInventory
*/
public function getInventory(){
return $this->doubleInventory instanceof DoubleChestInventory ? $this->doubleInventory : $this->inventory;
}
/**
* @return ChestInventory
*/
public function getRealInventory(){
return $this->inventory;
}
protected function checkPairing(){
if(($pair = $this->getPair()) instanceof Chest){
if(($pair->x + ($pair->z << 15)) > ($this->x + ($this->z << 15))){ //Order them correctly
$this->doubleInventory = new DoubleChestInventory($pair, $this);
}else{
$this->doubleInventory = new DoubleChestInventory($this, $pair);
}
}else{
$this->doubleInventory = null;
}
} }
public function isPaired(){ public function isPaired(){
@ -48,12 +159,18 @@ class Chest extends Spawnable{
return true; return true;
} }
/**
* @return Chest
*/
public function getPair(){ public function getPair(){
if($this->isPaired()){ if($this->isPaired()){
return $this->getLevel()->getTile(new Vector3((int) $this->namedtag->pairx, $this->y, (int) $this->namedtag->pairz)); $tile = $this->getLevel()->getTile(new Vector3((int) $this->namedtag->pairx, $this->y, (int) $this->namedtag->pairz));
if($tile instanceof Chest){
return $tile;
}
} }
return false; return null;
} }
public function pairWith(Chest $tile){ public function pairWith(Chest $tile){
@ -69,10 +186,11 @@ class Chest extends Spawnable{
$this->spawnToAll(); $this->spawnToAll();
$tile->spawnToAll(); $tile->spawnToAll();
$this->checkPairing();
//TODO: Update to new events //TODO: Update to new events
$this->server->handle("tile.update", $this); //$this->server->handle("tile.update", $this);
$this->server->handle("tile.update", $tile); //$this->server->handle("tile.update", $tile);
return true; return true;
} }
@ -86,10 +204,12 @@ class Chest extends Spawnable{
unset($this->namedtag->pairx, $this->namedtag->pairz, $tile->namedtag->pairx, $tile->namedtag->pairz); unset($this->namedtag->pairx, $this->namedtag->pairz, $tile->namedtag->pairx, $tile->namedtag->pairz);
$this->spawnToAll(); $this->spawnToAll();
$this->server->handle("tile.update", $this); $this->checkPairing();
//TODO: tile update event
//$this->server->handle("tile.update", $this);
if($tile instanceof Chest){ if($tile instanceof Chest){
$tile->spawnToAll(); $tile->spawnToAll();
$this->server->handle("tile.update", $tile); //$this->server->handle("tile.update", $tile);
} }
return true; return true;

View File

@ -23,178 +23,12 @@ namespace pocketmine\tile;
use pocketmine\event\tile\TileInventoryChangeEvent; use pocketmine\event\tile\TileInventoryChangeEvent;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\nbt\tag\Byte;
use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\Short;
use pocketmine\Network; use pocketmine\Network;
use pocketmine\network\protocol\ContainerOpenPacket;
use pocketmine\network\protocol\ContainerSetContentPacket;
use pocketmine\network\protocol\TileEventPacket;
use pocketmine\Player;
use pocketmine\Server;
trait Container{ interface Container{
public function openInventory(Player $player){ public function getItem($index);
if($this instanceof Chest){
$player->windowCnt++;
$player->windowCnt = $id = max(2, $player->windowCnt % 99);
if(($pair = $this->getPair()) !== false){
if(($pair->x + ($pair->z << 13)) > ($this->x + ($this->z << 13))){ //Order them correctly
$player->windows[$id] = array(
$pair,
$this
);
}else{
$player->windows[$id] = array(
$this,
$pair
);
}
}else{
$player->windows[$id] = $this;
}
$pk = new ContainerOpenPacket(); public function setItem($index, Item $item);
$pk->windowid = $id;
$pk->type = 0;
$pk->slots = is_array($player->windows[$id]) ? Chest::SLOTS << 1 : Chest::SLOTS;
$pk->x = $this->x;
$pk->y = $this->y;
$pk->z = $this->z;
$player->dataPacket($pk);
$slots = [];
if(is_array($player->windows[$id])){ public function getSize();
$all = $this->getLevel()->getPlayers();
foreach($player->windows[$id] as $ob){
$pk = new TileEventPacket();
$pk->x = $ob->x;
$pk->y = $ob->y;
$pk->z = $ob->z;
$pk->case1 = 1;
$pk->case2 = 2;
Player::broadcastPacket($all, $pk);
for($s = 0; $s < Chest::SLOTS; ++$s){
$slot = $ob->getSlot($s);
if($slot->getID() > Item::AIR and $slot->getCount() > 0){
$slots[] = $slot;
}else{
$slots[] = Item::get(Item::AIR, 0, 0);
}
}
}
}else{
$pk = new TileEventPacket();
$pk->x = $this->x;
$pk->y = $this->y;
$pk->z = $this->z;
$pk->case1 = 1;
$pk->case2 = 2;
Player::broadcastPacket($this->getLevel()->getPlayers(), $pk);
for($s = 0; $s < Chest::SLOTS; ++$s){
$slot = $this->getSlot($s);
if($slot->getID() > Item::AIR and $slot->getCount() > 0){
$slots[] = $slot;
}else{
$slots[] = Item::get(Item::AIR, 0, 0);
}
}
}
$pk = new ContainerSetContentPacket();
$pk->windowid = $id;
$pk->slots = $slots;
$player->dataPacket($pk);
return true;
}elseif($this instanceof Furnace){
$player->windowCnt++;
$player->windowCnt = $id = max(2, $player->windowCnt % 99);
$player->windows[$id] = $this;
$pk = new ContainerOpenPacket();
$pk->windowid = $id;
$pk->type = 2;
$pk->slots = Furnace::SLOTS;
$pk->x = $this->x;
$pk->y = $this->y;
$pk->z = $this->z;
$player->dataPacket($pk);
$slots = [];
for($s = 0; $s < Furnace::SLOTS; ++$s){
$slot = $this->getSlot($s);
if($slot->getID() > Item::AIR and $slot->getCount() > 0){
$slots[] = $slot;
}else{
$slots[] = Item::get(Item::AIR, 0, 0);
}
}
$pk = new ContainerSetContentPacket();
$pk->windowid = $id;
$pk->slots = $slots;
$player->dataPacket($pk);
return true;
}
}
public function getSlotIndex($s){
foreach($this->namedtag->Items as $i => $slot){
if($slot["Slot"] === $s){
return $i;
}
}
return -1;
}
/**
* @param int $s
*
* @return Item
*/
public function getSlot($s){
$i = $this->getSlotIndex($s);
if($i === false or $i < 0){
return Item::get(Item::AIR, 0, 0);
}else{
return Item::get($this->namedtag->Items[$i]["id"], $this->namedtag->Items[$i]["Damage"], $this->namedtag->Items[$i]["Count"]);
}
}
public function setSlot($s, Item $item, $update = true, $offset = 0){
$i = $this->getSlotIndex($s);
if($i === false){
return false;
}
Server::getInstance()->getPluginManager()->callEvent($ev = new TileInventoryChangeEvent($this, $this->getSlot($s), $item, $s, $offset));
if($ev->isCancelled()){
return false;
}
$item = $ev->getNewItem();
$d = new Compound(false, array(
new Byte("Count", $item->getCount()),
new Byte("Slot", $s),
new Short("id", $item->getID()),
new Short("Damage", $item->getDamage()),
));
if($item->getID() === Item::AIR or $item->getCount() <= 0){
if($i >= 0){
unset($this->namedtag->Items[$i]);
}
}elseif($i < 0){
$this->namedtag->Items[] = $d;
}else{
$this->namedtag->Items[$i] = $d;
}
if($update === true){
$this->scheduleUpdate();
}
return true;
}
} }

View File

@ -22,18 +22,26 @@
namespace pocketmine\tile; namespace pocketmine\tile;
use pocketmine\block\Block; use pocketmine\block\Block;
use pocketmine\inventory\FurnaceInventory;
use pocketmine\inventory\InventoryHolder;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\nbt\tag\Byte;
use pocketmine\nbt\tag\Compound; use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\Short;
class Furnace extends Tile{ class Furnace extends Tile implements InventoryHolder, Container{
use Container; /** @var FurnaceInventory */
protected $inventory;
const SLOTS = 3;
public function __construct(Level $level, Compound $nbt){ public function __construct(Level $level, Compound $nbt){
$nbt["id"] = Tile::FURNACE; $nbt["id"] = Tile::FURNACE;
parent::__construct($level, $nbt); parent::__construct($level, $nbt);
$this->inventory = new FurnaceInventory($this);
for($i = 0; $i < $this->getSize(); ++$i){
$this->inventory->setItem($i, $this->getItem($i));
}
if(!isset($this->namedtag->BurnTime) or $this->namedtag->BurnTime < 0){ if(!isset($this->namedtag->BurnTime) or $this->namedtag->BurnTime < 0){
$this->namedtag->BurnTime = 0; $this->namedtag->BurnTime = 0;
} }
@ -49,6 +57,85 @@ class Furnace extends Tile{
} }
} }
/**
* @return int
*/
public function getSize(){
return 3;
}
/**
* @param $index
*
* @return int
*/
protected function getSlotIndex($index){
foreach($this->namedtag->Items as $i => $slot){
if($slot["Slot"] === $s){
return $i;
}
}
return -1;
}
/**
* This method should not be used by plugins, use the Inventory
*
* @param int $index
*
* @return Item
*/
public function getItem($index){
$i = $this->getSlotIndex($index);
if($i < 0){
return Item::get(Item::AIR, 0, 0);
}else{
return Item::get($this->namedtag->Items[$i]["id"], $this->namedtag->Items[$i]["Damage"], $this->namedtag->Items[$i]["Count"]);
}
}
/**
* This method should not be used by plugins, use the Inventory
*
* @param int $index
* @param Item $item
*
* @return bool
*/
public function setItem($index, Item $item){
$i = $this->getSlotIndex($index);
if($i < 0){
return false;
}
$d = new Compound(false, array(
new Byte("Count", $item->getCount()),
new Byte("Slot", $index),
new Short("id", $item->getID()),
new Short("Damage", $item->getDamage()),
));
if($item->getID() === Item::AIR or $item->getCount() <= 0){
if($i >= 0){
unset($this->namedtag->Items[$i]);
}
}elseif($i < 0){
$this->namedtag->Items[] = $d;
}else{
$this->namedtag->Items[$i] = $d;
}
return true;
}
/**
* @return FurnaceInventory
*/
public function getInventory(){
return $this->inventory;
}
public function onUpdate(){ public function onUpdate(){
if($this->closed === true){ if($this->closed === true){
return false; return false;
@ -56,9 +143,9 @@ class Furnace extends Tile{
$ret = false; $ret = false;
$fuel = $this->getSlot(1); $fuel = $this->inventory->getFuel();
$raw = $this->getSlot(0); $raw = $this->inventory->getSmelting();
$product = $this->getSlot(2); $product = $this->inventory->getResult();
$smelt = $raw->getSmeltItem(); $smelt = $raw->getSmeltItem();
$canSmelt = ($smelt !== false and $raw->getCount() > 0 and (($product->getID() === $smelt->getID() and $product->getDamage() === $smelt->getDamage() and $product->getCount() < $product->getMaxStackSize()) or $product->getID() === Item::AIR)); $canSmelt = ($smelt !== false and $raw->getCount() > 0 and (($product->getID() === $smelt->getID() and $product->getDamage() === $smelt->getDamage() and $product->getCount() < $product->getMaxStackSize()) or $product->getID() === Item::AIR));
if($this->namedtag->BurnTime <= 0 and $canSmelt and $fuel->getFuelTime() !== false and $fuel->getCount() > 0){ if($this->namedtag->BurnTime <= 0 and $canSmelt and $fuel->getFuelTime() !== false and $fuel->getCount() > 0){
@ -69,7 +156,7 @@ class Furnace extends Tile{
if($fuel->getCount() === 0){ if($fuel->getCount() === 0){
$fuel = Item::get(Item::AIR, 0, 0); $fuel = Item::get(Item::AIR, 0, 0);
} }
$this->setSlot(1, $fuel, false); $this->inventory->setFuel($fuel);
$current = $this->getLevel()->getBlock($this); $current = $this->getLevel()->getBlock($this);
if($current->getID() === Item::FURNACE){ if($current->getID() === Item::FURNACE){
$this->getLevel()->setBlock($this, Block::get(Item::BURNING_FURNACE, $current->getDamage()), true, false, true); $this->getLevel()->setBlock($this, Block::get(Item::BURNING_FURNACE, $current->getDamage()), true, false, true);
@ -83,12 +170,12 @@ class Furnace extends Tile{
$this->namedtag->CookTime += $ticks; $this->namedtag->CookTime += $ticks;
if($this->namedtag->CookTime >= 200){ //10 seconds if($this->namedtag->CookTime >= 200){ //10 seconds
$product = Item::get($smelt->getID(), $smelt->getDamage(), $product->getCount() + 1); $product = Item::get($smelt->getID(), $smelt->getDamage(), $product->getCount() + 1);
$this->setSlot(2, $product, false); $this->inventory->setResult($product);
$raw->setCount($raw->getCount() - 1); $raw->setCount($raw->getCount() - 1);
if($raw->getCount() === 0){ if($raw->getCount() === 0){
$raw = Item::get(Item::AIR, 0, 0); $raw = Item::get(Item::AIR, 0, 0);
} }
$this->setSlot(0, $raw, false); $this->inventory->setSmelting($raw);
$this->namedtag->CookTime -= 200; $this->namedtag->CookTime -= 200;
} }
}elseif($this->namedtag->BurnTime <= 0){ }elseif($this->namedtag->BurnTime <= 0){
@ -109,8 +196,8 @@ class Furnace extends Tile{
$this->namedtag->BurnTicks = 0; $this->namedtag->BurnTicks = 0;
} }
//TODO: tile update event
$this->server->handle("tile.update", $this); //$this->server->handle("tile.update", $this);
$this->lastUpdate = microtime(true); $this->lastUpdate = microtime(true);
return $ret; return $ret;

View File

@ -28,7 +28,7 @@ abstract class Spawnable extends Tile{
public function spawnToAll(){ public function spawnToAll(){
foreach($this->getLevel()->getPlayers() as $player){ foreach($this->getLevel()->getPlayers() as $player){
if($player->eid !== false or $player->spawned !== true){ if($player->spawned === true){
$this->spawnTo($player); $this->spawnTo($player);
} }
} }

View File

@ -25,10 +25,10 @@
*/ */
namespace pocketmine\tile; namespace pocketmine\tile;
use pocketmine\level\format\pmf\LevelFormat;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\level\Position; use pocketmine\level\Position;
use pocketmine\nbt\tag\Compound; use pocketmine\nbt\tag\Compound;
use pocketmine\level\format\pmf\LevelFormat;
use pocketmine\Server; use pocketmine\Server;
abstract class Tile extends Position{ abstract class Tile extends Position{
@ -36,6 +36,8 @@ abstract class Tile extends Position{
const CHEST = "Chest"; const CHEST = "Chest";
const FURNACE = "Furnace"; const FURNACE = "Furnace";
//TODO: pre-close step NBT data saving method
public static $tileCount = 1; public static $tileCount = 1;
/** /**
@ -89,8 +91,8 @@ abstract class Tile extends Position{
$index = LevelFormat::getIndex($this->x >> 4, $this->z >> 4); $index = LevelFormat::getIndex($this->x >> 4, $this->z >> 4);
$this->chunkIndex = $index; $this->chunkIndex = $index;
$this->level->tiles[$this->id] = $this; $this->getLevel()->tiles[$this->id] = $this;
$this->level->chunkTiles[$this->chunkIndex][$this->id] = $this; $this->getLevel()->chunkTiles[$this->chunkIndex][$this->id] = $this;
} }
public function onUpdate(){ public function onUpdate(){
@ -105,8 +107,8 @@ abstract class Tile extends Position{
if($this->closed === false){ if($this->closed === false){
$this->closed = true; $this->closed = true;
unset(Tile::$needUpdate[$this->id]); unset(Tile::$needUpdate[$this->id]);
unset($this->level->tiles[$this->id]); unset($this->getLevel()->tiles[$this->id]);
unset($this->level->chunkTiles[$this->chunkIndex][$this->id]); unset($this->getLevel()->chunkTiles[$this->chunkIndex][$this->id]);
unset(Tile::$list[$this->id]); unset(Tile::$list[$this->id]);
} }
} }

View File

@ -171,6 +171,7 @@ class Binary{
return $m; return $m;
} }
/** /**
* Reads a byte boolean * Reads a byte boolean
* *

View File

@ -262,6 +262,7 @@ class Config{
$currPath = null; $currPath = null;
} }
} }
return $currPath; return $currPath;
} }

View File

@ -69,6 +69,7 @@ class Random{
if($t > 2147483647){ if($t > 2147483647){
$t -= 4294967296; $t -= 4294967296;
} }
return (int) $t; return (int) $t;
} }

View File

@ -274,6 +274,7 @@ class TextFormat{
break; break;
} }
} }
return $newString; return $newString;
} }

View File

@ -24,8 +24,6 @@
*/ */
namespace pocketmine\utils; namespace pocketmine\utils;
use pocketmine\item\Item;
/** /**
* Big collection of functions * Big collection of functions
*/ */