From e3b3f60c669ea413fca775e4487615ddbb229bf4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 17 Jun 2017 12:22:38 +0100 Subject: [PATCH] Fixed item stack count and effect amplifier overflows, close #1072 --- src/pocketmine/entity/Entity.php | 5 +++-- src/pocketmine/item/Item.php | 12 +++++++---- src/pocketmine/utils/Binary.php | 34 +++++++++++++++++++++++++++----- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index cc137bb51..5a9dbe9c6 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -60,6 +60,7 @@ use pocketmine\network\mcpe\protocol\SetEntityDataPacket; use pocketmine\Player; use pocketmine\plugin\Plugin; use pocketmine\Server; +use pocketmine\utils\Binary; abstract class Entity extends Location implements Metadatable{ @@ -773,7 +774,7 @@ abstract class Entity extends Location implements Metadatable{ foreach($this->effects as $effect){ $effects[] = new CompoundTag("", [ "Id" => new ByteTag("Id", $effect->getId()), - "Amplifier" => new ByteTag("Amplifier", $effect->getAmplifier()), + "Amplifier" => new ByteTag("Amplifier", Binary::signByte($effect->getAmplifier())), "Duration" => new IntTag("Duration", $effect->getDuration()), "Ambient" => new ByteTag("Ambient", 0), "ShowParticles" => new ByteTag("ShowParticles", $effect->isVisible() ? 1 : 0) @@ -800,7 +801,7 @@ abstract class Entity extends Location implements Metadatable{ if(isset($this->namedtag->ActiveEffects)){ foreach($this->namedtag->ActiveEffects->getValue() as $e){ - $amplifier = $e["Amplifier"] & 0xff; //0-255 only + $amplifier = Binary::unsignByte($e->Amplifier->getValue()); //0-255 only $effect = Effect::getEffect($e["Id"]); if($effect === null){ diff --git a/src/pocketmine/item/Item.php b/src/pocketmine/item/Item.php index b49ea708a..bebb5f3ad 100644 --- a/src/pocketmine/item/Item.php +++ b/src/pocketmine/item/Item.php @@ -40,6 +40,7 @@ use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\tag\Tag; use pocketmine\Player; use pocketmine\Server; +use pocketmine\utils\Binary; use pocketmine\utils\Config; class Item implements ItemIds, \JsonSerializable{ @@ -1009,7 +1010,7 @@ class Item implements ItemIds, \JsonSerializable{ public function nbtSerialize(int $slot = -1, string $tagName = "") : CompoundTag{ $tag = new CompoundTag($tagName, [ "id" => new ShortTag("id", $this->id), - "Count" => new ByteTag("Count", $this->count), + "Count" => new ByteTag("Count", Binary::signByte($this->count)), "Damage" => new ShortTag("Damage", $this->meta), ]); @@ -1037,12 +1038,15 @@ class Item implements ItemIds, \JsonSerializable{ return Item::get(0); } + $count = Binary::unsignByte($tag->Count->getValue()); + $meta = isset($tag->Damage) ? $tag->Damage->getValue() : 0; + if($tag->id instanceof ShortTag){ - $item = Item::get($tag->id->getValue(), !isset($tag->Damage) ? 0 : $tag->Damage->getValue(), $tag->Count->getValue()); + $item = Item::get($tag->id->getValue(), $meta, $count); }elseif($tag->id instanceof StringTag){ //PC item save format $item = Item::fromString($tag->id->getValue()); - $item->setDamage(!isset($tag->Damage) ? 0 : $tag->Damage->getValue()); - $item->setCount($tag->Count->getValue()); + $item->setDamage($meta); + $item->setCount($count); }else{ throw new \InvalidArgumentException("Item CompoundTag ID must be an instance of StringTag or ShortTag, " . get_class($tag->id) . " given"); } diff --git a/src/pocketmine/utils/Binary.php b/src/pocketmine/utils/Binary.php index df7c3c9bc..386aaa3d5 100644 --- a/src/pocketmine/utils/Binary.php +++ b/src/pocketmine/utils/Binary.php @@ -31,6 +31,30 @@ class Binary{ const BIG_ENDIAN = 0x00; const LITTLE_ENDIAN = 0x01; + public static function signByte(int $value) : int{ + return $value << 56 >> 56; + } + + public static function unsignByte(int $value) : int{ + return $value & 0xff; + } + + public static function signShort(int $value) : int{ + return $value << 48 >> 48; + } + + public function unsignShort(int $value) : int{ + return $value & 0xffff; + } + + public static function signInt(int $value) : int{ + return $value << 32 >> 32; + } + + public static function unsignInt(int $value) : int{ + return $value & 0xffffffff; + } + private static function checkLength($str, $expect){ assert(($len = strlen($str)) === $expect, "Expected $expect bytes, got $len"); } @@ -73,7 +97,7 @@ class Binary{ * @return int */ public static function readSignedByte(string $c) : int{ - return ord($c{0}) << 56 >> 56; + return self::signByte(ord($c{0})); } /** @@ -106,7 +130,7 @@ class Binary{ */ public static function readSignedShort(string $str) : int{ self::checkLength($str, 2); - return unpack("n", $str)[1] << 48 >> 48; + return self::signShort(unpack("n", $str)[1]); } /** @@ -141,7 +165,7 @@ class Binary{ */ public static function readSignedLShort(string $str) : int{ self::checkLength($str, 2); - return unpack("v", $str)[1] << 48 >> 48; + return self::signShort(unpack("v", $str)[1]); } /** @@ -205,7 +229,7 @@ class Binary{ */ public static function readInt(string $str) : int{ self::checkLength($str, 4); - return unpack("N", $str)[1] << 32 >> 32; + return self::signInt(unpack("N", $str)[1]); } /** @@ -226,7 +250,7 @@ class Binary{ */ public static function readLInt(string $str) : int{ self::checkLength($str, 4); - return unpack("V", $str)[1] << 32 >> 32; + return self::signInt(unpack("V", $str)[1]); } /**