public function saveMacro($name, Macro $macro)
 {
     $tag = new tag\Compound();
     $tag["author"] = new tag\String("author", $macro->getAuthor());
     $tag["description"] = new tag\String("description", $macro->getDescription());
     $tag["ops"] = new tag\Enum("ops");
     foreach ($macro->getOperations() as $i => $log) {
         $tag["ops"][$i] = $log->toTag();
     }
     $nbt = new NBT();
     $nbt->setData($tag);
     $file = $this->getFile($name);
     $stream = fopen($file, "wb");
     if (!is_resource($stream)) {
         throw new \RuntimeException("Unable to open stream. Maybe the macro name is not a valid filename?");
     }
     $compression = $this->getMain()->getConfig()->getAll()["data providers"]["macro"]["mcr"]["compression"];
     if ($compression === 0) {
         $data = $nbt->write();
     } else {
         $data = $nbt->writeCompressed($compression);
     }
     fwrite($stream, chr($compression) . $data);
     fclose($stream);
 }
Пример #2
0
 public function generateChunk($x, $z)
 {
     $nbt = new Compound("Level", []);
     $nbt->xPos = new Int("xPos", $this->getX() * 32 + $x);
     $nbt->zPos = new Int("zPos", $this->getZ() * 32 + $z);
     $nbt->LastUpdate = new Long("LastUpdate", 0);
     $nbt->LightPopulated = new Byte("LightPopulated", 0);
     $nbt->TerrainPopulated = new Byte("TerrainPopulated", 0);
     $nbt->V = new Byte("V", self::VERSION);
     $nbt->InhabitedTime = new Long("InhabitedTime", 0);
     $biomes = str_repeat(Binary::writeByte(-1), 256);
     $nbt->Biomes = new ByteArray("Biomes", $biomes);
     $nbt->BiomeColors = new IntArray("BiomeColors", array_fill(0, 156, Binary::readInt("…²J")));
     $nbt->HeightMap = new IntArray("HeightMap", array_fill(0, 256, 127));
     $nbt->Sections = new Enum("Sections", []);
     $nbt->Sections->setTagType(NBT::TAG_Compound);
     $nbt->Entities = new Enum("Entities", []);
     $nbt->Entities->setTagType(NBT::TAG_Compound);
     $nbt->TileEntities = new Enum("TileEntities", []);
     $nbt->TileEntities->setTagType(NBT::TAG_Compound);
     $nbt->TileTicks = new Enum("TileTicks", []);
     $nbt->TileTicks->setTagType(NBT::TAG_Compound);
     $writer = new NBT(NBT::BIG_ENDIAN);
     $nbt->setName("Level");
     $writer->setData(new Compound("", ["Level" => $nbt]));
     $chunkData = $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL);
     $this->saveChunk($x, $z, $chunkData);
 }
Пример #3
0
 public function requestChunkTask($x, $z)
 {
     $chunk = $this->getChunk($x, $z, false);
     if (!$chunk instanceof Chunk) {
         throw new ChunkException("Invalid Chunk sent");
     }
     $tiles = "";
     if (count($chunk->getTiles()) > 0) {
         $nbt = new NBT(NBT::LITTLE_ENDIAN);
         $list = [];
         foreach ($chunk->getTiles() as $tile) {
             if ($tile instanceof Spawnable) {
                 $list[] = $tile->getSpawnCompound();
             }
         }
         $nbt->setData($list);
         $tiles = $nbt->write(true);
     }
     $extraData = new BinaryStream();
     $extraData->putLInt(count($chunk->getBlockExtraDataArray()));
     foreach ($chunk->getBlockExtraDataArray() as $key => $value) {
         $extraData->putLInt($key);
         $extraData->putLShort($value);
     }
     $ordered = $chunk->getBlockIdArray() . $chunk->getBlockDataArray() . $chunk->getBlockSkyLightArray() . $chunk->getBlockLightArray() . pack("C*", ...$chunk->getHeightMapArray()) . pack("N*", ...$chunk->getBiomeColorArray()) . $extraData->getBuffer() . $tiles;
     $this->getLevel()->chunkRequestCallback($x, $z, $ordered, FullChunkDataPacket::ORDER_LAYERED);
     return null;
 }
Пример #4
0
 public function write(NBT $nbt, bool $network = false)
 {
     foreach ($this as $tag) {
         if ($tag instanceof Tag and !$tag instanceof EndTag) {
             $nbt->writeTag($tag, $network);
         }
     }
     $nbt->writeTag(new EndTag(), $network);
 }
Пример #5
0
 public function write(NBT $nbt)
 {
     foreach ($this as $tag) {
         if ($tag instanceof Tag and !$tag instanceof End) {
             $nbt->writeTag($tag);
         }
     }
     $nbt->writeTag(new End());
 }
 /**
  *
  * @param string $name        	
  *
  * @return CompoundTag
  */
 public function getOfflinePlayerData($name)
 {
     $name = strtolower($name);
     $path = $this->datapath . "players/";
     if (file_exists($path . "{$name}.dat")) {
         try {
             $nbt = new NBT(NBT::BIG_ENDIAN);
             $nbt->readCompressed(file_get_contents($path . "{$name}.dat"));
             return $nbt->getData();
         } catch (\Throwable $e) {
             // zlib decode error / corrupt data
             rename($path . "{$name}.dat", $path . "{$name}.dat.bak");
         }
     }
     $spawn = explode(':', $this->spawn);
     $nbt = new CompoundTag("", [new LongTag("firstPlayed", floor(microtime(true) * 1000)), new LongTag("lastPlayed", floor(microtime(true) * 1000)), new ListTag("Pos", [new DoubleTag(0, $spawn[0]), new DoubleTag(1, $spawn[1]), new DoubleTag(2, $spawn[2])]), new StringTag("Level", $spawn[3]), new ListTag("Inventory", []), new CompoundTag("Achievements", []), new IntTag("playerGameType", $this->gamemode), new ListTag("Motion", [new DoubleTag(0, 0.0), new DoubleTag(1, 0.0), new DoubleTag(2, 0.0)]), new ListTag("Rotation", [new FloatTag(0, 0.0), new FloatTag(1, 0.0)]), new FloatTag("FallDistance", 0.0), new ShortTag("Fire", 0), new ShortTag("Air", 300), new ByteTag("OnGround", 1), new ByteTag("Invulnerable", 0), new StringTag("NameTag", $name)]);
     $nbt->Pos->setTagType(NBT::TAG_Double);
     $nbt->Inventory->setTagType(NBT::TAG_Compound);
     $nbt->Motion->setTagType(NBT::TAG_Double);
     $nbt->Rotation->setTagType(NBT::TAG_Float);
     if (file_exists($path . "{$name}.yml")) {
         // Importing old PocketMine-MP files
         $data = new Config($path . "{$name}.yml", Config::YAML, []);
         $nbt["playerGameType"] = (int) $data->get("gamemode");
         $nbt["Level"] = $data->get("position")["level"];
         $nbt["Pos"][0] = $data->get("position")["x"];
         $nbt["Pos"][1] = $data->get("position")["y"];
         $nbt["Pos"][2] = $data->get("position")["z"];
         $nbt["SpawnLevel"] = $data->get("spawn")["level"];
         $nbt["SpawnX"] = (int) $data->get("spawn")["x"];
         $nbt["SpawnY"] = (int) $data->get("spawn")["y"];
         $nbt["SpawnZ"] = (int) $data->get("spawn")["z"];
         foreach ($data->get("inventory") as $slot => $item) {
             if (count($item) === 3) {
                 $nbt->Inventory[$slot + 9] = new CompoundTag("", [new ShortTag("id", $item[0]), new ShortTag("Damage", $item[1]), new ByteTag("Count", $item[2]), new ByteTag("Slot", $slot + 9), new ByteTag("TrueSlot", $slot + 9)]);
             }
         }
         foreach ($data->get("hotbar") as $slot => $itemSlot) {
             if (isset($nbt->Inventory[$itemSlot + 9])) {
                 $item = $nbt->Inventory[$itemSlot + 9];
                 $nbt->Inventory[$slot] = new CompoundTag("", [new ShortTag("id", $item["id"]), new ShortTag("Damage", $item["Damage"]), new ByteTag("Count", $item["Count"]), new ByteTag("Slot", $slot), new ByteTag("TrueSlot", $item["TrueSlot"])]);
             }
         }
         foreach ($data->get("armor") as $slot => $item) {
             if (count($item) === 2) {
                 $nbt->Inventory[$slot + 100] = new CompoundTag("", [new ShortTag("id", $item[0]), new ShortTag("Damage", $item[1]), new ByteTag("Count", 1), new ByteTag("Slot", $slot + 100)]);
             }
         }
         foreach ($data->get("achievements") as $achievement => $status) {
             $nbt->Achievements[$achievement] = new ByteTag($achievement, $status == true ? 1 : 0);
         }
         unlink($path . "{$name}.yml");
     }
     return $nbt;
 }
