Extract mandatory parameters into constructor parameters

the goal is obviously to ditch NBT entirely here, but there's more work to be done before that becomes possible.
This commit is contained in:
Dylan K. Taylor 2020-06-19 02:49:24 +01:00
parent 3f135da704
commit 1205432c34
22 changed files with 192 additions and 180 deletions

View File

@ -24,7 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\EntityFactory; use pocketmine\entity\Location;
use pocketmine\entity\object\PrimedTNT; use pocketmine\entity\object\PrimedTNT;
use pocketmine\entity\projectile\Arrow; use pocketmine\entity\projectile\Arrow;
use pocketmine\item\Durable; use pocketmine\item\Durable;
@ -32,6 +32,7 @@ use pocketmine\item\enchantment\Enchantment;
use pocketmine\item\FlintSteel; use pocketmine\item\FlintSteel;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\player\Player; use pocketmine\player\Player;
use pocketmine\utils\Random; use pocketmine\utils\Random;
use function cos; use function cos;
@ -93,10 +94,11 @@ class TNT extends Opaque{
$this->pos->getWorldNonNull()->setBlock($this->pos, VanillaBlocks::AIR()); $this->pos->getWorldNonNull()->setBlock($this->pos, VanillaBlocks::AIR());
$mot = (new Random())->nextSignedFloat() * M_PI * 2; $mot = (new Random())->nextSignedFloat() * M_PI * 2;
$nbt = EntityFactory::createBaseNBT($this->pos->add(0.5, 0, 0.5), new Vector3(-sin($mot) * 0.02, 0.2, -cos($mot) * 0.02));
$nbt->setShort("Fuse", $fuse);
$tnt = new PrimedTNT($this->pos->getWorldNonNull(), $nbt); $tnt = new PrimedTNT(Location::fromObject($this->pos->add(0.5, 0, 0.5), $this->pos->getWorldNonNull()), new CompoundTag());
$tnt->setFuse($fuse);
$tnt->setMotion(new Vector3(-sin($mot) * 0.02, 0.2, -cos($mot) * 0.02));
$tnt->spawnToAll(); $tnt->spawnToAll();
} }

View File

