From 274f972b58f27324535a880db8103bb30cc7ba3c Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Sun, 25 May 2014 21:57:58 +0200 Subject: [PATCH] Items can be picked up --- src/pocketmine/Player.php | 73 ++++++++++++-------- src/pocketmine/entity/DroppedItem.php | 16 +++-- src/pocketmine/entity/Entity.php | 8 ++- src/pocketmine/inventory/BaseInventory.php | 42 +++++++---- src/pocketmine/inventory/Inventory.php | 11 ++- src/pocketmine/inventory/PlayerInventory.php | 4 -- src/pocketmine/level/Level.php | 6 +- 7 files changed, 109 insertions(+), 51 deletions(-) diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 7a0fcb7b0..f626c955d 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -23,6 +23,7 @@ namespace pocketmine; use pocketmine\block\Block; use pocketmine\command\CommandSender; +use pocketmine\entity\DroppedItem; use pocketmine\entity\Human; use pocketmine\event\player\PlayerAchievementAwardedEvent; use pocketmine\event\player\PlayerChatEvent; @@ -60,6 +61,7 @@ use pocketmine\network\protocol\ServerHandshakePacket; use pocketmine\network\protocol\SetSpawnPositionPacket; use pocketmine\network\protocol\SetTimePacket; use pocketmine\network\protocol\StartGamePacket; +use pocketmine\network\protocol\TakeItemEntityPacket; use pocketmine\network\protocol\UnknownPacket; use pocketmine\network\protocol\UpdateBlockPacket; use pocketmine\network\raknet\Info; @@ -858,31 +860,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ } } break; - case "player.pickup": - if($data["eid"] === $this->id){ - $data["eid"] = 0; - $pk = new TakeItemEntityPacket; - $pk->eid = 0; - $pk->target = $data["entity"]->getID(); - $this->dataPacket($pk); - if(($this->gamemode & 0x01) === 0x00){ - //$this->addItem($data["entity"]->type, $data["entity"]->meta, $data["entity"]->stack); - } - switch($data["entity"]->type){ - case Item::WOOD: - $this->awardAchievement("mineWood"); - break; - case Item::DIAMOND: - $this->awardAchievement("diamond"); - break; - } - }elseif($data["entity"]->getLevel() === $this->getLevel()){ - $pk = new TakeItemEntityPacket; - $pk->eid = $data["eid"]; - $pk->target = $data["entity"]->getID(); - $this->dataPacket($pk); - } - break; case "entity.animate": if($data["eid"] === $this->id or $data["entity"]->getLevel() !== $this->getLevel()){ break; @@ -1212,6 +1189,48 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ } } + public function onUpdate(){ + if($this->spawned === false){ + return true; + } + $hasUpdate = $this->entityBaseTick(); + foreach($this->getNearbyEntities($this->boundingBox->expand(3, 3, 3)) as $entity){ + if($entity instanceof DroppedItem){ + if($entity->dead !== true and $entity->getPickupDelay() <= 0){ + $item = $entity->getItem(); + + if($item instanceof Item){ + if(($this->gamemode & 0x01) === 0 and !$this->inventory->canAddItem($item)){ + continue; + } + + switch($item->getID()){ + case Item::WOOD: + $this->awardAchievement("mineWood"); + break; + case Item::DIAMOND: + $this->awardAchievement("diamond"); + break; + } + $pk = new TakeItemEntityPacket; + $pk->eid = 0; + $pk->target = $entity->getID(); + $this->dataPacket($pk); + + $pk = new TakeItemEntityPacket; + $pk->eid = $this->getID(); + $pk->target = $entity->getID(); + $this->server->broadcastPacket($entity->getViewers(), $pk); + $this->inventory->addItem(clone $item); + $entity->kill(); + } + } + } + } + + $this->updateMovement(); + } + /** * Handles a Minecraft packet * TODO: Separate all of this in handlers @@ -1409,7 +1428,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ //$this->evid[] = $this->server->event("entity.animate", array($this, "eventHandler")); //$this->evid[] = $this->server->event("entity.event", array($this, "eventHandler")); //$this->evid[] = $this->server->event("entity.metadata", array($this, "eventHandler")); - //$this->evid[] = $this->server->event("player.pickup", array($this, "eventHandler")); //$this->evid[] = $this->server->event("tile.container.slot", array($this, "eventHandler")); //$this->evid[] = $this->server->event("tile.update", array($this, "eventHandler")); $this->lastMeasure = microtime(true); @@ -2001,7 +2019,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $this->craftingItems = []; } - if($packet->windowid === 0){ //Crafting! + if($packet->windowid == 0){ //Crafting! $craft = false; $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 @@ -2039,6 +2057,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ } $this->craftingItems = []; } + break; }else{ $this->toCraft = []; $this->craftingItems = []; diff --git a/src/pocketmine/entity/DroppedItem.php b/src/pocketmine/entity/DroppedItem.php index 84b49876a..7adc48cfa 100644 --- a/src/pocketmine/entity/DroppedItem.php +++ b/src/pocketmine/entity/DroppedItem.php @@ -62,12 +62,15 @@ class DroppedItem extends Entity{ if(isset($this->namedtag->Thrower)){ $this->thrower = $this->namedtag["Thrower"]; } - $this->item = Item::get($this->namedtag->Item["id"], $this->namedtag->Item["Damage"], min(64, $this->namedtag->Item["Count"])); + $this->item = Item::get($this->namedtag->Item["id"], $this->namedtag->Item["Damage"], $this->namedtag->Item["Count"]); } public function onUpdate(){ $this->entityBaseTick(); - //TODO: manage pickupDelay + + if($this->pickupDelay > 0 and $this->pickupDelay < 32767){ //Infinite delay + --$this->pickupDelay; + } $this->motionY -= $this->gravity; $this->inBlock = $this->checkObstruction($this->x, ($this->boundingBox->minY + $this->boundingBox->maxY) / 2, $this->z); @@ -94,10 +97,13 @@ class DroppedItem extends Entity{ $this->motionZ = 0; } - //TODO: update age in base entity tick - //TODO: kill entity if it's old enough + if($this->age > 6000){ + $this->kill(); + } $this->updateMovement(); - //$this->server->broadcastMessage("{$this->ticksLived}: ".round($this->x, 2).",".round($this->y, 2).",".round($this->z, 2)); + + //TODO: handle scheduled updates + return true; } public function attack($damage, $source = "generic"){ diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index db8bad40c..7b5ef5b4c 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -360,6 +360,11 @@ abstract class Entity extends Position implements Metadatable{ public function entityBaseTick(){ //TODO: check vehicles + if($this->dead === true){ + $this->close(); + return false; + } + $hasUpdate = false; $this->lastX = $this->x; $this->lastY = $this->y; @@ -600,7 +605,7 @@ abstract class Entity extends Position implements Metadatable{ $minX = ($bb->minX - 2) >> 4; $maxX = ($bb->maxX + 2) >> 4; $minZ = ($bb->minZ - 2) >> 4; - $maxZ = ($bb->maxX + 2) >> 4; + $maxZ = ($bb->maxZ + 2) >> 4; for($x = $minX; $x <= $maxX; ++$x){ for($z = $minZ; $z <= $maxZ; ++$z){ @@ -904,6 +909,7 @@ abstract class Entity extends Position implements Metadatable{ public function kill(){ $this->dead = true; + $this->scheduleUpdate(); } public function teleport(Vector3 $pos, $yaw = false, $pitch = false){ diff --git a/src/pocketmine/inventory/BaseInventory.php b/src/pocketmine/inventory/BaseInventory.php index 3c527bb1c..9408b9b13 100644 --- a/src/pocketmine/inventory/BaseInventory.php +++ b/src/pocketmine/inventory/BaseInventory.php @@ -202,25 +202,44 @@ abstract class BaseInventory implements Inventory{ return -1; } + public function canAddItem(Item $item){ + $item = clone $item; + $checkDamage = $item->getDamage() === null ? false : true; + for($i = 0; $i < $this->getSize(); ++$i){ + $slot = $this->getItem($i); + if($item->equals($slot, $checkDamage)){ + if(($diff = $slot->getMaxStackSize() - $slot->getCount()) > 0){ + $item->setCount($item->getCount() - $diff); + } + }elseif($slot->getID() === Item::AIR){ + $item->setCount($item->getCount() - $this->getMaxStackSize()); + } + + if($item->getCount() <= 0){ + return true; + } + } + return false; + } + public function addItem(){ /** @var Item[] $slots */ $slots = func_get_args(); foreach($slots as $i => $slot){ - if($slot->getCount() > $slot->getMaxStackSize()){ - while($slot->getCount() > $slot->getMaxStackSize()){ - $slots[] = Item::get($slot->getID(), $slot->getDamage(), $slot->getMaxStackSize()); - $slot->setCount($slot->getCount() - $slot->getMaxStackSize()); - if(count($slots) > $this->getSize()){ //Protect against large give commands - break; - } + while($slot->getCount() > $slot->getMaxStackSize()){ + $slots[] = Item::get($slot->getID(), $slot->getDamage(), $slot->getMaxStackSize()); + $slot->setCount($slot->getCount() - $slot->getMaxStackSize()); + if(count($slots) > $this->getSize()){ //Protect against large give commands + break; } } } - for($i = 0; $i < $this->size; ++$i){ + + for($i = 0; $i < $this->getSize(); ++$i){ $item = $this->getItem($i); if($item->getID() === Item::AIR){ - $item = array_shift($slots); - $this->setItem($i, $item); + $this->setItem($i, array_shift($slots)); + $item = $this->getItem($i); } foreach($slots as $index => $slot){ @@ -242,14 +261,13 @@ abstract class BaseInventory implements Inventory{ break; } } - return $slots; } public function removeItem(){ /** @var Item[] $slots */ $slots = func_get_args(); - for($i = 0; $i < $this->size; ++$i){ + for($i = 0; $i < $this->getSize(); ++$i){ $item = $this->getItem($i); if($item->getID() === Item::AIR){ continue; diff --git a/src/pocketmine/inventory/Inventory.php b/src/pocketmine/inventory/Inventory.php index 69819acfc..3bdd02815 100644 --- a/src/pocketmine/inventory/Inventory.php +++ b/src/pocketmine/inventory/Inventory.php @@ -62,7 +62,7 @@ interface Inventory{ public function setItem($index, Item $item); /** - * Stores the given Item in the inventory. This will try to fill + * Stores the given Items in the inventory. This will try to fill * existing stacks and empty slots as well as it can. * * Returns the Items that did not fit @@ -73,6 +73,15 @@ interface Inventory{ */ public function addItem(); + /** + * Checks if a given Item can be added to the inventory + * + * @param Item $item + * + * @return bool + */ + public function canAddItem(Item $item); + /** * Removes the given Item from the inventory. * It will return the Items that couldn't be removed. diff --git a/src/pocketmine/inventory/PlayerInventory.php b/src/pocketmine/inventory/PlayerInventory.php index 9c27505c2..0bc539c0c 100644 --- a/src/pocketmine/inventory/PlayerInventory.php +++ b/src/pocketmine/inventory/PlayerInventory.php @@ -114,10 +114,6 @@ class PlayerInventory extends BaseInventory{ $this->setHotbarSlotIndex($this->itemInHandIndex, $slot); $this->sendHeldItem($this->getHolder()->getViewers()); - - if($this->getHolder() instanceof Player){ - $this->sendHeldItem($this->getHolder()); - } } } diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index eddd3351f..97b44f3e8 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -705,7 +705,9 @@ class Level{ "Damage" => new Short("Damage", $item->getDamage()), "Count" => new Byte("Count", $item->getCount()) ]), + "PickupDelay" => new Short("PickupDelay", 10) ])); + $itemEntity->spawnToAll(); } } @@ -764,7 +766,9 @@ class Level{ if(!($player instanceof Player) or ($player->getGamemode() & 0x01) === 0){ foreach($target->getDrops($item) as $drop){ - $this->dropItem($vector->add(0.5, 0.5, 0.5), Item::get($drop[0], $drop[1], $drop[2]), 5); + if($drop[2] > 0){ + $this->dropItem($vector->add(0.5, 0.5, 0.5), Item::get($drop[0], $drop[1], $drop[2]), 1); + } } } return true;