Пример #7
0
 public function spawnTo(Player $player)
 {
     if ($this->closed) {
         return \false;
     }
     $nbt = new NBT(NBT::LITTLE_ENDIAN);
     $nbt->setData($this->getSpawnCompound());
     $pk = new TileEntityDataPacket();
     $pk->x = $this->x;
     $pk->y = $this->y;
     $pk->z = $this->z;
     $pk->namedtag = $nbt->write();
     $player->dataPacket($pk->setChannel(Network::CHANNEL_WORLD_EVENTS));
     return \true;
 }
Пример #8
0
 public function spawnTo(Player $player)
 {
     if ($this->closed) {
         return false;
     }
     $nbt = new NBT(NBT::LITTLE_ENDIAN);
     $nbt->setData($this->getSpawnCompound());
     $pk = new TileEntityDataPacket();
     $pk->x = $this->x;
     $pk->y = $this->y;
     $pk->z = $this->z;
     $pk->namedtag = $nbt->write();
     $player->dataPacket($pk);
     return true;
 }
Пример #9
0
 public function __construct(Human $player, $contents = null)
 {
     $this->hotbar = range(0, $this->getHotbarSize() - 1, 1);
     parent::__construct($player, InventoryType::get(InventoryType::PLAYER));
     if ($contents !== null) {
         if ($contents instanceof ListTag) {
             //Saved data to be loaded into the inventory
             foreach ($contents as $item) {
                 if ($item["Slot"] >= 0 and $item["Slot"] < $this->getHotbarSize()) {
                     //Hotbar
                     if (isset($item["TrueSlot"])) {
                         //Valid slot was found, change the linkage to this slot
                         if (0 <= $item["TrueSlot"] and $item["TrueSlot"] < $this->getSize()) {
                             $this->hotbar[$item["Slot"]] = $item["TrueSlot"];
                         } elseif ($item["TrueSlot"] < 0) {
                             //Link to an empty slot (empty hand)
                             $this->hotbar[$item["Slot"]] = -1;
                         }
                     }
                     /* If TrueSlot is not set, leave the slot index as its default which was filled in above
                      * This only overwrites slot indexes for valid links */
                 } elseif ($item["Slot"] >= 100 and $item["Slot"] < 104) {
                     //Armor
                     $this->setItem($this->getSize() + $item["Slot"] - 100, NBT::getItemHelper($item), false);
                 } else {
                     $this->setItem($item["Slot"] - $this->getHotbarSize(), NBT::getItemHelper($item), false);
                 }
             }
         } else {
             throw new \InvalidArgumentException("Expecting ListTag, received " . gettype($contents));
         }
     }
 }
Пример #10
0
 public function __construct(Level $level, Chunk $chunk)
 {
     $this->levelId = $level->getId();
     $this->chunk = $chunk->toFastBinary();
     $this->chunkX = $chunk->getX();
     $this->chunkZ = $chunk->getZ();
     $tiles = "";
     $nbt = new NBT(NBT::LITTLE_ENDIAN);
     foreach ($chunk->getTiles() as $tile) {
         if ($tile instanceof Spawnable) {
             $nbt->setData($tile->getSpawnCompound());
             $tiles .= $nbt->write();
         }
     }
     $this->tiles = $tiles;
 }
Пример #11
0
 public function setItem(Item $item, bool $setChanged = true)
 {
     $nbtItem = NBT::putItemHelper($item);
     $nbtItem->setName("Item");
     $this->namedtag->Item = $nbtItem;
     if ($setChanged) {
         $this->setChanged();
     }
 }
Пример #12
0
 /**
  * Return the defined game rules as NBT.
  */
 public function writeToNBT()
 {
     $compoundarray = [];
     foreach ($this->theGameRules as $key => $value) {
         $compoundarray[] = NBT::fromArrayGuesser($key, $value);
     }
     $nbttagcompound = new CompoundTag("GameRules", $compoundarray);
     return $nbttagcompound;
 }
Пример #13
0
 public function setItem(Item $item)
 {
     $tag = NBT::putItemHelper($item);
     $tag->setName("Item");
     $this->namedtag->Item = $tag;
     $this->spawnToAll();
     if ($this->chunk) {
         $this->chunk->setChanged();
         $this->level->clearChunkCache($this->chunk->getX(), $this->chunk->getZ());
     }
 }
Пример #14
0
 public function __construct(Anvil $level, $levelId, $chunkX, $chunkZ)
 {
     $this->levelId = $levelId;
     $this->chunkX = $chunkX;
     $this->chunkZ = $chunkZ;
     $chunk = $level->getChunk($chunkX, $chunkZ, false);
     if (!$chunk instanceof Chunk) {
         throw new ChunkException("Invalid Chunk sent");
     }
     $this->biomeIds = $chunk->getBiomeIdArray();
     $this->biomeColors = $chunk->getBiomeColorArray();
     $this->sections = $chunk->getSections();
     $tiles = "";
     $nbt = new NBT(NBT::LITTLE_ENDIAN);
     foreach ($chunk->getTiles() as $tile) {
         if ($tile instanceof Spawnable) {
             $nbt->setData($tile->getSpawnCompound());
             $tiles .= $nbt->write();
         }
     }
     $this->tiles = $tiles;
     $this->compressionLevel = Level::$COMPRESSION_LEVEL;
 }
Пример #15
0
 public function onRun($currentTicks)
 {
     $this->getOwner()->updateVars();
     foreach ($this->getOwner()->getServer()->getLevels() as $lv) {
         if (count($lv->getPlayers()) == 0) {
             continue;
         }
         foreach ($lv->getTiles() as $tile) {
             if (!$tile instanceof Sign) {
                 continue;
             }
             $sign = $tile->getText();
             $text = $this->getOwner()->getLiveSign($sign);
             if ($text == null) {
                 continue;
             }
             $pk = new TileEntityDataPacket();
             $data = $tile->getSpawnCompound();
             $data->Text1 = new String("Text1", $text[0]);
             $data->Text2 = new String("Text2", $text[1]);
             $data->Text3 = new String("Text3", $text[2]);
             $data->Text4 = new String("Text4", $text[3]);
             $nbt = new NBT(NBT::LITTLE_ENDIAN);
             $nbt->setData($data);
             $pk->x = $tile->getX();
             $pk->y = $tile->getY();
             $pk->z = $tile->getZ();
             $pk->namedtag = $nbt->write();
             foreach ($lv->getPlayers() as $pl) {
                 $pl->dataPacket($pk);
             }
             //foreach Players
         }
         //foreach Tiles
     }
     // foreach Levels
 }
Пример #16
0
 public function read(NBT $nbt)
 {
     $this->value = [];
     $size = $nbt->endianness === 1 ? \PHP_INT_SIZE === 8 ? \unpack("N", $nbt->get(4))[1] << 32 >> 32 : \unpack("N", $nbt->get(4))[1] : (\PHP_INT_SIZE === 8 ? \unpack("V", $nbt->get(4))[1] << 32 >> 32 : \unpack("V", $nbt->get(4))[1]);
     $value = \unpack($nbt->endianness === NBT::LITTLE_ENDIAN ? "V*" : "N*", $nbt->get($size * 4));
     foreach ($value as $i => $v) {
         $this->value[$i - 1] = $v;
     }
 }
 public function saveArea(Area $area)
 {
     $nbt = new NBT(NBT::BIG_ENDIAN);
     $data = new Compound();
     $data->CaseName = new String("CaseName", $area->getName());
     $data->SerializedShape = new String("SerializedShape", serialize($area->getShape()));
     $data->UserFlags = new Int("UserFlags", $area->getUserFlags());
     $data->NonUserFlags = new Int("NonUserFlags", $area->getNonUserFlags());
     $data->Owner = new String("Owner", $area->getOwner());
     $data->Users = new Enum("Users", array_map(function ($user) {
         return new String("", $user);
     }, $area->getUsers()));
     $file = str_replace('$${areaname}', strtolower($area->getName()), $this->areaFile);
     file_put_contents($file, $nbt->writeCompressed());
 }