@ -23,13 +23,16 @@ declare(strict_types=1);
namespace pocketmine\block\utils; namespace pocketmine\block\utils;
use pocketmine\block\Block;
use pocketmine\block\BlockLegacyIds; use pocketmine\block\BlockLegacyIds;
use pocketmine\block\Fire; use pocketmine\block\Fire;
use pocketmine\block\Liquid; use pocketmine\block\Liquid;
use pocketmine\block\VanillaBlocks; use pocketmine\block\VanillaBlocks;
use pocketmine\entity\EntityFactory; use pocketmine\entity\Location;
use pocketmine\entity\object\FallingBlock; use pocketmine\entity\object\FallingBlock;
use pocketmine\math\Facing; use pocketmine\math\Facing;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\world\Position; use pocketmine\world\Position;
/** /**
@ -51,11 +54,10 @@ trait FallableTrait{
if($down->getId() === BlockLegacyIds::AIR or $down instanceof Liquid or $down instanceof Fire){ if($down->getId() === BlockLegacyIds::AIR or $down instanceof Liquid or $down instanceof Fire){
$pos->getWorldNonNull()->setBlock($pos, VanillaBlocks::AIR()); $pos->getWorldNonNull()->setBlock($pos, VanillaBlocks::AIR());
$nbt = EntityFactory::createBaseNBT($pos->add(0.5, 0, 0.5)); $block = $this;
$nbt->setInt("TileID", $this->getId()); if(!($block instanceof Block)) throw new AssumptionFailedError(__TRAIT__ . " should only be used by Blocks");
$nbt->setByte("Data", $this->getMeta());
$fall = new FallingBlock($pos->getWorldNonNull(), $nbt); $fall = new FallingBlock(Location::fromObject($pos->add(0.5, 0, 0.5), $pos->getWorldNonNull()), $block, new CompoundTag());
$fall->spawnToAll(); $fall->spawnToAll();
} }
} }

View File

@ -213,7 +213,7 @@ abstract class Entity{
/** @var int|null */ /** @var int|null */
protected $targetId = null; protected $targetId = null;
public function __construct(World $world, CompoundTag $nbt){ public function __construct(Location $location, CompoundTag $nbt){
$this->timings = Timings::getEntityTimings($this); $this->timings = Timings::getEntityTimings($this);
$this->temporalVector = new Vector3(); $this->temporalVector = new Vector3();
@ -223,14 +223,9 @@ abstract class Entity{
} }
$this->id = EntityFactory::nextRuntimeId(); $this->id = EntityFactory::nextRuntimeId();
$this->server = $world->getServer(); $this->server = $location->getWorldNonNull()->getServer();
/** @var float[] $pos */ $this->location = $location->asLocation();
$pos = $nbt->getListTag("Pos")->getAllValues();
/** @var float[] $rotation */
$rotation = $nbt->getListTag("Rotation")->getAllValues();
$this->location = new Location($pos[0], $pos[1], $pos[2], $rotation[0], $rotation[1], $world);
assert( assert(
!is_nan($this->location->x) and !is_infinite($this->location->x) and !is_nan($this->location->x) and !is_infinite($this->location->x) and
!is_nan($this->location->y) and !is_infinite($this->location->y) and !is_nan($this->location->y) and !is_infinite($this->location->y) and

View File

@ -26,6 +26,7 @@ namespace pocketmine\entity;
use DaveRandom\CallbackValidator\CallbackType; use DaveRandom\CallbackValidator\CallbackType;
use DaveRandom\CallbackValidator\ParameterType; use DaveRandom\CallbackValidator\ParameterType;
use DaveRandom\CallbackValidator\ReturnType; use DaveRandom\CallbackValidator\ReturnType;
use pocketmine\block\BlockFactory;
use pocketmine\entity\object\ExperienceOrb; use pocketmine\entity\object\ExperienceOrb;
use pocketmine\entity\object\FallingBlock; use pocketmine\entity\object\FallingBlock;
use pocketmine\entity\object\ItemEntity; use pocketmine\entity\object\ItemEntity;
@ -38,7 +39,11 @@ use pocketmine\entity\projectile\EnderPearl;
use pocketmine\entity\projectile\ExperienceBottle; use pocketmine\entity\projectile\ExperienceBottle;
use pocketmine\entity\projectile\Snowball; use pocketmine\entity\projectile\Snowball;
use pocketmine\entity\projectile\SplashPotion; use pocketmine\entity\projectile\SplashPotion;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\DoubleTag; use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\FloatTag; use pocketmine\nbt\tag\FloatTag;
@ -50,6 +55,7 @@ use pocketmine\utils\SingletonTrait;
use pocketmine\utils\Utils; use pocketmine\utils\Utils;
use pocketmine\world\World; use pocketmine\world\World;
use function array_keys; use function array_keys;
use function count;
use function in_array; use function in_array;
use function reset; use function reset;
@ -84,63 +90,85 @@ final class EntityFactory{
//TODO: index them by version to allow proper multi-save compatibility //TODO: index them by version to allow proper multi-save compatibility
$this->register(Arrow::class, function(World $world, CompoundTag $nbt) : Arrow{ $this->register(Arrow::class, function(World $world, CompoundTag $nbt) : Arrow{
return new Arrow($world, $nbt); return new Arrow(self::parseLocation($nbt, $world), null, false, $nbt); //TODO: missing critical flag
}, ['Arrow', 'minecraft:arrow'], EntityLegacyIds::ARROW); }, ['Arrow', 'minecraft:arrow'], EntityLegacyIds::ARROW);
$this->register(Egg::class, function(World $world, CompoundTag $nbt) : Egg{ $this->register(Egg::class, function(World $world, CompoundTag $nbt) : Egg{
return new Egg($world, $nbt); return new Egg(self::parseLocation($nbt, $world), null, $nbt);
}, ['Egg', 'minecraft:egg'], EntityLegacyIds::EGG); }, ['Egg', 'minecraft:egg'], EntityLegacyIds::EGG);
$this->register(EnderPearl::class, function(World $world, CompoundTag $nbt) : EnderPearl{ $this->register(EnderPearl::class, function(World $world, CompoundTag $nbt) : EnderPearl{
return new EnderPearl($world, $nbt); return new EnderPearl(self::parseLocation($nbt, $world), null, $nbt);
}, ['ThrownEnderpearl', 'minecraft:ender_pearl'], EntityLegacyIds::ENDER_PEARL); }, ['ThrownEnderpearl', 'minecraft:ender_pearl'], EntityLegacyIds::ENDER_PEARL);
$this->register(ExperienceBottle::class, function(World $world, CompoundTag $nbt) : ExperienceBottle{ $this->register(ExperienceBottle::class, function(World $world, CompoundTag $nbt) : ExperienceBottle{
return new ExperienceBottle($world, $nbt); return new ExperienceBottle(self::parseLocation($nbt, $world), null, $nbt);
}, ['ThrownExpBottle', 'minecraft:xp_bottle'], EntityLegacyIds::XP_BOTTLE); }, ['ThrownExpBottle', 'minecraft:xp_bottle'], EntityLegacyIds::XP_BOTTLE);
$this->register(ExperienceOrb::class, function(World $world, CompoundTag $nbt) : ExperienceOrb{ $this->register(ExperienceOrb::class, function(World $world, CompoundTag $nbt) : ExperienceOrb{
return new ExperienceOrb($world, $nbt); return new ExperienceOrb(self::parseLocation($nbt, $world), $nbt);
}, ['XPOrb', 'minecraft:xp_orb'], EntityLegacyIds::XP_ORB); }, ['XPOrb', 'minecraft:xp_orb'], EntityLegacyIds::XP_ORB);
$this->register(FallingBlock::class, function(World $world, CompoundTag $nbt) : FallingBlock{ $this->register(FallingBlock::class, function(World $world, CompoundTag $nbt) : FallingBlock{
return new FallingBlock($world, $nbt); return new FallingBlock(self::parseLocation($nbt, $world), FallingBlock::parseBlockNBT(BlockFactory::getInstance(), $nbt), $nbt);
}, ['FallingSand', 'minecraft:falling_block'], EntityLegacyIds::FALLING_BLOCK); }, ['FallingSand', 'minecraft:falling_block'], EntityLegacyIds::FALLING_BLOCK);
$this->register(ItemEntity::class, function(World $world, CompoundTag $nbt) : ItemEntity{ $this->register(ItemEntity::class, function(World $world, CompoundTag $nbt) : ItemEntity{
return new ItemEntity($world, $nbt); $itemTag = $nbt->getCompoundTag("Item");
if($itemTag === null){
throw new \UnexpectedValueException("Expected \"Item\" NBT tag not found");
}
$item = Item::nbtDeserialize($itemTag);
if($item->isNull()){
throw new \UnexpectedValueException("Item is invalid");
}
return new ItemEntity(self::parseLocation($nbt, $world), $item, $nbt);
}, ['Item', 'minecraft:item'], EntityLegacyIds::ITEM); }, ['Item', 'minecraft:item'], EntityLegacyIds::ITEM);
$this->register(Painting::class, function(World $world, CompoundTag $nbt) : Painting{ $this->register(Painting::class, function(World $world, CompoundTag $nbt) : Painting{
return new Painting($world, $nbt); $motive = PaintingMotive::getMotiveByName($nbt->getString("Motive"));
if($motive === null){
throw new \UnexpectedValueException("Unknown painting motive");
}
$blockIn = new Vector3($nbt->getInt("TileX"), $nbt->getInt("TileY"), $nbt->getInt("TileZ"));
if($nbt->hasTag("Direction", ByteTag::class)){
$facing = Painting::DATA_TO_FACING[$nbt->getByte("Direction")] ?? Facing::NORTH;
}elseif($nbt->hasTag("Facing", ByteTag::class)){
$facing = Painting::DATA_TO_FACING[$nbt->getByte("Facing")] ?? Facing::NORTH;
}else{
throw new \UnexpectedValueException("Missing facing info");
}
return new Painting(self::parseLocation($nbt, $world), $blockIn, $facing, $motive, $nbt);
}, ['Painting', 'minecraft:painting'], EntityLegacyIds::PAINTING); }, ['Painting', 'minecraft:painting'], EntityLegacyIds::PAINTING);
$this->register(PrimedTNT::class, function(World $world, CompoundTag $nbt) : PrimedTNT{ $this->register(PrimedTNT::class, function(World $world, CompoundTag $nbt) : PrimedTNT{
return new PrimedTNT($world, $nbt); return new PrimedTNT(self::parseLocation($nbt, $world), $nbt);
}, ['PrimedTnt', 'PrimedTNT', 'minecraft:tnt'], EntityLegacyIds::TNT); }, ['PrimedTnt', 'PrimedTNT', 'minecraft:tnt'], EntityLegacyIds::TNT);
$this->register(Snowball::class, function(World $world, CompoundTag $nbt) : Snowball{ $this->register(Snowball::class, function(World $world, CompoundTag $nbt) : Snowball{
return new Snowball($world, $nbt); return new Snowball(self::parseLocation($nbt, $world), null, $nbt);
}, ['Snowball', 'minecraft:snowball'], EntityLegacyIds::SNOWBALL); }, ['Snowball', 'minecraft:snowball'], EntityLegacyIds::SNOWBALL);
$this->register(SplashPotion::class, function(World $world, CompoundTag $nbt) : SplashPotion{ $this->register(SplashPotion::class, function(World $world, CompoundTag $nbt) : SplashPotion{
return new SplashPotion($world, $nbt); return new SplashPotion(self::parseLocation($nbt, $world), null, $nbt);
}, ['ThrownPotion', 'minecraft:potion', 'thrownpotion'], EntityLegacyIds::SPLASH_POTION); }, ['ThrownPotion', 'minecraft:potion', 'thrownpotion'], EntityLegacyIds::SPLASH_POTION);
$this->register(Squid::class, function(World $world, CompoundTag $nbt) : Squid{ $this->register(Squid::class, function(World $world, CompoundTag $nbt) : Squid{
return new Squid($world, $nbt); return new Squid(self::parseLocation($nbt, $world), $nbt);
}, ['Squid', 'minecraft:squid'], EntityLegacyIds::SQUID); }, ['Squid', 'minecraft:squid'], EntityLegacyIds::SQUID);
$this->register(Villager::class, function(World $world, CompoundTag $nbt) : Villager{ $this->register(Villager::class, function(World $world, CompoundTag $nbt) : Villager{
return new Villager($world, $nbt); return new Villager(self::parseLocation($nbt, $world), $nbt);
}, ['Villager', 'minecraft:villager'], EntityLegacyIds::VILLAGER); }, ['Villager', 'minecraft:villager'], EntityLegacyIds::VILLAGER);
$this->register(Zombie::class, function(World $world, CompoundTag $nbt) : Zombie{ $this->register(Zombie::class, function(World $world, CompoundTag $nbt) : Zombie{
return new Zombie($world, $nbt); return new Zombie(self::parseLocation($nbt, $world), $nbt);
}, ['Zombie', 'minecraft:zombie'], EntityLegacyIds::ZOMBIE); }, ['Zombie', 'minecraft:zombie'], EntityLegacyIds::ZOMBIE);
$this->register(Human::class, function(World $world, CompoundTag $nbt) : Human{ $this->register(Human::class, function(World $world, CompoundTag $nbt) : Human{
return new Human($world, $nbt); return new Human(self::parseLocation($nbt, $world), Human::parseSkinNBT($nbt), $nbt);
}, ['Human']); }, ['Human']);
PaintingMotive::init(); PaintingMotive::init();
@ -247,6 +275,37 @@ final class EntityFactory{
throw new \InvalidArgumentException("Entity $class is not registered"); throw new \InvalidArgumentException("Entity $class is not registered");
} }
public static function parseLocation(CompoundTag $nbt, World $world) : Location{
$pos = self::parseVec3($nbt, "Pos", false);
$yawPitch = $nbt->getTag("Rotation");
if(!($yawPitch instanceof ListTag) or $yawPitch->getTagType() !== NBT::TAG_Float){
throw new \UnexpectedValueException("'Rotation' should be a List<Float>");
}
$values = $yawPitch->getValue();
if(count($values) !== 2){
throw new \UnexpectedValueException("Expected exactly 2 entries for 'Rotation'");
}
return Location::fromObject($pos, $world, $values[0]->getValue(), $values[1]->getValue());
}
private static function parseVec3(CompoundTag $nbt, string $tagName, bool $optional) : Vector3{
$pos = $nbt->getTag($tagName);
if($pos === null and $optional){
return new Vector3(0, 0, 0);
}
if(!($pos instanceof ListTag) or $pos->getTagType() !== NBT::TAG_Double){
throw new \UnexpectedValueException("'$tagName' should be a List<Double>");
}
/** @var DoubleTag[] $values */
$values = $pos->getValue();
if(count($values) !== 3){
throw new \UnexpectedValueException("Expected exactly 3 entries in '$tagName' tag");
}
return new Vector3($values[0]->getValue(), $values[1]->getValue(), $values[2]->getValue());
}
/** /**
* Helper function which creates minimal NBT needed to spawn an entity. * Helper function which creates minimal NBT needed to spawn an entity.
*/ */

View File

@ -55,7 +55,6 @@ use pocketmine\player\Player;
use pocketmine\utils\Limits; use pocketmine\utils\Limits;
use pocketmine\uuid\UUID; use pocketmine\uuid\UUID;
use pocketmine\world\sound\TotemUseSound; use pocketmine\world\sound\TotemUseSound;
use pocketmine\world\World;
use function array_filter; use function array_filter;
use function array_merge; use function array_merge;
use function array_values; use function array_values;
@ -94,13 +93,21 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
protected $baseOffset = 1.62; protected $baseOffset = 1.62;
public function __construct(World $world, CompoundTag $nbt){ public function __construct(Location $location, Skin $skin, CompoundTag $nbt){
if($this->skin === null){ $this->skin = $skin;
parent::__construct($location, $nbt);
}
/**
* @throws InvalidSkinException
* @throws \UnexpectedValueException
*/
public static function parseSkinNBT(CompoundTag $nbt) : Skin{
$skinTag = $nbt->getCompoundTag("Skin"); $skinTag = $nbt->getCompoundTag("Skin");
if($skinTag === null){ if($skinTag === null){
throw new \InvalidStateException((new \ReflectionClass($this))->getShortName() . " must have a valid skin set"); throw new \UnexpectedValueException("Missing skin data");
} }
$this->skin = new Skin( //this throws if the skin is invalid return new Skin( //this throws if the skin is invalid
$skinTag->getString("Name"), $skinTag->getString("Name"),
$skinTag->hasTag("Data", StringTag::class) ? $skinTag->getString("Data") : $skinTag->getByteArray("Data"), //old data (this used to be saved as a StringTag in older versions of PM) $skinTag->hasTag("Data", StringTag::class) ? $skinTag->getString("Data") : $skinTag->getByteArray("Data"), //old data (this used to be saved as a StringTag in older versions of PM)
$skinTag->getByteArray("CapeData", ""), $skinTag->getByteArray("CapeData", ""),
@ -109,9 +116,6 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
); );
} }
parent::__construct($world, $nbt);
}
public function getUniqueId() : UUID{ public function getUniqueId() : UUID{
return $this->uuid; return $this->uuid;
} }

View File

@ -27,6 +27,7 @@ use pocketmine\block\Block;
use pocketmine\block\BlockFactory; use pocketmine\block\BlockFactory;
use pocketmine\block\utils\Fallable; use pocketmine\block\utils\Fallable;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\Location;
use pocketmine\event\entity\EntityBlockChangeEvent; use pocketmine\event\entity\EntityBlockChangeEvent;
use pocketmine\event\entity\EntityDamageEvent; use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\ByteTag;
@ -36,7 +37,6 @@ use pocketmine\network\mcpe\protocol\types\entity\EntityLegacyIds;
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataCollection; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataCollection;
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
use function abs; use function abs;
use function get_class;
class FallingBlock extends Entity{ class FallingBlock extends Entity{
@ -55,9 +55,12 @@ class FallingBlock extends Entity{
public $canCollide = false; public $canCollide = false;
protected function initEntity(CompoundTag $nbt) : void{ public function __construct(Location $location, Block $block, CompoundTag $nbt){
parent::initEntity($nbt); $this->block = $block;
parent::__construct($location, $nbt);
}
public static function parseBlockNBT(BlockFactory $factory, CompoundTag $nbt) : Block{
$blockId = 0; $blockId = 0;
//TODO: 1.8+ save format //TODO: 1.8+ save format
@ -68,12 +71,12 @@ class FallingBlock extends Entity{
} }
if($blockId === 0){ if($blockId === 0){
throw new \UnexpectedValueException("Invalid " . get_class($this) . " entity: block ID is 0 or missing"); throw new \UnexpectedValueException("Missing block info from NBT");
} }
$damage = $nbt->getByte("Data", 0); $damage = $nbt->getByte("Data", 0);
$this->block = BlockFactory::getInstance()->get($blockId, $damage); return $factory->get($blockId, $damage);
} }
public function canCollideWith(Entity $entity) : bool{ public function canCollideWith(Entity $entity) : bool{

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\entity\object; namespace pocketmine\entity\object;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\Location;
use pocketmine\event\entity\ItemDespawnEvent; use pocketmine\event\entity\ItemDespawnEvent;
use pocketmine\event\entity\ItemSpawnEvent; use pocketmine\event\entity\ItemSpawnEvent;
use pocketmine\event\inventory\InventoryPickupItemEvent; use pocketmine\event\inventory\InventoryPickupItemEvent;
@ -33,7 +34,6 @@ use pocketmine\network\mcpe\convert\TypeConverter;
use pocketmine\network\mcpe\protocol\AddItemActorPacket; use pocketmine\network\mcpe\protocol\AddItemActorPacket;
use pocketmine\network\mcpe\protocol\types\entity\EntityLegacyIds; use pocketmine\network\mcpe\protocol\types\entity\EntityLegacyIds;
use pocketmine\player\Player; use pocketmine\player\Player;
use function get_class;
use function max; use function max;
class ItemEntity extends Entity{ class ItemEntity extends Entity{
@ -65,6 +65,14 @@ class ItemEntity extends Entity{
/** @var int */ /** @var int */
protected $despawnDelay = self::DEFAULT_DESPAWN_DELAY; protected $despawnDelay = self::DEFAULT_DESPAWN_DELAY;
public function __construct(Location $location, Item $item, CompoundTag $nbt){
if($item->isNull()){
throw new \InvalidArgumentException("Item entity must have a non-air item with a count of at least 1");
}
$this->item = $item;
parent::__construct($location, $nbt);
}
protected function initEntity(CompoundTag $nbt) : void{ protected function initEntity(CompoundTag $nbt) : void{
parent::initEntity($nbt); parent::initEntity($nbt);
@ -81,16 +89,6 @@ class ItemEntity extends Entity{
$this->owner = $nbt->getString("Owner", $this->owner); $this->owner = $nbt->getString("Owner", $this->owner);
$this->thrower = $nbt->getString("Thrower", $this->thrower); $this->thrower = $nbt->getString("Thrower", $this->thrower);
$itemTag = $nbt->getCompoundTag("Item");
if($itemTag === null){
throw new \UnexpectedValueException("Invalid " . get_class($this) . " entity: expected \"Item\" NBT tag not found");
}
$this->item = Item::nbtDeserialize($itemTag);
if($this->item->isNull()){
throw new \UnexpectedValueException("Item for " . get_class($this) . " is invalid");
}
(new ItemSpawnEvent($this))->call(); (new ItemSpawnEvent($this))->call();
} }

View File

@ -25,12 +25,12 @@ namespace pocketmine\entity\object;
use pocketmine\block\VanillaBlocks; use pocketmine\block\VanillaBlocks;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\Location;
use pocketmine\event\entity\EntityDamageByEntityEvent; use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\item\VanillaItems; use pocketmine\item\VanillaItems;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing; use pocketmine\math\Facing;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\protocol\AddPaintingPacket; use pocketmine\network\mcpe\protocol\AddPaintingPacket;
use pocketmine\network\mcpe\protocol\types\entity\EntityLegacyIds; use pocketmine\network\mcpe\protocol\types\entity\EntityLegacyIds;
@ -42,7 +42,7 @@ use function ceil;
class Painting extends Entity{ class Painting extends Entity{
public static function getNetworkTypeId() : int{ return EntityLegacyIds::PAINTING; } public static function getNetworkTypeId() : int{ return EntityLegacyIds::PAINTING; }
private const DATA_TO_FACING = [ public const DATA_TO_FACING = [
0 => Facing::SOUTH, 0 => Facing::SOUTH,
1 => Facing::WEST, 1 => Facing::WEST,
2 => Facing::NORTH, 2 => Facing::NORTH,
@ -73,15 +73,11 @@ class Painting extends Entity{
/** @var string */ /** @var string */
protected $motive; protected $motive;
public function __construct(World $world, CompoundTag $nbt){ public function __construct(Location $location, Vector3 $blockIn, int $facing, PaintingMotive $motive, CompoundTag $nbt){
$this->motive = $nbt->getString("Motive"); $this->motive = $motive->getName(); //TODO: use motive directly
$this->blockIn = new Vector3($nbt->getInt("TileX"), $nbt->getInt("TileY"), $nbt->getInt("TileZ")); $this->blockIn = $blockIn->asVector3();
if($nbt->hasTag("Direction", ByteTag::class)){ $this->facing = $facing;
$this->facing = self::DATA_TO_FACING[$nbt->getByte("Direction")] ?? Facing::NORTH; parent::__construct($location, $nbt);
}elseif($nbt->hasTag("Facing", ByteTag::class)){
$this->facing = self::DATA_TO_FACING[$nbt->getByte("Facing")] ?? Facing::NORTH;
}
parent::__construct($world, $nbt);
} }
protected function initEntity(CompoundTag $nbt) : void{ protected function initEntity(CompoundTag $nbt) : void{

View File

@ -53,6 +53,17 @@ class PrimedTNT extends Entity implements Explosive{
public $canCollide = false; public $canCollide = false;
public function getFuse() : int{
return $this->fuse;
}
public function setFuse(int $fuse) : void{
if($fuse < 0 or $fuse > 32767){
throw new \InvalidArgumentException("Fuse must be in the range 0-32767");
}
$this->fuse = $fuse;
}
public function attack(EntityDamageEvent $source) : void{ public function attack(EntityDamageEvent $source) : void{
if($source->getCause() === EntityDamageEvent::CAUSE_VOID){ if($source->getCause() === EntityDamageEvent::CAUSE_VOID){
parent::attack($source); parent::attack($source);

View File

@ -26,6 +26,7 @@ namespace pocketmine\entity\projectile;
use pocketmine\block\Block; use pocketmine\block\Block;
use pocketmine\entity\animation\ArrowShakeAnimation; use pocketmine\entity\animation\ArrowShakeAnimation;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\Location;
use pocketmine\event\entity\ProjectileHitEvent; use pocketmine\event\entity\ProjectileHitEvent;
use pocketmine\event\inventory\InventoryPickupArrowEvent; use pocketmine\event\inventory\InventoryPickupArrowEvent;
use pocketmine\item\VanillaItems; use pocketmine\item\VanillaItems;
@ -36,7 +37,6 @@ use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataCollection;
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags;
use pocketmine\player\Player; use pocketmine\player\Player;
use pocketmine\world\sound\ArrowHitSound; use pocketmine\world\sound\ArrowHitSound;
use pocketmine\world\World;
use function mt_rand; use function mt_rand;
use function sqrt; use function sqrt;
@ -71,8 +71,8 @@ class Arrow extends Projectile{
/** @var bool */ /** @var bool */
protected $critical = false; protected $critical = false;
public function __construct(World $world, CompoundTag $nbt, ?Entity $shootingEntity = null, bool $critical = false){ public function __construct(Location $location, ?Entity $shootingEntity, bool $critical, CompoundTag $nbt){
parent::__construct($world, $nbt, $shootingEntity); parent::__construct($location, $shootingEntity, $nbt);
$this->setCritical($critical); $this->setCritical($critical);
} }

View File

@ -27,6 +27,7 @@ use pocketmine\block\Block;
use pocketmine\block\BlockFactory; use pocketmine\block\BlockFactory;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\Living; use pocketmine\entity\Living;
use pocketmine\entity\Location;
use pocketmine\event\entity\EntityCombustByEntityEvent; use pocketmine\event\entity\EntityCombustByEntityEvent;
use pocketmine\event\entity\EntityDamageByChildEntityEvent; use pocketmine\event\entity\EntityDamageByChildEntityEvent;
use pocketmine\event\entity\EntityDamageByEntityEvent; use pocketmine\event\entity\EntityDamageByEntityEvent;
@ -41,7 +42,6 @@ use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\IntTag;
use pocketmine\timings\Timings; use pocketmine\timings\Timings;
use pocketmine\world\World;
use function assert; use function assert;
use function atan2; use function atan2;
use function ceil; use function ceil;
@ -57,8 +57,8 @@ abstract class Projectile extends Entity{
/** @var Block|null */ /** @var Block|null */
protected $blockHit; protected $blockHit;
public function __construct(World $world, CompoundTag $nbt, ?Entity $shootingEntity = null){ public function __construct(Location $location, ?Entity $shootingEntity, CompoundTag $nbt){
parent::__construct($world, $nbt); parent::__construct($location, $nbt);
if($shootingEntity !== null){ if($shootingEntity !== null){
$this->setOwningEntity($shootingEntity); $this->setOwningEntity($shootingEntity);
} }

View File

@ -23,12 +23,13 @@ declare(strict_types=1);
namespace pocketmine\item; namespace pocketmine\item;
use pocketmine\entity\EntityFactory; use pocketmine\entity\Location;
use pocketmine\entity\projectile\Arrow as ArrowEntity; use pocketmine\entity\projectile\Arrow as ArrowEntity;
use pocketmine\entity\projectile\Projectile; use pocketmine\entity\projectile\Projectile;
use pocketmine\event\entity\EntityShootBowEvent; use pocketmine\event\entity\EntityShootBowEvent;
use pocketmine\event\entity\ProjectileLaunchEvent; use pocketmine\event\entity\ProjectileLaunchEvent;
use pocketmine\item\enchantment\Enchantment; use pocketmine\item\enchantment\Enchantment;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\player\Player; use pocketmine\player\Player;
use pocketmine\world\sound\BowShootSound; use pocketmine\world\sound\BowShootSound;
use function intdiv; use function intdiv;
@ -51,18 +52,18 @@ class Bow extends Tool{
} }
$location = $player->getLocation(); $location = $player->getLocation();
$nbt = EntityFactory::createBaseNBT(
$player->getEyePos(),
$player->getDirectionVector(),
($location->yaw > 180 ? 360 : 0) - $location->yaw,
-$location->pitch
);
$diff = $player->getItemUseDuration(); $diff = $player->getItemUseDuration();
$p = $diff / 20; $p = $diff / 20;
$baseForce = min((($p ** 2) + $p * 2) / 3, 1); $baseForce = min((($p ** 2) + $p * 2) / 3, 1);
$entity = new ArrowEntity($location->getWorldNonNull(), $nbt, $player, $baseForce >= 1); $entity = new ArrowEntity(Location::fromObject(
$player->getEyePos(),
$player->getWorld(),
($location->yaw > 180 ? 360 : 0) - $location->yaw,
-$location->pitch
), $player, $baseForce >= 1, new CompoundTag());
$entity->setMotion($player->getDirectionVector());
$infinity = $this->hasEnchantment(Enchantment::INFINITY()); $infinity = $this->hasEnchantment(Enchantment::INFINITY());
if($infinity){ if($infinity){

View File

@ -23,10 +23,10 @@ declare(strict_types=1);
namespace pocketmine\item; namespace pocketmine\item;
use pocketmine\entity\EntityFactory;
use pocketmine\entity\Location; use pocketmine\entity\Location;
use pocketmine\entity\projectile\Egg as EggEntity; use pocketmine\entity\projectile\Egg as EggEntity;
use pocketmine\entity\projectile\Throwable; use pocketmine\entity\projectile\Throwable;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\player\Player; use pocketmine\player\Player;
class Egg extends ProjectileItem{ class Egg extends ProjectileItem{
@ -36,11 +36,7 @@ class Egg extends ProjectileItem{
} }
protected function createEntity(Location $location, Player $thrower) : Throwable{ protected function createEntity(Location $location, Player $thrower) : Throwable{
return new EggEntity( return new EggEntity($location, $thrower, new CompoundTag());
$location->getWorldNonNull(),
EntityFactory::createBaseNBT($location, null, $location->yaw, $location->pitch),
$thrower
);
} }
public function getThrowForce() : float{ public function getThrowForce() : float{

View File

@ -23,10 +23,10 @@ declare(strict_types=1);
namespace pocketmine\item; namespace pocketmine\item;
use pocketmine\entity\EntityFactory;
use pocketmine\entity\Location; use pocketmine\entity\Location;
use pocketmine\entity\projectile\EnderPearl as EnderPearlEntity; use pocketmine\entity\projectile\EnderPearl as EnderPearlEntity;
use pocketmine\entity\projectile\Throwable; use pocketmine\entity\projectile\Throwable;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\player\Player; use pocketmine\player\Player;
class EnderPearl extends ProjectileItem{ class EnderPearl extends ProjectileItem{
@ -36,11 +36,7 @@ class EnderPearl extends ProjectileItem{
} }
protected function createEntity(Location $location, Player $thrower) : Throwable{ protected function createEntity(Location $location, Player $thrower) : Throwable{
return new EnderPearlEntity( return new EnderPearlEntity($location, $thrower, new CompoundTag());
$location->getWorldNonNull(),
EntityFactory::createBaseNBT($location, null, $location->yaw, $location->pitch),
$thrower
);
} }
public function getThrowForce() : float{ public function getThrowForce() : float{

View File

@ -23,20 +23,16 @@ declare(strict_types=1);
namespace pocketmine\item; namespace pocketmine\item;
use pocketmine\entity\EntityFactory;
use pocketmine\entity\Location; use pocketmine\entity\Location;
use pocketmine\entity\projectile\ExperienceBottle as ExperienceBottleEntity; use pocketmine\entity\projectile\ExperienceBottle as ExperienceBottleEntity;
use pocketmine\entity\projectile\Throwable; use pocketmine\entity\projectile\Throwable;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\player\Player; use pocketmine\player\Player;
class ExperienceBottle extends ProjectileItem{ class ExperienceBottle extends ProjectileItem{
protected function createEntity(Location $location, Player $thrower) : Throwable{ protected function createEntity(Location $location, Player $thrower) : Throwable{
return new ExperienceBottleEntity( return new ExperienceBottleEntity($location, $thrower, new CompoundTag());
$location->getWorldNonNull(),
EntityFactory::createBaseNBT($location, null, $location->yaw, $location->pitch),
$thrower
);
} }
public function getThrowForce() : float{ public function getThrowForce() : float{

View File

@ -30,7 +30,7 @@ use pocketmine\block\utils\SkullType;
use pocketmine\block\utils\TreeType; use pocketmine\block\utils\TreeType;
use pocketmine\block\VanillaBlocks; use pocketmine\block\VanillaBlocks;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\EntityFactory; use pocketmine\entity\Location;
use pocketmine\entity\Squid; use pocketmine\entity\Squid;
use pocketmine\entity\Villager; use pocketmine\entity\Villager;
use pocketmine\entity\Zombie; use pocketmine\entity\Zombie;
@ -319,17 +319,17 @@ class ItemFactory{
//TODO: the meta values should probably be hardcoded; they won't change, but the EntityLegacyIds might //TODO: the meta values should probably be hardcoded; they won't change, but the EntityLegacyIds might
$this->register(new class(ItemIds::SPAWN_EGG, EntityLegacyIds::ZOMBIE, "Zombie Spawn Egg") extends SpawnEgg{ $this->register(new class(ItemIds::SPAWN_EGG, EntityLegacyIds::ZOMBIE, "Zombie Spawn Egg") extends SpawnEgg{
protected function createEntity(World $world, Vector3 $pos, float $yaw, float $pitch) : Entity{ protected function createEntity(World $world, Vector3 $pos, float $yaw, float $pitch) : Entity{
return new Zombie($world, EntityFactory::createBaseNBT($pos, null, $yaw, $pitch)); return new Zombie(Location::fromObject($pos, $world, $yaw, $pitch), new CompoundTag());
} }
}); });
$this->register(new class(ItemIds::SPAWN_EGG, EntityLegacyIds::SQUID, "Squid Spawn Egg") extends SpawnEgg{ $this->register(new class(ItemIds::SPAWN_EGG, EntityLegacyIds::SQUID, "Squid Spawn Egg") extends SpawnEgg{
public function createEntity(World $world, Vector3 $pos, float $yaw, float $pitch) : Entity{ public function createEntity(World $world, Vector3 $pos, float $yaw, float $pitch) : Entity{
return new Squid($world, EntityFactory::createBaseNBT($pos, null, $yaw, $pitch)); return new Squid(Location::fromObject($pos, $world, $yaw, $pitch), new CompoundTag());
} }
}); });
$this->register(new class(ItemIds::SPAWN_EGG, EntityLegacyIds::VILLAGER, "Villager Spawn Egg") extends SpawnEgg{ $this->register(new class(ItemIds::SPAWN_EGG, EntityLegacyIds::VILLAGER, "Villager Spawn Egg") extends SpawnEgg{
public function createEntity(World $world, Vector3 $pos, float $yaw, float $pitch) : Entity{ public function createEntity(World $world, Vector3 $pos, float $yaw, float $pitch) : Entity{
return new Villager($world, EntityFactory::createBaseNBT($pos, null, $yaw, $pitch)); return new Villager(Location::fromObject($pos, $world, $yaw, $pitch), new CompoundTag());
} }
}); });
} }

View File

@ -24,11 +24,12 @@ declare(strict_types=1);
namespace pocketmine\item; namespace pocketmine\item;
use pocketmine\block\Block; use pocketmine\block\Block;
use pocketmine\entity\EntityFactory; use pocketmine\entity\Location;
use pocketmine\entity\object\Painting; use pocketmine\entity\object\Painting;
use pocketmine\entity\object\PaintingMotive; use pocketmine\entity\object\PaintingMotive;
use pocketmine\math\Facing; use pocketmine\math\Facing;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\player\Player; use pocketmine\player\Player;
use pocketmine\world\sound\PaintingPlaceSound; use pocketmine\world\sound\PaintingPlaceSound;
use function array_rand; use function array_rand;
@ -72,28 +73,10 @@ class PaintingItem extends Item{
/** @var PaintingMotive $motive */ /** @var PaintingMotive $motive */
$motive = $motives[array_rand($motives)]; $motive = $motives[array_rand($motives)];
static $directions = [
Facing::SOUTH => 0,
Facing::WEST => 1,
Facing::NORTH => 2,
Facing::EAST => 3
];
$direction = $directions[$face] ?? -1;
if($direction === -1){
return ItemUseResult::NONE();
}
$replacePos = $blockReplace->getPos(); $replacePos = $blockReplace->getPos();
$clickedPos = $blockClicked->getPos(); $clickedPos = $blockClicked->getPos();
$nbt = EntityFactory::createBaseNBT($replacePos, null, $direction * 90, 0);
$nbt->setByte("Direction", $direction);
$nbt->setString("Motive", $motive->getName());
$nbt->setInt("TileX", $clickedPos->getFloorX());
$nbt->setInt("TileY", $clickedPos->getFloorY());
$nbt->setInt("TileZ", $clickedPos->getFloorZ());
$entity = new Painting($replacePos->getWorldNonNull(), $nbt); $entity = new Painting(Location::fromObject($replacePos, $replacePos->getWorldNonNull()), $clickedPos, $face, $motive, new CompoundTag());
$this->pop(); $this->pop();
$entity->spawnToAll(); $entity->spawnToAll();

View File

@ -23,10 +23,10 @@ declare(strict_types=1);
namespace pocketmine\item; namespace pocketmine\item;
use pocketmine\entity\EntityFactory;
use pocketmine\entity\Location; use pocketmine\entity\Location;
use pocketmine\entity\projectile\Snowball as SnowballEntity; use pocketmine\entity\projectile\Snowball as SnowballEntity;
use pocketmine\entity\projectile\Throwable; use pocketmine\entity\projectile\Throwable;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\player\Player; use pocketmine\player\Player;
class Snowball extends ProjectileItem{ class Snowball extends ProjectileItem{
@ -36,11 +36,7 @@ class Snowball extends ProjectileItem{
} }
protected function createEntity(Location $location, Player $thrower) : Throwable{ protected function createEntity(Location $location, Player $thrower) : Throwable{
return new SnowballEntity( return new SnowballEntity($location, $thrower, new CompoundTag());
$location->getWorldNonNull(),
EntityFactory::createBaseNBT($location, null, $location->yaw, $location->pitch),
$thrower
);
} }
public function getThrowForce() : float{ public function getThrowForce() : float{

View File

@ -25,10 +25,8 @@ namespace pocketmine\item;
use pocketmine\block\Block; use pocketmine\block\Block;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\EntityFactory;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\player\Player; use pocketmine\player\Player;
use pocketmine\utils\Utils;
use pocketmine\world\World; use pocketmine\world\World;
use function lcg_value; use function lcg_value;

View File

@ -23,10 +23,10 @@ declare(strict_types=1);
namespace pocketmine\item; namespace pocketmine\item;
use pocketmine\entity\EntityFactory;
use pocketmine\entity\Location; use pocketmine\entity\Location;
use pocketmine\entity\projectile\SplashPotion as SplashPotionEntity; use pocketmine\entity\projectile\SplashPotion as SplashPotionEntity;
use pocketmine\entity\projectile\Throwable; use pocketmine\entity\projectile\Throwable;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\player\Player; use pocketmine\player\Player;
class SplashPotion extends ProjectileItem{ class SplashPotion extends ProjectileItem{
@ -36,12 +36,7 @@ class SplashPotion extends ProjectileItem{
} }
protected function createEntity(Location $location, Player $thrower) : Throwable{ protected function createEntity(Location $location, Player $thrower) : Throwable{
$projectile = new SplashPotionEntity( $projectile = new SplashPotionEntity($location, $thrower, new CompoundTag());
$location->getWorldNonNull(),
EntityFactory::createBaseNBT($location, null, $location->yaw, $location->pitch),
$thrower
);
$projectile->setPotionId($this->meta); $projectile->setPotionId($this->meta);
return $projectile; return $projectile;
} }

View File

@ -267,7 +267,6 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
$this->networkSession = $session; $this->networkSession = $session;
$this->playerInfo = $playerInfo; $this->playerInfo = $playerInfo;
$this->authenticated = $authenticated; $this->authenticated = $authenticated;
$this->skin = $this->playerInfo->getSkin();
$this->username = $username; $this->username = $username;
$this->displayName = $this->username; $this->displayName = $this->username;
@ -282,16 +281,11 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
$namedtag = $this->server->getOfflinePlayerData($this->username); //TODO: make this async $namedtag = $this->server->getOfflinePlayerData($this->username); //TODO: make this async
$spawnReset = false;
if($namedtag !== null and ($world = $this->server->getWorldManager()->getWorldByName($namedtag->getString("Level", ""))) !== null){ if($namedtag !== null and ($world = $this->server->getWorldManager()->getWorldByName($namedtag->getString("Level", ""))) !== null){
/** @var float[] $pos */ $spawn = EntityFactory::parseLocation($namedtag, $world);
$pos = $namedtag->getListTag("Pos")->getAllValues();
$spawn = new Vector3($pos[0], $pos[1], $pos[2]);
}else{ }else{
$world = $this->server->getWorldManager()->getDefaultWorld(); //TODO: default world might be null $world = $this->server->getWorldManager()->getDefaultWorld();
$spawn = $world->getSafeSpawn(); $spawn = Location::fromObject($world->getSafeSpawn(), $world);
$spawnReset = true;
} }
//load the spawn chunk so we can see the terrain //load the spawn chunk so we can see the terrain
@ -300,20 +294,13 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
$this->usedChunks[World::chunkHash($spawn->getFloorX() >> 4, $spawn->getFloorZ() >> 4)] = UsedChunkStatus::NEEDED(); $this->usedChunks[World::chunkHash($spawn->getFloorX() >> 4, $spawn->getFloorZ() >> 4)] = UsedChunkStatus::NEEDED();
if($namedtag === null){ if($namedtag === null){
$namedtag = EntityFactory::createBaseNBT($spawn); $namedtag = new CompoundTag();
$namedtag->setByte("OnGround", 1); //TODO: this hack is needed for new players in-air ticks - they don't get detected as on-ground until they move $namedtag->setByte("OnGround", 1); //TODO: this hack is needed for new players in-air ticks - they don't get detected as on-ground until they move
//TODO: old code had a TODO for SpawnForced //TODO: old code had a TODO for SpawnForced
}elseif($spawnReset){
$namedtag->setTag("Pos", new ListTag([
new DoubleTag($spawn->x),
new DoubleTag($spawn->y),
new DoubleTag($spawn->z)
]));
} }
parent::__construct($world, $namedtag); parent::__construct($spawn, $this->playerInfo->getSkin(), $namedtag);
$ev = new PlayerLoginEvent($this, "Plugin reason"); $ev = new PlayerLoginEvent($this, "Plugin reason");
$ev->call(); $ev->call();

View File

@ -34,7 +34,7 @@ use pocketmine\block\tile\Spawnable;
use pocketmine\block\tile\Tile; use pocketmine\block\tile\Tile;
use pocketmine\block\UnknownBlock; use pocketmine\block\UnknownBlock;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\EntityFactory; use pocketmine\entity\Location;
use pocketmine\entity\object\ExperienceOrb; use pocketmine\entity\object\ExperienceOrb;
use pocketmine\entity\object\ItemEntity; use pocketmine\entity\object\ItemEntity;
use pocketmine\event\block\BlockBreakEvent; use pocketmine\event\block\BlockBreakEvent;
@ -52,6 +52,7 @@ use pocketmine\item\ItemUseResult;
use pocketmine\item\LegacyStringToItemParser; use pocketmine\item\LegacyStringToItemParser;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\protocol\BlockActorDataPacket; use pocketmine\network\mcpe\protocol\BlockActorDataPacket;
use pocketmine\network\mcpe\protocol\ClientboundPacket; use pocketmine\network\mcpe\protocol\ClientboundPacket;
use pocketmine\network\mcpe\protocol\UpdateBlockPacket; use pocketmine\network\mcpe\protocol\UpdateBlockPacket;
@ -1385,16 +1386,13 @@ class World implements ChunkManager{
return null; return null;
} }
$motion = $motion ?? new Vector3(lcg_value() * 0.2 - 0.1, 0.2, lcg_value() * 0.2 - 0.1); $itemEntity = new ItemEntity(Location::fromObject($source, $this, lcg_value() * 360, 0), $item, new CompoundTag());
$nbt = EntityFactory::createBaseNBT($source, $motion, lcg_value() * 360, 0);
$nbt->setShort("Health", 5);
$nbt->setShort("PickupDelay", $delay);
$nbt->setTag("Item", $item->nbtSerialize());
$itemEntity = new ItemEntity($this, $nbt); $itemEntity->setPickupDelay($delay);
$itemEntity->setMotion($motion ?? new Vector3(lcg_value() * 0.2 - 0.1, 0.2, lcg_value() * 0.2 - 0.1));
$itemEntity->spawnToAll(); $itemEntity->spawnToAll();
return $itemEntity;
return $itemEntity;
} }
/** /**
@ -1407,16 +1405,12 @@ class World implements ChunkManager{
$orbs = []; $orbs = [];
foreach(ExperienceOrb::splitIntoOrbSizes($amount) as $split){ foreach(ExperienceOrb::splitIntoOrbSizes($amount) as $split){
$nbt = EntityFactory::createBaseNBT( $orb = new ExperienceOrb(Location::fromObject($pos, $this,lcg_value() * 360, 0), new CompoundTag());
$pos,
$this->temporalVector->setComponents((lcg_value() * 0.2 - 0.1) * 2, lcg_value() * 0.4, (lcg_value() * 0.2 - 0.1) * 2),
lcg_value() * 360,
0
);
$nbt->setShort(ExperienceOrb::TAG_VALUE_PC, $split);
$orb = new ExperienceOrb($this, $nbt); $orb->setXpValue($split);
$orb->setMotion($this->temporalVector->setComponents((lcg_value() * 0.2 - 0.1) * 2, lcg_value() * 0.4, (lcg_value() * 0.2 - 0.1) * 2));
$orb->spawnToAll(); $orb->spawnToAll();
$orbs[] = $orb; $orbs[] = $orb;
} }