From 7fd053fb09dad829cb309f4be9b9566960257be9 Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Mon, 3 Aug 2015 18:04:13 +0200 Subject: [PATCH] More changes! Alsp added Anvil block and BinaryStream --- src/pocketmine/Player.php | 7 +- src/pocketmine/block/Anvil.php | 86 ++++++++ src/pocketmine/block/Block.php | 3 + src/pocketmine/inventory/AnvilInventory.php | 48 ++++ src/pocketmine/inventory/InventoryType.php | 8 +- src/pocketmine/item/Item.php | 7 + src/pocketmine/level/format/anvil/Anvil.php | 3 + .../level/format/leveldb/LevelDB.php | 2 + .../level/format/mcregion/McRegion.php | 3 +- .../network/protocol/CraftingDataPacket.php | 79 ++++--- .../network/protocol/DataPacket.php | 169 +------------- src/pocketmine/network/protocol/Info.php | 2 +- src/pocketmine/utils/BinaryStream.php | 207 ++++++++++++++++++ 13 files changed, 422 insertions(+), 202 deletions(-) create mode 100644 src/pocketmine/block/Anvil.php create mode 100644 src/pocketmine/inventory/AnvilInventory.php create mode 100644 src/pocketmine/utils/BinaryStream.php diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index e4356396b..bdd7290e7 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -1910,8 +1910,11 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $packet->slot -= 9; //Get real block slot } + /** @var Item $item */ + $item = null; + if($this->isCreative()){ //Creative mode match - $item = Item::get($packet->item, $packet->meta, 1); + $item = $packet->item; $slot = Item::getCreativeItemIndex($item); }else{ $item = $this->inventory->getItem($packet->slot); @@ -1942,7 +1945,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade break; } } - }elseif(!isset($item) or $slot === -1 or $item->getId() !== $packet->item or $item->getDamage() !== $packet->meta){ // packet error or not implemented + }elseif($item === null or $slot === -1 or $item->equals($packet->item, true)){ // packet error or not implemented $this->inventory->sendContents($this); break; }elseif($this->isCreative()){ diff --git a/src/pocketmine/block/Anvil.php b/src/pocketmine/block/Anvil.php new file mode 100644 index 000000000..30db5c841 --- /dev/null +++ b/src/pocketmine/block/Anvil.php @@ -0,0 +1,86 @@ +meta = $meta; + } + + public function canBeActivated(){ + return true; + } + + public function getHardness(){ + return 5; + } + + public function getResistance(){ + return 6000; + } + + public function getName(){ + return "Anvil"; + } + + public function getToolType(){ + return Tool::TYPE_PICKAXE; + } + + public function onActivate(Item $item, Player $player = null){ + if($player instanceof Player){ + if($player->isCreative()){ + return true; + } + + $player->addWindow(new AnvilInventory($this)); + } + + return true; + } + + public function getDrops(Item $item){ + return [ + [$this->id, 0, 1], + ]; + } +} \ No newline at end of file diff --git a/src/pocketmine/block/Block.php b/src/pocketmine/block/Block.php index a36c35256..4d3bfda3c 100644 --- a/src/pocketmine/block/Block.php +++ b/src/pocketmine/block/Block.php @@ -206,6 +206,8 @@ class Block extends Position implements Metadatable{ const CARROT_BLOCK = 141; const POTATO_BLOCK = 142; + const ANVIL = 145; + const REDSTONE_BLOCK = 152; const QUARTZ_BLOCK = 155; @@ -424,6 +426,7 @@ class Block extends Position implements Metadatable{ self::$list[self::CARROT_BLOCK] = Carrot::class; self::$list[self::POTATO_BLOCK] = Potato::class; + self::$list[self::ANVIL] = Anvil::class; self::$list[self::REDSTONE_BLOCK] = Redstone::class; diff --git a/src/pocketmine/inventory/AnvilInventory.php b/src/pocketmine/inventory/AnvilInventory.php new file mode 100644 index 000000000..25e88624d --- /dev/null +++ b/src/pocketmine/inventory/AnvilInventory.php @@ -0,0 +1,48 @@ +holder; + } +} \ No newline at end of file diff --git a/src/pocketmine/inventory/InventoryType.php b/src/pocketmine/inventory/InventoryType.php index b149b680f..db9f2a99d 100644 --- a/src/pocketmine/inventory/InventoryType.php +++ b/src/pocketmine/inventory/InventoryType.php @@ -32,6 +32,9 @@ class InventoryType{ const CRAFTING = 4; const WORKBENCH = 5; const STONECUTTER = 6; + const BREWING_STAND = 7; + const ANVIL = 8; + const ENCHANT_TABLE = 9; private static $default = []; @@ -59,7 +62,10 @@ class InventoryType{ static::$default[static::FURNACE] = new InventoryType(3, "Furnace", 2); static::$default[static::CRAFTING] = new InventoryType(5, "Crafting", 1); //4 CRAFTING slots, 1 RESULT static::$default[static::WORKBENCH] = new InventoryType(10, "Crafting", 1); //9 CRAFTING slots, 1 RESULT - static::$default[static::STONECUTTER] = new InventoryType(10, "Crafting", 3); //9 CRAFTING slots, 1 RESULT + static::$default[static::STONECUTTER] = new InventoryType(10, "Crafting", 1); //9 CRAFTING slots, 1 RESULT + static::$default[static::ENCHANT_TABLE] = new InventoryType(1, "Enchant", 4); //1 INPUT/OUTPUT + static::$default[static::BREWING_STAND] = new InventoryType(4, "Brewing", 5); //1 INPUT, 3 POTION + static::$default[static::ANVIL] = new InventoryType(3, "Brewing", 6); //2 INPUT, 1 OUTPUT } /** diff --git a/src/pocketmine/item/Item.php b/src/pocketmine/item/Item.php index 38b0120fb..70a7d6735 100644 --- a/src/pocketmine/item/Item.php +++ b/src/pocketmine/item/Item.php @@ -200,6 +200,8 @@ class Item{ const CARROT_BLOCK = 141; const POTATO_BLOCK = 142; + const ANVIL = 145; + const REDSTONE_BLOCK = 152; const QUARTZ_BLOCK = 155; @@ -727,6 +729,11 @@ class Item{ self::addCreativeItem(Item::get(Item::CARPET, 9)); self::addCreativeItem(Item::get(Item::CARPET, 8)); + + self::addCreativeItem(Item::get(Item::ANVIL, 0)); + self::addCreativeItem(Item::get(Item::ANVIL, 4)); + self::addCreativeItem(Item::get(Item::ANVIL, 8)); + //Tools //TODO self::addCreativeItem(Item::get(Item::RAILS, 0)); //TODO self::addCreativeItem(Item::get(Item::POWERED_RAILS, 0)); diff --git a/src/pocketmine/level/format/anvil/Anvil.php b/src/pocketmine/level/format/anvil/Anvil.php index 13c642f69..0f7bb20c2 100644 --- a/src/pocketmine/level/format/anvil/Anvil.php +++ b/src/pocketmine/level/format/anvil/Anvil.php @@ -31,6 +31,7 @@ use pocketmine\nbt\tag\Compound; use pocketmine\network\protocol\FullChunkDataPacket; use pocketmine\tile\Spawnable; use pocketmine\utils\ChunkException; +use raklib\Binary; class Anvil extends McRegion{ @@ -94,6 +95,8 @@ class Anvil extends McRegion{ $chunk->getBlockLightArray() . pack("C*", ...$chunk->getHeightMapArray()) . pack("N*", ...$chunk->getBiomeColorArray()) . + //TODO extra data + Binary::writeInt(0) . $tiles; $this->getLevel()->chunkRequestCallback($x, $z, $ordered, FullChunkDataPacket::ORDER_LAYERED); diff --git a/src/pocketmine/level/format/leveldb/LevelDB.php b/src/pocketmine/level/format/leveldb/LevelDB.php index 3407606de..e2bbb3f41 100644 --- a/src/pocketmine/level/format/leveldb/LevelDB.php +++ b/src/pocketmine/level/format/leveldb/LevelDB.php @@ -162,6 +162,8 @@ class LevelDB extends BaseLevelProvider{ $chunk->getBlockLightArray() . $heightmap . $biomeColors . + //TODO extra data + Binary::writeInt(0) . $tiles; $this->getLevel()->chunkRequestCallback($x, $z, $ordered); diff --git a/src/pocketmine/level/format/mcregion/McRegion.php b/src/pocketmine/level/format/mcregion/McRegion.php index 68273c790..68abe171b 100644 --- a/src/pocketmine/level/format/mcregion/McRegion.php +++ b/src/pocketmine/level/format/mcregion/McRegion.php @@ -31,7 +31,6 @@ use pocketmine\nbt\tag\Compound; use pocketmine\nbt\tag\Int; use pocketmine\nbt\tag\Long; use pocketmine\nbt\tag\String; -use pocketmine\network\protocol\FullChunkDataPacket; use pocketmine\tile\Spawnable; use pocketmine\utils\Binary; use pocketmine\utils\ChunkException; @@ -139,6 +138,8 @@ class McRegion extends BaseLevelProvider{ $chunk->getBlockLightArray() . pack("C*", ...$chunk->getHeightMapArray()) . pack("N*", ...$chunk->getBiomeColorArray()) . + //TODO extra data + Binary::writeInt(0) . $tiles; $this->getLevel()->chunkRequestCallback($x, $z, $ordered); diff --git a/src/pocketmine/network/protocol/CraftingDataPacket.php b/src/pocketmine/network/protocol/CraftingDataPacket.php index c983f5efa..9f71e0484 100644 --- a/src/pocketmine/network/protocol/CraftingDataPacket.php +++ b/src/pocketmine/network/protocol/CraftingDataPacket.php @@ -28,6 +28,7 @@ use pocketmine\inventory\FurnaceRecipe; use pocketmine\inventory\ShapedRecipe; use pocketmine\inventory\ShapelessRecipe; use pocketmine\utils\Binary; +use pocketmine\utils\BinaryStream; class CraftingDataPacket extends DataPacket{ const NETWORK_ID = Info::CRAFTING_DATA_PACKET; @@ -42,47 +43,53 @@ class CraftingDataPacket extends DataPacket{ public $entries = []; public $cleanRecipes = false; - public function writeEntry($entry){ + private static function writeEntry($entry, BinaryStream $stream){ if($entry instanceof ShapelessRecipe){ - $this->writeShapelessRecipe($entry); + return self::writeShapelessRecipe($entry, $stream); }elseif($entry instanceof ShapedRecipe){ - $this->writeShapedRecipe($entry); + return self::writeShapedRecipe($entry, $stream); }elseif($entry instanceof FurnaceRecipe){ - $this->writeFurnaceRecipe($entry); + return self::writeFurnaceRecipe($entry, $stream); } + + return -1; } - private function writeShapelessRecipe(ShapelessRecipe $recipe){ - $this->putInt(CraftingDataPacket::ENTRY_SHAPELESS); - - $this->putInt($recipe->getIngredientCount()); + private static function writeShapelessRecipe(ShapelessRecipe $recipe, BinaryStream $stream){ + $stream->putInt($recipe->getIngredientCount()); foreach($recipe->getIngredientList() as $item){ - $this->putSlot($item); + $stream->putSlot($item); } - $this->putInt(1); - $this->putSlot($recipe->getResult()); + $stream->putInt(1); + $stream->putSlot($recipe->getResult()); + + return CraftingDataPacket::ENTRY_SHAPELESS; } - private function writeShapedRecipe(ShapedRecipe $recipe){ - $this->putInt(CraftingDataPacket::ENTRY_SHAPED); - } - - private function writeFurnaceRecipe(FurnaceRecipe $recipe){ - if($recipe->getInput()->getDamage() !== 0){ //Data recipe - $this->putInt(CraftingDataPacket::ENTRY_FURNACE_DATA); - $this->putInt(($recipe->getInput()->getId() << 16) | ($recipe->getInput()->getDamage())); - $this->putSlot($recipe->getResult()); - }else{ - $this->putInt(CraftingDataPacket::ENTRY_FURNACE); - $this->putInt($recipe->getInput()->getId()); - $this->putSlot($recipe->getResult()); - } - } - - private function writeEnchant(){ - $entry = Binary::writeInt(CraftingDataPacket::ENTRY_ENCHANT); + private static function writeShapedRecipe(ShapedRecipe $recipe, BinaryStream $stream){ //TODO + return CraftingDataPacket::ENTRY_SHAPED; + } + + private static function writeFurnaceRecipe(FurnaceRecipe $recipe, BinaryStream $stream){ + if($recipe->getInput()->getDamage() !== 0){ //Data recipe + $stream->putInt(($recipe->getInput()->getId() << 16) | ($recipe->getInput()->getDamage())); + $stream->putSlot($recipe->getResult()); + + return CraftingDataPacket::ENTRY_FURNACE_DATA; + }else{ + $stream->putInt($recipe->getInput()->getId()); + $stream->putSlot($recipe->getResult()); + + return CraftingDataPacket::ENTRY_FURNACE; + } + } + + private static function writeEnchant(){ + //TODO + + return CraftingDataPacket::ENTRY_ENCHANT; } public function addShapelessRecipe(ShapelessRecipe $recipe){ @@ -113,8 +120,20 @@ class CraftingDataPacket extends DataPacket{ public function encode(){ $this->reset(); $this->putInt(count($this->entries)); + + $writer = new BinaryStream(); foreach($this->entries as $d){ - $this->writeEntry($d); + $entryType = self::writeEntry($d, $writer); + if($entryType >= 0){ + $this->putInt($entryType); + $this->putInt(strlen($writer->getBuffer())); + $this->put($writer->getBuffer()); + }else{ + $this->putInt(-1); + $this->putInt(0); + } + + $writer->reset(); } $this->putByte($this->cleanRecipes ? 1 : 0); diff --git a/src/pocketmine/network/protocol/DataPacket.php b/src/pocketmine/network/protocol/DataPacket.php index eb98dbf7e..a0112b33d 100644 --- a/src/pocketmine/network/protocol/DataPacket.php +++ b/src/pocketmine/network/protocol/DataPacket.php @@ -28,16 +28,15 @@ use pocketmine\utils\Binary; #endif use pocketmine\item\Item; +use pocketmine\utils\BinaryStream; use pocketmine\utils\Utils; use pocketmine\utils\UUID; -abstract class DataPacket extends \stdClass{ +abstract class DataPacket extends BinaryStream{ const NETWORK_ID = 0; - public $offset = 0; - public $buffer = ""; public $isEncoded = false; private $channel = 0; @@ -63,170 +62,6 @@ abstract class DataPacket extends \stdClass{ return $this->channel; } - public function setBuffer($buffer = null, $offset = 0){ - $this->buffer = $buffer; - $this->offset = (int) $offset; - } - - public function getOffset(){ - return $this->offset; - } - - public function getBuffer(){ - return $this->buffer; - } - - protected function get($len){ - if($len < 0){ - $this->offset = strlen($this->buffer) - 1; - return ""; - }elseif($len === true){ - return substr($this->buffer, $this->offset); - } - - return $len === 1 ? $this->buffer{$this->offset++} : substr($this->buffer, ($this->offset += $len) - $len, $len); - } - - protected function put($str){ - $this->buffer .= $str; - } - - protected function getLong(){ - return Binary::readLong($this->get(8)); - } - - protected function putLong($v){ - $this->buffer .= Binary::writeLong($v); - } - - protected function getInt(){ - return Binary::readInt($this->get(4)); - } - - protected function putInt($v){ - $this->buffer .= Binary::writeInt($v); - } - - protected function getShort($signed = true){ - return $signed ? Binary::readSignedShort($this->get(2)) : Binary::readShort($this->get(2)); - } - - protected function putShort($v){ - $this->buffer .= Binary::writeShort($v); - } - - protected function getFloat(){ - return Binary::readFloat($this->get(4)); - } - - protected function putFloat($v){ - $this->buffer .= Binary::writeFloat($v); - } - - protected function getTriad(){ - return Binary::readTriad($this->get(3)); - } - - protected function putTriad($v){ - $this->buffer .= Binary::writeTriad($v); - } - - - protected function getLTriad(){ - return Binary::readLTriad($this->get(3)); - } - - protected function putLTriad($v){ - $this->buffer .= Binary::writeLTriad($v); - } - - protected function getByte(){ - return ord($this->buffer{$this->offset++}); - } - - protected function putByte($v){ - $this->buffer .= chr($v); - } - - protected function getDataArray($len = 10){ - $data = []; - for($i = 1; $i <= $len and !$this->feof(); ++$i){ - $data[] = $this->get($this->getTriad()); - } - - return $data; - } - - protected function putDataArray(array $data = []){ - foreach($data as $v){ - $this->putTriad(strlen($v)); - $this->put($v); - } - } - - protected function getUUID(){ - return UUID::fromBinary($this->get(16)); - } - - protected function putUUID(UUID $uuid){ - $this->put($uuid->toBinary()); - } - - protected function getSlot(){ - $id = $this->getShort(true); - - if($id <= 0){ - return Item::get(0, 0, 0); - } - - $cnt = $this->getByte(); - - $data = $this->getShort(); - - $nbtLen = $this->getShort(); - - $nbt = ""; - - if($nbtLen > 0){ - $nbt = $this->get($nbtLen); - } - - return Item::get( - $id, - $data, - $cnt, - $nbt - ); - } - - protected function putSlot(Item $item){ - if($item->getId() === 0){ - $this->putShort(0); - return; - } - - $this->putShort($item->getId()); - $this->putByte($item->getCount()); - $this->putShort($item->getDamage()); - $nbt = $item->getCompoundTag(); - $this->putShort(strlen($nbt)); - $this->put($nbt); - - } - - protected function getString(){ - return $this->get($this->getShort()); - } - - protected function putString($v){ - $this->putShort(strlen($v)); - $this->put($v); - } - - protected function feof(){ - return !isset($this->buffer{$this->offset}); - } - public function clean(){ $this->buffer = null; $this->isEncoded = false; diff --git a/src/pocketmine/network/protocol/Info.php b/src/pocketmine/network/protocol/Info.php index ba55bf73d..675350525 100644 --- a/src/pocketmine/network/protocol/Info.php +++ b/src/pocketmine/network/protocol/Info.php @@ -30,7 +30,7 @@ interface Info{ /** * Actual Minecraft: PE protocol version */ - const CURRENT_PROTOCOL = 30; + const CURRENT_PROTOCOL = 31; const LOGIN_PACKET = 0x87; const PLAY_STATUS_PACKET = 0x88; diff --git a/src/pocketmine/utils/BinaryStream.php b/src/pocketmine/utils/BinaryStream.php new file mode 100644 index 000000000..8411afbe3 --- /dev/null +++ b/src/pocketmine/utils/BinaryStream.php @@ -0,0 +1,207 @@ + + +#ifndef COMPILE +use pocketmine\utils\Binary; +#endif + +use pocketmine\item\Item; +use pocketmine\utils\UUID; + + +class BinaryStream extends \stdClass{ + + public $offset = 0; + public $buffer = ""; + + protected function reset(){ + $this->buffer = ""; + $this->offset = 0; + } + + public function setBuffer($buffer = null, $offset = 0){ + $this->buffer = $buffer; + $this->offset = (int) $offset; + } + + public function getOffset(){ + return $this->offset; + } + + public function getBuffer(){ + return $this->buffer; + } + + protected function get($len){ + if($len < 0){ + $this->offset = strlen($this->buffer) - 1; + return ""; + }elseif($len === true){ + return substr($this->buffer, $this->offset); + } + + return $len === 1 ? $this->buffer{$this->offset++} : substr($this->buffer, ($this->offset += $len) - $len, $len); + } + + protected function put($str){ + $this->buffer .= $str; + } + + protected function getLong(){ + return Binary::readLong($this->get(8)); + } + + protected function putLong($v){ + $this->buffer .= Binary::writeLong($v); + } + + protected function getInt(){ + return Binary::readInt($this->get(4)); + } + + protected function putInt($v){ + $this->buffer .= Binary::writeInt($v); + } + + protected function getShort($signed = true){ + return $signed ? Binary::readSignedShort($this->get(2)) : Binary::readShort($this->get(2)); + } + + protected function putShort($v){ + $this->buffer .= Binary::writeShort($v); + } + + protected function getFloat(){ + return Binary::readFloat($this->get(4)); + } + + protected function putFloat($v){ + $this->buffer .= Binary::writeFloat($v); + } + + protected function getTriad(){ + return Binary::readTriad($this->get(3)); + } + + protected function putTriad($v){ + $this->buffer .= Binary::writeTriad($v); + } + + + protected function getLTriad(){ + return Binary::readLTriad($this->get(3)); + } + + protected function putLTriad($v){ + $this->buffer .= Binary::writeLTriad($v); + } + + protected function getByte(){ + return ord($this->buffer{$this->offset++}); + } + + protected function putByte($v){ + $this->buffer .= chr($v); + } + + protected function getDataArray($len = 10){ + $data = []; + for($i = 1; $i <= $len and !$this->feof(); ++$i){ + $data[] = $this->get($this->getTriad()); + } + + return $data; + } + + protected function putDataArray(array $data = []){ + foreach($data as $v){ + $this->putTriad(strlen($v)); + $this->put($v); + } + } + + protected function getUUID(){ + return UUID::fromBinary($this->get(16)); + } + + protected function putUUID(UUID $uuid){ + $this->put($uuid->toBinary()); + } + + protected function getSlot(){ + $id = $this->getShort(true); + + if($id <= 0){ + return Item::get(0, 0, 0); + } + + $cnt = $this->getByte(); + + $data = $this->getShort(); + + $nbtLen = $this->getShort(); + + $nbt = ""; + + if($nbtLen > 0){ + $nbt = $this->get($nbtLen); + } + + return Item::get( + $id, + $data, + $cnt, + $nbt + ); + } + + protected function putSlot(Item $item){ + if($item->getId() === 0){ + $this->putShort(0); + return; + } + + $this->putShort($item->getId()); + $this->putByte($item->getCount()); + $this->putShort($item->getDamage() === null ? -1 : $item->getDamage()); + $nbt = $item->getCompoundTag(); + $this->putShort(strlen($nbt)); + $this->put($nbt); + + } + + protected function getString(){ + return $this->get($this->getShort()); + } + + protected function putString($v){ + $this->putShort(strlen($v)); + $this->put($v); + } + + protected function feof(){ + return !isset($this->buffer{$this->offset}); + } +}