Пример #18
0
 public function execute(CommandSender $sender, $currentAlias, array $args)
 {
     if (!$this->testPermission($sender)) {
         return true;
     }
     if (count($args) < 2) {
         $sender->sendMessage(new TranslationContainer("commands.generic.usage", [$this->usageMessage]));
         return true;
     }
     $player = $sender->getServer()->getPlayer($args[0]);
     $item = Item::fromString($args[1]);
     if (!isset($args[2])) {
         $item->setCount($item->getMaxStackSize());
     } else {
         $item->setCount((int) $args[2]);
     }
     if (isset($args[3])) {
         $tags = $exception = null;
         $data = implode(" ", array_slice($args, 3));
         try {
             $tags = NBT::parseJSON($data);
         } catch (\Throwable $ex) {
             $exception = $ex;
         }
         if (!$tags instanceof CompoundTag or $exception !== null) {
             $sender->sendMessage(new TranslationContainer("commands.give.tagError", [$exception !== null ? $exception->getMessage() : "Invalid tag conversion"]));
             return true;
         }
         $item->setNamedTag($tags);
     }
     if ($player instanceof Player) {
         if ($item->getId() === 0) {
             $sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.give.item.notFound", [$args[1]]));
             return true;
         }
         //TODO: overflow
         $player->getInventory()->addItem(clone $item);
     } else {
         $sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.player.notFound"));
         return true;
     }
     Command::broadcastCommandMessage($sender, new TranslationContainer("%commands.give.success", [$item->getName() . " (" . $item->getId() . ":" . $item->getDamage() . ")", (string) $item->getCount(), $player->getName()]));
     return true;
 }
 /**
  * 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);
     $d = NBT::putItemHelper($item, $index);
     if ($item->getId() === Item::AIR or $item->getCount() <= 0) {
         if ($i >= 0) {
             unset($this->namedtag->Items[$i]);
         }
     } elseif ($i < 0) {
         for ($i = 0; $i <= $this->getSize(); ++$i) {
             if (!isset($this->namedtag->Items[$i])) {
                 break;
             }
         }
         $this->namedtag->Items[$i] = $d;
     } else {
         $this->namedtag->Items[$i] = $d;
     }
     return true;
 }
 public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null)
 {
     if ($face > 1) {
         $faces = [2 => 3, 3 => 2, 4 => 1, 5 => 4];
         $itemTag = NBT::putItemHelper(Item::get(Item::AIR));
         $itemTag->setName("Item");
         $nbt = new CompoundTag("", [new StringTag("id", MainClass::TILE_ITEM_FRAME), new IntTag("x", $block->x), new IntTag("y", $block->y), new IntTag("z", $block->z), new CompoundTag("Item", $itemTag->getValue()), new FloatTag("ItemDropChance", 1.0), new ByteTag("ItemRotation", 0)]);
         if ($item->hasCustomBlockData()) {
             foreach ($item->getCustomBlockData() as $key => $value) {
                 //Reformat: support "Item" tag by give command
                 if ($key === "Item" and $value instanceof CompoundTag) {
                     $value = NBT::putItemHelper(NBT::getItemHelper($value));
                     $value->setName("Item");
                 }
                 $nbt->{$key} = $value;
             }
         }
         //var_dump($nbt);//debug
         Tile::createTile("ItemFrame", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
         $this->getLevel()->setBlock($block, Block::get(MainClass::BLOCK_ITEM_FRAME, $faces[$face]), true, true);
         return true;
     }
     return false;
 }
Пример #21
0
 /**
  * @param Vector3 $source
  * @param Item    $item
  * @param Vector3 $motion
  * @param int     $delay
  */
 public function dropItem(Vector3 $source, Item $item, Vector3 $motion = null, $delay = 10)
 {
     $motion = $motion === null ? new Vector3(lcg_value() * 0.2 - 0.1, 0.2, lcg_value() * 0.2 - 0.1) : $motion;
     $itemTag = NBT::putItemHelper($item);
     $itemTag->setName("Item");
     if ($item->getId() > 0 and $item->getCount() > 0) {
         $itemEntity = Entity::createEntity("Item", $this->getChunk($source->getX() >> 4, $source->getZ() >> 4, true), new Compound("", ["Pos" => new Enum("Pos", [new Double("", $source->getX()), new Double("", $source->getY()), new Double("", $source->getZ())]), "Motion" => new Enum("Motion", [new Double("", $motion->x), new Double("", $motion->y), new Double("", $motion->z)]), "Rotation" => new Enum("Rotation", [new Float("", lcg_value() * 360), new Float("", 0)]), "Health" => new Short("Health", 5), "Item" => $itemTag, "PickupDelay" => new Short("PickupDelay", $delay)]));
         $itemEntity->spawnToAll();
     }
 }
Пример #22
0
 /**
  * @param string   $name
  * @param Compound $nbtTag
  * @param bool $async
  */
 public function saveOfflinePlayerData($name, Compound $nbtTag, $async = false)
 {
     $nbt = new NBT(NBT::BIG_ENDIAN);
     try {
         $nbt->setData($nbtTag);
         if ($async) {
             $this->getScheduler()->scheduleAsyncTask(new FileWriteTask($this->getDataPath() . "players/" . strtolower($name) . ".dat", $nbt->writeCompressed()));
         } else {
             file_put_contents($this->getDataPath() . "players/" . strtolower($name) . ".dat", $nbt->writeCompressed());
         }
     } catch (\Exception $e) {
         $this->logger->critical($this->getLanguage()->translateString("pocketmine.data.saveError", [$name, $e->getMessage()]));
         if (\pocketmine\DEBUG > 1 and $this->logger instanceof MainLogger) {
             $this->logger->logException($e);
         }
     }
 }
Пример #23
0
 public function write(NBT $nbt, bool $network = false)
 {
     $nbt->putByte($this->value);
 }
Пример #24
0
 public function write(NBT $nbt)
 {
     $nbt->putInt(strlen($this->value));
     $nbt->put($this->value);
 }
Пример #25
0
 public function toBinary()
 {
     $nbt = clone $this->getNBT();
     $nbt->xPos = new Int("xPos", $this->x);
     $nbt->zPos = new Int("zPos", $this->z);
     if ($this->isGenerated()) {
         $nbt->Blocks = new ByteArray("Blocks", $this->getBlockIdArray());
         $nbt->Data = new ByteArray("Data", $this->getBlockDataArray());
         $nbt->SkyLight = new ByteArray("SkyLight", $this->getBlockSkyLightArray());
         $nbt->BlockLight = new ByteArray("BlockLight", $this->getBlockLightArray());
         $nbt->Biomes = new ByteArray("Biomes", $this->getBiomeIdArray());
         $nbt->BiomeColors = new IntArray("BiomeColors", $this->getBiomeColorArray());
         $nbt->HeightMap = new IntArray("HeightMap", $this->getHeightMapArray());
     }
     $entities = [];
     foreach ($this->getEntities() as $entity) {
         if (!$entity instanceof Player and !$entity->closed) {
             $entity->saveNBT();
             $entities[] = $entity->namedtag;
         }
     }
     $nbt->Entities = new Enum("Entities", $entities);
     $nbt->Entities->setTagType(NBT::TAG_Compound);
     $tiles = [];
     foreach ($this->getTiles() as $tile) {
         $tile->saveNBT();
         $tiles[] = $tile->namedtag;
     }
     $nbt->TileEntities = new Enum("TileEntities", $tiles);
     $nbt->TileEntities->setTagType(NBT::TAG_Compound);
     $writer = new NBT(NBT::BIG_ENDIAN);
     $nbt->setName("Level");
     $writer->setData(new Compound("", ["Level" => $nbt]));
     return $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL);
 }
Пример #26
0
 public final function deepEquals(Item $item, $checkDamage = true, $checkCompound = true)
 {
     if ($this->equals($item, $checkDamage, $checkCompound)) {
         return true;
     } elseif ($item->hasCompoundTag() and $this->hasCompoundTag()) {
         return NBT::matchTree($this->getNamedTag(), $item->getNamedTag());
     }
     return false;
 }
Пример #27
0
 public function write(NBT $nbt)
 {
     $nbt->putLong($this->value);
 }
Пример #28
0
 public function saveNBT()
 {
     parent::saveNBT();
     $this->namedtag->Item = NBT::putItemHelper($this->item);
     $this->namedtag->Health = new Short("Health", $this->getHealth());
     $this->namedtag->Age = new Short("Age", $this->age);
     $this->namedtag->PickupDelay = new Short("PickupDelay", $this->pickupDelay);
     if ($this->owner !== null) {
         $this->namedtag->Owner = new String("Owner", $this->owner);
     }
     if ($this->thrower !== null) {
         $this->namedtag->Thrower = new String("Thrower", $this->thrower);
     }
 }
Пример #29
0
 public function saveNBT()
 {
     parent::saveNBT();
     $this->namedtag->Inventory = new Enum("Inventory", []);
     $this->namedtag->Inventory->setTagType(NBT::TAG_Compound);
     if ($this->inventory !== null) {
         for ($slot = 0; $slot < 9; ++$slot) {
             $hotbarSlot = $this->inventory->getHotbarSlotIndex($slot);
             if ($hotbarSlot !== -1) {
                 $item = $this->inventory->getItem($hotbarSlot);
                 if ($item->getId() !== 0 and $item->getCount() > 0) {
                     $tag = NBT::putItemHelper($item, $slot);
                     $tag->TrueSlot = new Byte("TrueSlot", $hotbarSlot);
                     $this->namedtag->Inventory[$slot] = $tag;
                     continue;
                 }
             }
             $this->namedtag->Inventory[$slot] = new Compound("", [new Byte("Count", 0), new Short("Damage", 0), new Byte("Slot", $slot), new Byte("TrueSlot", -1), new Short("id", 0)]);
         }
         //Normal inventory
         $slotCount = 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) {
             $item = $this->inventory->getItem($slot - 9);
             $this->namedtag->Inventory[$slot] = NBT::putItemHelper($item, $slot);
         }
         //Armor
         for ($slot = 100; $slot < 104; ++$slot) {
             $item = $this->inventory->getItem($this->inventory->getSize() + $slot - 100);
             if ($item instanceof ItemItem and $item->getId() !== ItemItem::AIR) {
                 $this->namedtag->Inventory[$slot] = NBT::putItemHelper($item, $slot);
             }
         }
     }
     if (strlen($this->getSkinData()) > 0) {
         $this->namedtag->Skin = new Compound("Skin", ["Data" => new String("Data", $this->getSkinData()), "Slim" => new Byte("Slim", $this->isSkinSlim() ? 1 : 0), "Transparent" => new Byte("Transparent", $this->isSkinTransparent() ? 1 : 0)]);
     }
 }
Пример #30
-2
 /**
  * Handles a Minecraft packet
  * TODO: Separate all of this in handlers
  *
  * WARNING: Do not use this, it's only for internal use.
  * Changes to this function won't be recorded on the version.
  *
  * @param DataPacket $packet
  */
 public function handleDataPacket(DataPacket $packet)
 {
     if ($this->connected === false) {
         return;
     }
     if ($packet::NETWORK_ID === ProtocolInfo::BATCH_PACKET) {
         /** @var BatchPacket $packet */
         $this->server->getNetwork()->processBatch($packet, $this);
         return;
     }
     $timings = Timings::getReceiveDataPacketTimings($packet);
     $timings->startTiming();
     $this->server->getPluginManager()->callEvent($ev = new DataPacketReceiveEvent($this, $packet));
     if ($ev->isCancelled()) {
         $timings->stopTiming();
         return;
     }
     switch ($packet::NETWORK_ID) {
         case ProtocolInfo::LOGIN_PACKET:
             if ($this->loggedIn) {
                 break;
             }
             $this->username = TextFormat::clean($packet->username);
             $this->displayName = $this->username;
             $this->setNameTag($this->username);
             $this->iusername = strtolower($this->username);
             if (count($this->server->getOnlinePlayers()) >= $this->server->getMaxPlayers() and $this->kick("disconnectionScreen.serverFull", false)) {
                 break;
             }
             if ($packet->protocol1 !== ProtocolInfo::CURRENT_PROTOCOL) {
                 if ($packet->protocol1 < ProtocolInfo::CURRENT_PROTOCOL) {
                     $message = "disconnectionScreen.outdatedClient";
                     $pk = new PlayStatusPacket();
                     $pk->status = PlayStatusPacket::LOGIN_FAILED_CLIENT;
                     $this->directDataPacket($pk);
                 } else {
                     $message = "disconnectionScreen.outdatedServer";
                     $pk = new PlayStatusPacket();
                     $pk->status = PlayStatusPacket::LOGIN_FAILED_SERVER;
                     $this->directDataPacket($pk);
                 }
                 $this->close("", $message, false);
                 break;
             }
             $this->randomClientId = $packet->clientId;
             $this->loginData = ["clientId" => $packet->clientId, "loginData" => null];
             $this->uuid = $packet->clientUUID;
             $this->rawUUID = $this->uuid->toBinary();
             $this->clientSecret = $packet->clientSecret;
             $valid = true;
             $len = strlen($packet->username);
             if ($len > 16 or $len < 3) {
                 $valid = false;
             }
             for ($i = 0; $i < $len and $valid; ++$i) {
                 $c = ord($packet->username[$i]);
                 if ($c >= ord("a") and $c <= ord("z") or $c >= ord("A") and $c <= ord("Z") or $c >= ord("0") and $c <= ord("9") or $c === ord("_")) {
                     continue;
                 }
                 $valid = false;
                 break;
             }
             if (!$valid or $this->iusername === "rcon" or $this->iusername === "console") {
                 $this->close("", "disconnectionScreen.invalidName");
                 break;
             }
             if (strlen($packet->skin) !== 64 * 32 * 4 and strlen($packet->skin) !== 64 * 64 * 4) {
                 $this->close("", "disconnectionScreen.invalidSkin");
                 break;
             }
             $this->setSkin($packet->skin, $packet->skinname, $packet->oldclient, $packet->slim, $packet->transparent);
             $this->server->getPluginManager()->callEvent($ev = new PlayerPreLoginEvent($this, "Plugin reason"));
             if ($ev->isCancelled()) {
                 $this->close("", $ev->getKickMessage());
                 break;
             }
             $this->onPlayerPreLogin();
             break;
         case ProtocolInfo::MOVE_PLAYER_PACKET:
             $newPos = new Vector3($packet->x, $packet->y - $this->getEyeHeight(), $packet->z);
             $revert = false;
             if (!$this->isAlive() or $this->spawned !== true) {
                 $revert = true;
                 $this->forceMovement = new Vector3($this->x, $this->y, $this->z);
             }
             if ($this->teleportPosition !== null or $this->forceMovement instanceof Vector3 and (($dist = $newPos->distanceSquared($this->forceMovement)) > 0.1 or $revert)) {
                 $this->sendPosition($this->forceMovement, $packet->yaw, $packet->pitch);
             } else {
                 $packet->yaw %= 360;
                 $packet->pitch %= 360;
                 if ($packet->yaw < 0) {
                     $packet->yaw += 360;
                 }
                 $this->setRotation($packet->yaw, $packet->pitch);
                 $this->newPosition = $newPos;
                 $this->forceMovement = null;
             }
             break;
         case ProtocolInfo::MOB_EQUIPMENT_PACKET:
             if ($this->spawned === false or !$this->isAlive()) {
                 break;
             }
             if ($packet->slot === 0x28 or $packet->slot === 0 or $packet->slot === 255) {
                 //0 for 0.8.0 compatibility
                 $packet->slot = -1;
                 //Air
             } else {
                 $packet->slot -= 9;
                 //Get real block slot
             }
             /** @var Item $item */
             $item = null;
             if ($this->isCreative()) {
                 //Creative mode match
                 $item = $packet->item;
                 $slot = Item::getCreativeItemIndex($item);
             } else {
                 $item = $this->inventory->getItem($packet->slot);
                 $slot = $packet->slot;
             }
             if ($packet->slot === -1) {
                 //Air
                 if ($this->isCreative()) {
                     $found = false;
                     for ($i = 0; $i < $this->inventory->getHotbarSize(); ++$i) {
                         if ($this->inventory->getHotbarSlotIndex($i) === -1) {
                             $this->inventory->setHeldItemIndex($i);
                             $found = true;
                             break;
                         }
                     }
                     if (!$found) {
                         //couldn't find a empty slot (error)
                         $this->inventory->sendContents($this);
                         break;
                     }
                 } else {
                     if ($packet->selectedSlot >= 0 and $packet->selectedSlot < 9) {
                         $this->inventory->setHeldItemIndex($packet->selectedSlot);
                         $this->inventory->setHeldItemSlot($packet->slot);
                     } else {
                         $this->inventory->sendContents($this);
                         break;
                     }
                 }
             } elseif ($item === null or $slot === -1 or !$item->deepEquals($packet->item)) {
                 // packet error or not implemented
                 $this->inventory->sendContents($this);
                 break;
             } elseif ($this->isCreative()) {
                 $this->inventory->setHeldItemIndex($packet->selectedSlot);
                 $this->inventory->setItem($packet->selectedSlot, $item);
                 $this->inventory->setHeldItemSlot($packet->selectedSlot);
             } else {
                 if ($packet->selectedSlot >= 0 and $packet->selectedSlot < $this->inventory->getHotbarSize()) {
                     $this->inventory->setHeldItemIndex($packet->selectedSlot);
                     $this->inventory->setHeldItemSlot($slot);
                 } else {
                     $this->inventory->sendContents($this);
                     break;
                 }
             }
             $this->inventory->sendHeldItem($this->hasSpawned);
             $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false);
             break;
         case ProtocolInfo::USE_ITEM_PACKET:
             if ($this->spawned === false or !$this->isAlive() or $this->blocked) {
                 break;
             }
             $blockVector = new Vector3($packet->x, $packet->y, $packet->z);
             $this->craftingType = 0;
             if ($packet->face >= 0 and $packet->face <= 5) {
                 //Use Block, place
                 $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false);
                 if (!$this->canInteract($blockVector->add(0.5, 0.5, 0.5), 13) or $this->isSpectator()) {
                 } elseif ($this->isCreative()) {
                     $item = $this->inventory->getItemInHand();
                     if ($this->level->useItemOn($blockVector, $item, $packet->face, $packet->fx, $packet->fy, $packet->fz, $this) === true) {
                         break;
                     }
                 } elseif (!$this->inventory->getItemInHand()->deepEquals($packet->item)) {
                     $this->inventory->sendHeldItem($this);
                 } else {
                     $item = $this->inventory->getItemInHand();
                     $oldItem = clone $item;
                     //TODO: Implement adventure mode checks
                     if ($this->level->useItemOn($blockVector, $item, $packet->face, $packet->fx, $packet->fy, $packet->fz, $this)) {
                         if (!$item->deepEquals($oldItem) or $item->getCount() !== $oldItem->getCount()) {
                             $this->inventory->setItemInHand($item);
                             $this->inventory->sendHeldItem($this->hasSpawned);
                         }
                         break;
                     }
                 }
                 $this->inventory->sendHeldItem($this);
                 if ($blockVector->distanceSquared($this) > 10000) {
                     break;
                 }
                 $target = $this->level->getBlock($blockVector);
                 $block = $target->getSide($packet->face);
                 $this->level->sendBlocks([$this], [$target, $block], UpdateBlockPacket::FLAG_ALL_PRIORITY);
                 break;
             } elseif ($packet->face === 0xff) {
                 $aimPos = (new Vector3($packet->x / 32768, $packet->y / 32768, $packet->z / 32768))->normalize();
                 if ($this->isCreative()) {
                     $item = $this->inventory->getItemInHand();
                 } elseif (!$this->inventory->getItemInHand()->deepEquals($packet->item)) {
                     $this->inventory->sendHeldItem($this);
                     break;
                 } else {
                     $item = $this->inventory->getItemInHand();
                 }
                 $ev = new PlayerInteractEvent($this, $item, $aimPos, $packet->face, PlayerInteractEvent::RIGHT_CLICK_AIR);
                 $this->server->getPluginManager()->callEvent($ev);
                 if ($ev->isCancelled()) {
                     $this->inventory->sendHeldItem($this);
                     break;
                 }
                 if ($item->getId() === Item::SNOWBALL) {
                     $nbt = new Compound("", ["Pos" => new Enum("Pos", [new Double("", $this->x), new Double("", $this->y + $this->getEyeHeight()), new Double("", $this->z)]), "Motion" => new Enum("Motion", [new Double("", $aimPos->x), new Double("", $aimPos->y), new Double("", $aimPos->z)]), "Rotation" => new Enum("Rotation", [new Float("", $this->yaw), new Float("", $this->pitch)])]);
                     $f = 1.5;
                     $snowball = Entity::createEntity("Snowball", $this->chunk, $nbt, $this);
                     $snowball->setMotion($snowball->getMotion()->multiply($f));
                     if ($this->isSurvival()) {
                         $item->setCount($item->getCount() - 1);
                         $this->inventory->setItemInHand($item->getCount() > 0 ? $item : Item::get(Item::AIR));
                     }
                     if ($snowball instanceof Projectile) {
                         $this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($snowball));
                         if ($projectileEv->isCancelled()) {
                             $snowball->kill();
                         } else {
                             $snowball->spawnToAll();
                             $this->level->addSound(new LaunchSound($this), $this->getViewers());
                         }
                     } else {
                         $snowball->spawnToAll();
                     }
                 }
                 $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, true);
                 $this->startAction = $this->server->getTick();
             }
             break;
         case ProtocolInfo::PLAYER_ACTION_PACKET:
             if ($this->spawned === false or $this->blocked === true or !$this->isAlive() and $packet->action !== PlayerActionPacket::ACTION_RESPAWN and $packet->action !== PlayerActionPacket::ACTION_DIMENSION_CHANGE) {
                 break;
             }
             $packet->eid = $this->id;
             $pos = new Vector3($packet->x, $packet->y, $packet->z);
             switch ($packet->action) {
                 case PlayerActionPacket::ACTION_START_BREAK:
                     if ($this->lastBreak !== PHP_INT_MAX or $pos->distanceSquared($this) > 10000) {
                         break;
                     }
                     $target = $this->level->getBlock($pos);
                     $ev = new PlayerInteractEvent($this, $this->inventory->getItemInHand(), $target, $packet->face, $target->getId() === 0 ? PlayerInteractEvent::LEFT_CLICK_AIR : PlayerInteractEvent::LEFT_CLICK_BLOCK);
                     $this->getServer()->getPluginManager()->callEvent($ev);
                     if ($ev->isCancelled()) {
                         $this->inventory->sendHeldItem($this);
                         break;
                     }
                     $this->lastBreak = microtime(true);
                     break;
                 case PlayerActionPacket::ACTION_ABORT_BREAK:
                     $this->lastBreak = PHP_INT_MAX;
                     break;
                 case PlayerActionPacket::ACTION_RELEASE_ITEM:
                     if ($this->startAction > -1 and $this->getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION)) {
                         if ($this->inventory->getItemInHand()->getId() === Item::BOW) {
                             $bow = $this->inventory->getItemInHand();
                             if ($this->isSurvival() and !$this->inventory->contains(Item::get(Item::ARROW, 0, 1))) {
                                 $this->inventory->sendContents($this);
                                 break;
                             }
                             $nbt = new Compound("", ["Pos" => new Enum("Pos", [new Double("", $this->x), new Double("", $this->y + $this->getEyeHeight()), new Double("", $this->z)]), "Motion" => new Enum("Motion", [new Double("", -sin($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI)), new Double("", -sin($this->pitch / 180 * M_PI)), new Double("", cos($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI))]), "Rotation" => new Enum("Rotation", [new Float("", $this->yaw), new Float("", $this->pitch)]), "Fire" => new Short("Fire", $this->isOnFire() ? 45 * 60 : 0)]);
                             $diff = $this->server->getTick() - $this->startAction;
                             $p = $diff / 20;
                             $f = min(($p ** 2 + $p * 2) / 3, 1) * 2;
                             $ev = new EntityShootBowEvent($this, $bow, Entity::createEntity("Arrow", $this->chunk, $nbt, $this, $f == 2 ? true : false), $f);
                             if ($f < 0.1 or $diff < 5) {
                                 $ev->setCancelled();
                             }
                             $this->server->getPluginManager()->callEvent($ev);
                             if ($ev->isCancelled()) {
                                 $ev->getProjectile()->kill();
                                 $this->inventory->sendContents($this);
                             } else {
                                 $ev->getProjectile()->setMotion($ev->getProjectile()->getMotion()->multiply($ev->getForce()));
                                 if ($this->isSurvival()) {
                                     $this->inventory->removeItem(Item::get(Item::ARROW, 0, 1));
                                     $bow->setDamage($bow->getDamage() + 1);
                                     if ($bow->getDamage() >= 385) {
                                         $this->inventory->setItemInHand(Item::get(Item::AIR, 0, 0));
                                     } else {
                                         $this->inventory->setItemInHand($bow);
                                     }
                                 }
                                 if ($ev->getProjectile() instanceof Projectile) {
                                     $this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($ev->getProjectile()));
                                     if ($projectileEv->isCancelled()) {
                                         $ev->getProjectile()->kill();
                                     } else {
                                         $ev->getProjectile()->spawnToAll();
                                         $this->level->addSound(new LaunchSound($this), $this->getViewers());
                                     }
                                 } else {
                                     $ev->getProjectile()->spawnToAll();
                                 }
                             }
                         }
                     } elseif ($this->inventory->getItemInHand()->getId() === Item::BUCKET and $this->inventory->getItemInHand()->getDamage() === 1) {
                         //Milk!
                         $this->server->getPluginManager()->callEvent($ev = new PlayerItemConsumeEvent($this, $this->inventory->getItemInHand()));
                         if ($ev->isCancelled()) {
                             $this->inventory->sendContents($this);
                             break;
                         }
                         $pk = new EntityEventPacket();
                         $pk->eid = $this->getId();
                         $pk->event = EntityEventPacket::USE_ITEM;
                         $this->dataPacket($pk);
                         Server::broadcastPacket($this->getViewers(), $pk);
                         if ($this->isSurvival()) {
                             $slot = $this->inventory->getItemInHand();
                             --$slot->count;
                             $this->inventory->setItemInHand($slot);
                             $this->inventory->addItem(Item::get(Item::BUCKET, 0, 1));
                         }
                         $this->removeAllEffects();
                     } else {
                         $this->inventory->sendContents($this);
                     }
                     break;
                 case PlayerActionPacket::ACTION_STOP_SLEEPING:
                     $this->stopSleep();
                     break;
                 case PlayerActionPacket::ACTION_RESPAWN:
                     if ($this->spawned === false or $this->isAlive() or !$this->isOnline()) {
                         break;
                     }
                     if ($this->server->isHardcore()) {
                         $this->setBanned(true);
                         break;
                     }
                     $this->craftingType = 0;
                     $this->server->getPluginManager()->callEvent($ev = new PlayerRespawnEvent($this, $this->getSpawn()));
                     $this->teleport($ev->getRespawnPosition());
                     $this->setSprinting(false);
                     $this->setSneaking(false);
                     $this->extinguish();
                     $this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, 300);
                     $this->deadTicks = 0;
                     $this->noDamageTicks = 60;
                     $this->setHealth($this->getMaxHealth());
                     $this->removeAllEffects();
                     $this->sendData($this);
                     $this->sendSettings();
                     $this->inventory->sendContents($this);
                     $this->inventory->sendArmorContents($this);
                     $this->blocked = false;
                     $this->spawnToAll();
                     $this->scheduleUpdate();
                     break;
                 case PlayerActionPacket::ACTION_START_SPRINT:
                     $ev = new PlayerToggleSprintEvent($this, true);
                     $this->server->getPluginManager()->callEvent($ev);
                     if ($ev->isCancelled()) {
                         $this->sendData($this);
                     } else {
                         $this->setSprinting(true);
                     }
                     break;
                 case PlayerActionPacket::ACTION_STOP_SPRINT:
                     $ev = new PlayerToggleSprintEvent($this, false);
                     $this->server->getPluginManager()->callEvent($ev);
                     if ($ev->isCancelled()) {
                         $this->sendData($this);
                     } else {
                         $this->setSprinting(false);
                     }
                     break;
                 case PlayerActionPacket::ACTION_START_SNEAK:
                     $ev = new PlayerToggleSneakEvent($this, true);
                     $this->server->getPluginManager()->callEvent($ev);
                     if ($ev->isCancelled()) {
                         $this->sendData($this);
                     } else {
                         $this->setSneaking(true);
                     }
                     break;
                 case PlayerActionPacket::ACTION_STOP_SNEAK:
                     $ev = new PlayerToggleSneakEvent($this, false);
                     $this->server->getPluginManager()->callEvent($ev);
                     if ($ev->isCancelled()) {
                         $this->sendData($this);
                     } else {
                         $this->setSneaking(false);
                     }
                     break;
             }
             $this->startAction = -1;
             $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false);
             break;
         case ProtocolInfo::REMOVE_BLOCK_PACKET:
             if ($this->spawned === false or $this->blocked === true or !$this->isAlive()) {
                 break;
             }
             $this->craftingType = 0;
             $vector = new Vector3($packet->x, $packet->y, $packet->z);
             if ($this->isCreative()) {
                 $item = $this->inventory->getItemInHand();
             } else {
                 $item = $this->inventory->getItemInHand();
             }
             $oldItem = clone $item;
             if ($this->canInteract($vector->add(0.5, 0.5, 0.5), $this->isCreative() ? 13 : 6) and $this->level->useBreakOn($vector, $item, $this)) {
                 if ($this->isSurvival()) {
                     if (!$item->deepEquals($oldItem) or $item->getCount() !== $oldItem->getCount()) {
                         $this->inventory->setItemInHand($item);
                         $this->inventory->sendHeldItem($this->hasSpawned);
                     }
                 }
                 break;
             }
             $this->inventory->sendContents($this);
             $target = $this->level->getBlock($vector);
             $tile = $this->level->getTile($vector);
             $this->level->sendBlocks([$this], [$target], UpdateBlockPacket::FLAG_ALL_PRIORITY);
             $this->inventory->sendHeldItem($this);
             if ($tile instanceof Spawnable) {
                 $tile->spawnTo($this);
             }
             break;
         case ProtocolInfo::MOB_ARMOR_EQUIPMENT_PACKET:
             break;
         case ProtocolInfo::INTERACT_PACKET:
             if ($this->spawned === false or !$this->isAlive() or $this->blocked) {
                 break;
             }
             $this->craftingType = 0;
             $target = $this->level->getEntity($packet->target);
             $cancelled = false;
             if ($target instanceof Player and $this->server->getConfigBoolean("pvp", true) === false) {
                 $cancelled = true;
             }
             if ($target instanceof Entity and $this->getGamemode() !== Player::VIEW and $this->isAlive() and $target->isAlive()) {
                 if ($target instanceof DroppedItem or $target instanceof Arrow) {
                     $this->kick("Attempting to attack an invalid entity");
                     $this->server->getLogger()->warning($this->getServer()->getLanguage()->translateString("pocketmine.player.invalidEntity", [$this->getName()]));
                     break;
                 }
                 $item = $this->inventory->getItemInHand();
                 $damageTable = [Item::WOODEN_SWORD => 4, Item::GOLD_SWORD => 4, Item::STONE_SWORD => 5, Item::IRON_SWORD => 6, Item::DIAMOND_SWORD => 7, Item::WOODEN_AXE => 3, Item::GOLD_AXE => 3, Item::STONE_AXE => 3, Item::IRON_AXE => 5, Item::DIAMOND_AXE => 6, Item::WOODEN_PICKAXE => 2, Item::GOLD_PICKAXE => 2, Item::STONE_PICKAXE => 3, Item::IRON_PICKAXE => 4, Item::DIAMOND_PICKAXE => 5, Item::WOODEN_SHOVEL => 1, Item::GOLD_SHOVEL => 1, Item::STONE_SHOVEL => 2, Item::IRON_SHOVEL => 3, Item::DIAMOND_SHOVEL => 4];
                 $damage = [EntityDamageEvent::MODIFIER_BASE => isset($damageTable[$item->getId()]) ? $damageTable[$item->getId()] : 1];
                 if (!$this->canInteract($target, 8)) {
                     $cancelled = true;
                 } elseif ($target instanceof Player) {
                     if (($target->getGamemode() & 0x1) > 0) {
                         break;
                     } elseif ($this->server->getConfigBoolean("pvp") !== true or $this->server->getDifficulty() === 0) {
                         $cancelled = true;
                     }
                     $armorValues = [Item::LEATHER_CAP => 1, Item::LEATHER_TUNIC => 3, Item::LEATHER_PANTS => 2, Item::LEATHER_BOOTS => 1, Item::CHAIN_HELMET => 1, Item::CHAIN_CHESTPLATE => 5, Item::CHAIN_LEGGINGS => 4, Item::CHAIN_BOOTS => 1, Item::GOLD_HELMET => 1, Item::GOLD_CHESTPLATE => 5, Item::GOLD_LEGGINGS => 3, Item::GOLD_BOOTS => 1, Item::IRON_HELMET => 2, Item::IRON_CHESTPLATE => 6, Item::IRON_LEGGINGS => 5, Item::IRON_BOOTS => 2, Item::DIAMOND_HELMET => 3, Item::DIAMOND_CHESTPLATE => 8, Item::DIAMOND_LEGGINGS => 6, Item::DIAMOND_BOOTS => 3];
                     $points = 0;
                     foreach ($target->getInventory()->getArmorContents() as $index => $i) {
                         if (isset($armorValues[$i->getId()])) {
                             $points += $armorValues[$i->getId()];
                         }
                     }
                     $damage[EntityDamageEvent::MODIFIER_ARMOR] = -floor($damage[EntityDamageEvent::MODIFIER_BASE] * $points * 0.04);
                 }
                 $ev = new EntityDamageByEntityEvent($this, $target, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $damage);
                 if ($cancelled) {
                     $ev->setCancelled();
                 }
                 $target->attack($ev->getFinalDamage(), $ev);
                 if ($ev->isCancelled()) {
                     if ($item->isTool() and $this->isSurvival()) {
                         $this->inventory->sendContents($this);
                     }
                     break;
                 }
                 if ($item->isTool() and $this->isSurvival()) {
                     if ($item->useOn($target) and $item->getDamage() >= $item->getMaxDurability()) {
                         $this->inventory->setItemInHand(Item::get(Item::AIR, 0, 1));
                     } else {
                         $this->inventory->setItemInHand($item);
                     }
                 }
             }
             break;
         case ProtocolInfo::ANIMATE_PACKET:
             if ($this->spawned === false or !$this->isAlive()) {
                 break;
             }
             $this->server->getPluginManager()->callEvent($ev = new PlayerAnimationEvent($this, $packet->action));
             if ($ev->isCancelled()) {
                 break;
             }
             $pk = new AnimatePacket();
             $pk->eid = $this->getId();
             $pk->action = $ev->getAnimationType();
             Server::broadcastPacket($this->getViewers(), $pk);
             break;
         case ProtocolInfo::SET_HEALTH_PACKET:
             //Not used
             break;
         case ProtocolInfo::ENTITY_EVENT_PACKET:
             if ($this->spawned === false or $this->blocked === true or !$this->isAlive()) {
                 break;
             }
             $this->craftingType = 0;
             $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false);
             //TODO: check if this should be true
             switch ($packet->event) {
                 case 9:
                     //Eating
                     $items = [Item::APPLE => 4, Item::MUSHROOM_STEW => 10, Item::BEETROOT_SOUP => 10, Item::BREAD => 5, Item::RAW_PORKCHOP => 3, Item::COOKED_PORKCHOP => 8, Item::RAW_BEEF => 3, Item::STEAK => 8, Item::COOKED_CHICKEN => 6, Item::RAW_CHICKEN => 2, Item::MELON_SLICE => 2, Item::GOLDEN_APPLE => 10, Item::PUMPKIN_PIE => 8, Item::CARROT => 4, Item::POTATO => 1, Item::BAKED_POTATO => 6, Item::COOKIE => 2, Item::COOKED_FISH => 5, Item::COOKED_SALMON => 6, Item::RAW_FISH => 2, Item::RAW_SALMON => 2, Item::CLOWN_FISH => 1, Item::PUFFER_FISH => 1];
                     $slot = $this->inventory->getItemInHand();
                     if ($this->getHealth() < $this->getMaxHealth() and isset($items[$slot->getId()])) {
                         $this->server->getPluginManager()->callEvent($ev = new PlayerItemConsumeEvent($this, $slot));
                         if ($ev->isCancelled()) {
                             $this->inventory->sendContents($this);
                             break;
                         }
                         $pk = new EntityEventPacket();
                         $pk->eid = $this->getId();
                         $pk->event = EntityEventPacket::USE_ITEM;
                         $this->dataPacket($pk);
                         Server::broadcastPacket($this->getViewers(), $pk);
                         $amount = $items[$slot->getId()];
                         $ev = new EntityRegainHealthEvent($this, $amount, EntityRegainHealthEvent::CAUSE_EATING);
                         $this->heal($ev->getAmount(), $ev);
                         --$slot->count;
                         $this->inventory->setItemInHand($slot);
                         if ($slot->getId() === Item::MUSHROOM_STEW or $slot->getId() === Item::BEETROOT_SOUP) {
                             $this->inventory->addItem(Item::get(Item::BOWL, 0, 1));
                         } elseif ($slot->getId() === Item::PUFFER_FISH) {
                             //Pufferfish
                             //$this->addEffect(Effect::getEffect(Effect::HUNGER)->setAmplifier(2)->setDuration(15 * 20));
                             $this->addEffect(Effect::getEffect(Effect::NAUSEA)->setAmplifier(1)->setDuration(15 * 20));
                             $this->addEffect(Effect::getEffect(Effect::POISON)->setAmplifier(3)->setDuration(60 * 20));
                         }
                     }
                     break;
             }
             break;
         case ProtocolInfo::DROP_ITEM_PACKET:
             if ($this->spawned === false or $this->blocked === true or !$this->isAlive()) {
                 break;
             }
             $item = $this->inventory->getItemInHand();
             $ev = new PlayerDropItemEvent($this, $item);
             $this->server->getPluginManager()->callEvent($ev);
             if ($ev->isCancelled()) {
                 $this->inventory->sendContents($this);
                 break;
             }
             $this->inventory->setItemInHand(Item::get(Item::AIR, 0, 1));
             $motion = $this->getDirectionVector()->multiply(0.4);
             $this->level->dropItem($this->add(0, 1.3, 0), $item, $motion, 40);
             $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false);
             break;
         case ProtocolInfo::TEXT_PACKET:
             if ($this->spawned === false or !$this->isAlive()) {
                 break;
             }
             $this->craftingType = 0;
             if ($packet->type === TextPacket::TYPE_CHAT) {
                 $packet->message = TextFormat::clean($packet->message, $this->removeFormat);
                 foreach (explode("\n", $packet->message) as $message) {
                     if (trim($message) != "" and strlen($message) <= 255 and $this->messageCounter-- > 0) {
                         $ev = new PlayerCommandPreprocessEvent($this, $message);
                         if (mb_strlen($ev->getMessage(), "UTF-8") > 320) {
                             $ev->setCancelled();
                         }
                         $this->server->getPluginManager()->callEvent($ev);
                         if ($ev->isCancelled()) {
                             break;
                         }
                         if (substr($ev->getMessage(), 0, 1) === "/") {
                             //Command
                             Timings::$playerCommandTimer->startTiming();
                             $this->server->dispatchCommand($ev->getPlayer(), substr($ev->getMessage(), 1));
                             Timings::$playerCommandTimer->stopTiming();
                         } else {
                             $this->server->getPluginManager()->callEvent($ev = new PlayerChatEvent($this, $ev->getMessage()));
                             if (!$ev->isCancelled()) {
                                 $this->server->broadcastMessage($this->getServer()->getLanguage()->translateString($ev->getFormat(), [$ev->getPlayer()->getDisplayName(), $ev->getMessage()]), $ev->getRecipients());
                             }
                         }
                     }
                 }
             }
             break;
         case ProtocolInfo::CONTAINER_CLOSE_PACKET:
             if ($this->spawned === false or $packet->windowid === 0) {
                 break;
             }
             $this->craftingType = 0;
             $this->currentTransaction = null;
             if (isset($this->windowIndex[$packet->windowid])) {
                 $this->server->getPluginManager()->callEvent(new InventoryCloseEvent($this->windowIndex[$packet->windowid], $this));
                 $this->removeWindow($this->windowIndex[$packet->windowid]);
             } else {
                 unset($this->windowIndex[$packet->windowid]);
             }
             break;
         case ProtocolInfo::CRAFTING_EVENT_PACKET:
             if ($this->spawned === false or !$this->isAlive()) {
                 break;
             } elseif (!isset($this->windowIndex[$packet->windowId])) {
                 $this->inventory->sendContents($this);
                 $pk = new ContainerClosePacket();
                 $pk->windowid = $packet->windowId;
                 $this->dataPacket($pk);
                 break;
             }
             $recipe = $this->server->getCraftingManager()->getRecipe($packet->id);
             if ($recipe === null or ($recipe instanceof BigShapelessRecipe or $recipe instanceof BigShapedRecipe) and $this->craftingType === 0) {
                 $this->inventory->sendContents($this);
                 break;
             }
             foreach ($packet->input as $i => $item) {
                 if ($item->getDamage() === -1 or $item->getDamage() === 0xffff) {
                     $item->setDamage(null);
                 }
                 if ($i < 9 and $item->getId() > 0) {
                     $item->setCount(1);
                 }
             }
             $canCraft = true;
             if ($recipe instanceof ShapedRecipe) {
                 for ($x = 0; $x < 3 and $canCraft; ++$x) {
                     for ($y = 0; $y < 3; ++$y) {
                         $item = $packet->input[$y * 3 + $x];
                         $ingredient = $recipe->getIngredient($x, $y);
                         if ($item->getCount() > 0) {
                             if ($ingredient === null or !$ingredient->deepEquals($item, $ingredient->getDamage() !== null, $ingredient->getCompoundTag() !== null)) {
                                 $canCraft = false;
                                 break;
                             }
                         }
                     }
                 }
             } elseif ($recipe instanceof ShapelessRecipe) {
                 $needed = $recipe->getIngredientList();
                 for ($x = 0; $x < 3 and $canCraft; ++$x) {
                     for ($y = 0; $y < 3; ++$y) {
                         $item = clone $packet->input[$y * 3 + $x];
                         foreach ($needed as $k => $n) {
                             if ($n->deepEquals($item, $n->getDamage() !== null, $n->getCompoundTag() !== null)) {
                                 $remove = min($n->getCount(), $item->getCount());
                                 $n->setCount($n->getCount() - $remove);
                                 $item->setCount($item->getCount() - $remove);
                                 if ($n->getCount() === 0) {
                                     unset($needed[$k]);
                                 }
                             }
                         }
                         if ($item->getCount() > 0) {
                             $canCraft = false;
                             break;
                         }
                     }
                 }
                 if (count($needed) > 0) {
                     $canCraft = false;
                 }
             } else {
                 $canCraft = false;
             }
             /** @var Item[] $ingredients */
             $ingredients = $packet->input;
             $result = $packet->output[0];
             if (!$canCraft or !$recipe->getResult()->deepEquals($result)) {
                 $this->server->getLogger()->debug("Unmatched recipe " . $recipe->getId() . " from player " . $this->getName() . ": expected " . $recipe->getResult() . ", got " . $result . ", using: " . implode(", ", $ingredients));
                 $this->inventory->sendContents($this);
                 break;
             }
             $used = array_fill(0, $this->inventory->getSize(), 0);
             foreach ($ingredients as $ingredient) {
                 $slot = -1;
                 foreach ($this->inventory->getContents() as $index => $i) {
                     if ($ingredient->getId() !== 0 and $ingredient->deepEquals($i, $i->getDamage() !== null) and $i->getCount() - $used[$index] >= 1) {
                         $slot = $index;
                         $used[$index]++;
                         break;
                     }
                 }
                 if ($ingredient->getId() !== 0 and $slot === -1) {
                     $canCraft = false;
                     break;
                 }
             }
             if (!$canCraft) {
                 $this->server->getLogger()->debug("Unmatched recipe " . $recipe->getId() . " from player " . $this->getName() . ": client does not have enough items, using: " . implode(", ", $ingredients));
                 $this->inventory->sendContents($this);
                 break;
             }
             $this->server->getPluginManager()->callEvent($ev = new CraftItemEvent($this, $ingredients, $recipe));
             if ($ev->isCancelled()) {
                 $this->inventory->sendContents($this);
                 break;
             }
             foreach ($used as $slot => $count) {
                 if ($count === 0) {
                     continue;
                 }
                 $item = $this->inventory->getItem($slot);
                 if ($item->getCount() > $count) {
                     $newItem = clone $item;
                     $newItem->setCount($item->getCount() - $count);
                 } else {
                     $newItem = Item::get(Item::AIR, 0, 0);
                 }
                 $this->inventory->setItem($slot, $newItem);
             }
             $extraItem = $this->inventory->addItem($recipe->getResult());
             if (count($extraItem) > 0) {
                 foreach ($extraItem as $item) {
                     $this->level->dropItem($this, $item);
                 }
             }
             switch ($recipe->getResult()->getId()) {
                 case Item::WORKBENCH:
                     $this->awardAchievement("buildWorkBench");
                     break;
                 case Item::WOODEN_PICKAXE:
                     $this->awardAchievement("buildPickaxe");
                     break;
                 case Item::FURNACE:
                     $this->awardAchievement("buildFurnace");
                     break;
                 case Item::WOODEN_HOE:
                     $this->awardAchievement("buildHoe");
                     break;
                 case Item::BREAD:
                     $this->awardAchievement("makeBread");
                     break;
                 case Item::CAKE:
                     //TODO: detect complex recipes like cake that leave remains
                     $this->awardAchievement("bakeCake");
                     $this->inventory->addItem(Item::get(Item::BUCKET, 0, 3));
                     break;
                 case Item::STONE_PICKAXE:
                 case Item::GOLD_PICKAXE:
                 case Item::IRON_PICKAXE:
                 case Item::DIAMOND_PICKAXE:
                     $this->awardAchievement("buildBetterPickaxe");
                     break;
                 case Item::WOODEN_SWORD:
                     $this->awardAchievement("buildSword");
                     break;
                 case Item::DIAMOND:
                     $this->awardAchievement("diamond");
                     break;
             }
             break;
         case ProtocolInfo::CONTAINER_SET_SLOT_PACKET:
             if ($this->spawned === false or $this->blocked === true or !$this->isAlive()) {
                 break;
             }
             if ($packet->slot < 0) {
                 break;
             }
             if ($packet->windowid === 0) {
                 //Our inventory
                 if ($packet->slot >= $this->inventory->getSize()) {
                     break;
                 }
                 if ($this->isCreative()) {
                     if (Item::getCreativeItemIndex($packet->item) !== -1) {
                         $this->inventory->setItem($packet->slot, $packet->item);
                         $this->inventory->setHotbarSlotIndex($packet->slot, $packet->slot);
                         //links $hotbar[$packet->slot] to $slots[$packet->slot]
                     }
                 }
                 $transaction = new BaseTransaction($this->inventory, $packet->slot, $this->inventory->getItem($packet->slot), $packet->item);
             } elseif ($packet->windowid === ContainerSetContentPacket::SPECIAL_ARMOR) {
                 //Our armor
                 if ($packet->slot >= 4) {
                     break;
                 }
                 $transaction = new BaseTransaction($this->inventory, $packet->slot + $this->inventory->getSize(), $this->inventory->getArmorItem($packet->slot), $packet->item);
             } elseif (isset($this->windowIndex[$packet->windowid])) {
                 $this->craftingType = 0;
                 $inv = $this->windowIndex[$packet->windowid];
                 $transaction = new BaseTransaction($inv, $packet->slot, $inv->getItem($packet->slot), $packet->item);
             } else {
                 break;
             }
             if ($transaction->getSourceItem()->deepEquals($transaction->getTargetItem()) and $transaction->getTargetItem()->getCount() === $transaction->getSourceItem()->getCount()) {
                 //No changes!
                 //No changes, just a local inventory update sent by the server
                 break;
             }
             if ($this->currentTransaction === null or $this->currentTransaction->getCreationTime() < microtime(true) - 8) {
                 if ($this->currentTransaction !== null) {
                     foreach ($this->currentTransaction->getInventories() as $inventory) {
                         if ($inventory instanceof PlayerInventory) {
                             $inventory->sendArmorContents($this);
                         }
                         $inventory->sendContents($this);
                     }
                 }
                 $this->currentTransaction = new SimpleTransactionGroup($this);
             }
             $this->currentTransaction->addTransaction($transaction);
             if ($this->currentTransaction->canExecute()) {
                 $achievements = [];
                 foreach ($this->currentTransaction->getTransactions() as $ts) {
                     $inv = $ts->getInventory();
                     if ($inv instanceof FurnaceInventory) {
                         if ($ts->getSlot() === 2) {
                             switch ($inv->getResult()->getId()) {
                                 case Item::IRON_INGOT:
                                     $achievements[] = "acquireIron";
                                     break;
                             }
                         }
                     }
                 }
                 if ($this->currentTransaction->execute()) {
                     foreach ($achievements as $a) {
                         $this->awardAchievement($a);
                     }
                 }
                 $this->currentTransaction = null;
             }
             break;
         case ProtocolInfo::BLOCK_ENTITY_DATA_PACKET:
             if ($this->spawned === false or $this->blocked === true or !$this->isAlive()) {
                 break;
             }
             $this->craftingType = 0;
             $pos = new Vector3($packet->x, $packet->y, $packet->z);
             if ($pos->distanceSquared($this) > 10000) {
                 break;
             }
             $t = $this->level->getTile($pos);
             if ($t instanceof Sign) {
                 $nbt = new NBT(NBT::LITTLE_ENDIAN);
                 $nbt->read($packet->namedtag);
                 $nbt = $nbt->getData();
                 if ($nbt["id"] !== Tile::SIGN) {
                     $t->spawnTo($this);
                 } else {
                     $ev = new SignChangeEvent($t->getBlock(), $this, [TextFormat::clean($nbt["Text1"], $this->removeFormat), TextFormat::clean($nbt["Text2"], $this->removeFormat), TextFormat::clean($nbt["Text3"], $this->removeFormat), TextFormat::clean($nbt["Text4"], $this->removeFormat)]);
                     if (!isset($t->namedtag->Creator) or $t->namedtag["Creator"] !== $this->getRawUniqueId()) {
                         $ev->setCancelled();
                     } else {
                         foreach ($ev->getLines() as $line) {
                             if (mb_strlen($line, "UTF-8") > 16) {
                                 $ev->setCancelled();
                             }
                         }
                     }
                     $this->server->getPluginManager()->callEvent($ev);
                     if (!$ev->isCancelled()) {
                         $t->setText($ev->getLine(0), $ev->getLine(1), $ev->getLine(2), $ev->getLine(3));
                     } else {
                         $t->spawnTo($this);
                     }
                 }
             }
             break;
         default:
             break;
     }
     $timings->stopTiming();
 }