mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-26 05:14:05 +00:00
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:
parent
3f135da704
commit
1205432c34
@ -24,7 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\EntityFactory;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\entity\object\PrimedTNT;
|
||||
use pocketmine\entity\projectile\Arrow;
|
||||
use pocketmine\item\Durable;
|
||||
@ -32,6 +32,7 @@ use pocketmine\item\enchantment\Enchantment;
|
||||
use pocketmine\item\FlintSteel;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\Random;
|
||||
use function cos;
|
||||
@ -93,10 +94,11 @@ class TNT extends Opaque{
|
||||
$this->pos->getWorldNonNull()->setBlock($this->pos, VanillaBlocks::AIR());
|
||||
|
||||
$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();
|
||||
}
|
||||
|
||||
|
@ -23,13 +23,16 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\BlockLegacyIds;
|
||||
use pocketmine\block\Fire;
|
||||
use pocketmine\block\Liquid;
|
||||
use pocketmine\block\VanillaBlocks;
|
||||
use pocketmine\entity\EntityFactory;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\entity\object\FallingBlock;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
/**
|
||||
@ -51,11 +54,10 @@ trait FallableTrait{
|
||||
if($down->getId() === BlockLegacyIds::AIR or $down instanceof Liquid or $down instanceof Fire){
|
||||
$pos->getWorldNonNull()->setBlock($pos, VanillaBlocks::AIR());
|
||||
|
||||
$nbt = EntityFactory::createBaseNBT($pos->add(0.5, 0, 0.5));
|
||||
$nbt->setInt("TileID", $this->getId());
|
||||
$nbt->setByte("Data", $this->getMeta());
|
||||
$block = $this;
|
||||
if(!($block instanceof Block)) throw new AssumptionFailedError(__TRAIT__ . " should only be used by Blocks");
|
||||
|
||||
$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();
|
||||
}
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ abstract class Entity{
|
||||
/** @var int|null */
|
||||
protected $targetId = null;
|
||||
|
||||
public function __construct(World $world, CompoundTag $nbt){
|
||||
public function __construct(Location $location, CompoundTag $nbt){
|
||||
$this->timings = Timings::getEntityTimings($this);
|
||||
|
||||
$this->temporalVector = new Vector3();
|
||||
@ -223,14 +223,9 @@ abstract class Entity{
|
||||
}
|
||||
|
||||
$this->id = EntityFactory::nextRuntimeId();
|
||||
$this->server = $world->getServer();
|
||||
$this->server = $location->getWorldNonNull()->getServer();
|
||||
|
||||
/** @var float[] $pos */
|
||||
$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);
|
||||
$this->location = $location->asLocation();
|
||||
assert(
|
||||
!is_nan($this->location->x) and !is_infinite($this->location->x) and
|
||||
!is_nan($this->location->y) and !is_infinite($this->location->y) and
|
||||
|
@ -26,6 +26,7 @@ namespace pocketmine\entity;
|
||||
use DaveRandom\CallbackValidator\CallbackType;
|
||||
use DaveRandom\CallbackValidator\ParameterType;
|
||||
use DaveRandom\CallbackValidator\ReturnType;
|
||||
use pocketmine\block\BlockFactory;
|
||||
use pocketmine\entity\object\ExperienceOrb;
|
||||
use pocketmine\entity\object\FallingBlock;
|
||||
use pocketmine\entity\object\ItemEntity;
|
||||
@ -38,7 +39,11 @@ use pocketmine\entity\projectile\EnderPearl;
|
||||
use pocketmine\entity\projectile\ExperienceBottle;
|
||||
use pocketmine\entity\projectile\Snowball;
|
||||
use pocketmine\entity\projectile\SplashPotion;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\NBT;
|
||||
use pocketmine\nbt\tag\ByteTag;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\DoubleTag;
|
||||
use pocketmine\nbt\tag\FloatTag;
|
||||
@ -50,6 +55,7 @@ use pocketmine\utils\SingletonTrait;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\world\World;
|
||||
use function array_keys;
|
||||
use function count;
|
||||
use function in_array;
|
||||
use function reset;
|
||||
|
||||
@ -84,63 +90,85 @@ final class EntityFactory{
|
||||
//TODO: index them by version to allow proper multi-save compatibility
|
||||
|
||||
$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);
|
||||
|
||||
$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);
|
||||
|
||||
$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);
|
||||
|
||||
$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);
|
||||
|
||||
$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);
|
||||
|
||||
$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);
|
||||
|
||||
$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);
|
||||
|
||||
$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);
|
||||
|
||||
$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);
|
||||
|
||||
$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);
|
||||
|
||||
$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);
|
||||
|
||||
$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);
|
||||
|
||||
$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);
|
||||
|
||||
$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);
|
||||
|
||||
$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']);
|
||||
|
||||
PaintingMotive::init();
|
||||
@ -247,6 +275,37 @@ final class EntityFactory{
|
||||
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.
|
||||
*/
|
||||
|
@ -55,7 +55,6 @@ use pocketmine\player\Player;
|
||||
use pocketmine\utils\Limits;
|
||||
use pocketmine\uuid\UUID;
|
||||
use pocketmine\world\sound\TotemUseSound;
|
||||
use pocketmine\world\World;
|
||||
use function array_filter;
|
||||
use function array_merge;
|
||||
use function array_values;
|
||||
@ -94,13 +93,21 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
|
||||
protected $baseOffset = 1.62;
|
||||
|
||||
public function __construct(World $world, CompoundTag $nbt){
|
||||
if($this->skin === null){
|
||||
public function __construct(Location $location, Skin $skin, CompoundTag $nbt){
|
||||
$this->skin = $skin;
|
||||
parent::__construct($location, $nbt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidSkinException
|
||||
* @throws \UnexpectedValueException
|
||||
*/
|
||||
public static function parseSkinNBT(CompoundTag $nbt) : Skin{
|
||||
$skinTag = $nbt->getCompoundTag("Skin");
|
||||
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->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", ""),
|
||||
@ -109,9 +116,6 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
);
|
||||
}
|
||||
|
||||
parent::__construct($world, $nbt);
|
||||
}
|
||||
|
||||
public function getUniqueId() : UUID{
|
||||
return $this->uuid;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ use pocketmine\block\Block;
|
||||
use pocketmine\block\BlockFactory;
|
||||
use pocketmine\block\utils\Fallable;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\event\entity\EntityBlockChangeEvent;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
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\EntityMetadataProperties;
|
||||
use function abs;
|
||||
use function get_class;
|
||||
|
||||
class FallingBlock extends Entity{
|
||||
|
||||
@ -55,9 +55,12 @@ class FallingBlock extends Entity{
|
||||
|
||||
public $canCollide = false;
|
||||
|
||||
protected function initEntity(CompoundTag $nbt) : void{
|
||||
parent::initEntity($nbt);
|
||||
public function __construct(Location $location, Block $block, CompoundTag $nbt){
|
||||
$this->block = $block;
|
||||
parent::__construct($location, $nbt);
|
||||
}
|
||||
|
||||
public static function parseBlockNBT(BlockFactory $factory, CompoundTag $nbt) : Block{
|
||||
$blockId = 0;
|
||||
|
||||
//TODO: 1.8+ save format
|
||||
@ -68,12 +71,12 @@ class FallingBlock extends Entity{
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
$this->block = BlockFactory::getInstance()->get($blockId, $damage);
|
||||
return $factory->get($blockId, $damage);
|
||||
}
|
||||
|
||||
public function canCollideWith(Entity $entity) : bool{
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\entity\object;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\event\entity\ItemDespawnEvent;
|
||||
use pocketmine\event\entity\ItemSpawnEvent;
|
||||
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\types\entity\EntityLegacyIds;
|
||||
use pocketmine\player\Player;
|
||||
use function get_class;
|
||||
use function max;
|
||||
|
||||
class ItemEntity extends Entity{
|
||||
@ -65,6 +65,14 @@ class ItemEntity extends Entity{
|
||||
/** @var int */
|
||||
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{
|
||||
parent::initEntity($nbt);
|
||||
|
||||
@ -81,16 +89,6 @@ class ItemEntity extends Entity{
|
||||
$this->owner = $nbt->getString("Owner", $this->owner);
|
||||
$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();
|
||||
}
|
||||
|
||||
|
@ -25,12 +25,12 @@ namespace pocketmine\entity\object;
|
||||
|
||||
use pocketmine\block\VanillaBlocks;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\event\entity\EntityDamageByEntityEvent;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\ByteTag;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\network\mcpe\protocol\AddPaintingPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityLegacyIds;
|
||||
@ -42,7 +42,7 @@ use function ceil;
|
||||
class Painting extends Entity{
|
||||
public static function getNetworkTypeId() : int{ return EntityLegacyIds::PAINTING; }
|
||||
|
||||
private const DATA_TO_FACING = [
|
||||
public const DATA_TO_FACING = [
|
||||
0 => Facing::SOUTH,
|
||||
1 => Facing::WEST,
|
||||
2 => Facing::NORTH,
|
||||
@ -73,15 +73,11 @@ class Painting extends Entity{
|
||||
/** @var string */
|
||||
protected $motive;
|
||||
|
||||
public function __construct(World $world, CompoundTag $nbt){
|
||||
$this->motive = $nbt->getString("Motive");
|
||||
$this->blockIn = new Vector3($nbt->getInt("TileX"), $nbt->getInt("TileY"), $nbt->getInt("TileZ"));
|
||||
if($nbt->hasTag("Direction", ByteTag::class)){
|
||||
$this->facing = self::DATA_TO_FACING[$nbt->getByte("Direction")] ?? Facing::NORTH;
|
||||
}elseif($nbt->hasTag("Facing", ByteTag::class)){
|
||||
$this->facing = self::DATA_TO_FACING[$nbt->getByte("Facing")] ?? Facing::NORTH;
|
||||
}
|
||||
parent::__construct($world, $nbt);
|
||||
public function __construct(Location $location, Vector3 $blockIn, int $facing, PaintingMotive $motive, CompoundTag $nbt){
|
||||
$this->motive = $motive->getName(); //TODO: use motive directly
|
||||
$this->blockIn = $blockIn->asVector3();
|
||||
$this->facing = $facing;
|
||||
parent::__construct($location, $nbt);
|
||||
}
|
||||
|
||||
protected function initEntity(CompoundTag $nbt) : void{
|
||||
|
@ -53,6 +53,17 @@ class PrimedTNT extends Entity implements Explosive{
|
||||
|
||||
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{
|
||||
if($source->getCause() === EntityDamageEvent::CAUSE_VOID){
|
||||
parent::attack($source);
|
||||
|
@ -26,6 +26,7 @@ namespace pocketmine\entity\projectile;
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\entity\animation\ArrowShakeAnimation;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\event\entity\ProjectileHitEvent;
|
||||
use pocketmine\event\inventory\InventoryPickupArrowEvent;
|
||||
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\player\Player;
|
||||
use pocketmine\world\sound\ArrowHitSound;
|
||||
use pocketmine\world\World;
|
||||
use function mt_rand;
|
||||
use function sqrt;
|
||||
|
||||
@ -71,8 +71,8 @@ class Arrow extends Projectile{
|
||||
/** @var bool */
|
||||
protected $critical = false;
|
||||
|
||||
public function __construct(World $world, CompoundTag $nbt, ?Entity $shootingEntity = null, bool $critical = false){
|
||||
parent::__construct($world, $nbt, $shootingEntity);
|
||||
public function __construct(Location $location, ?Entity $shootingEntity, bool $critical, CompoundTag $nbt){
|
||||
parent::__construct($location, $shootingEntity, $nbt);
|
||||
$this->setCritical($critical);
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ use pocketmine\block\Block;
|
||||
use pocketmine\block\BlockFactory;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\Living;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\event\entity\EntityCombustByEntityEvent;
|
||||
use pocketmine\event\entity\EntityDamageByChildEntityEvent;
|
||||
use pocketmine\event\entity\EntityDamageByEntityEvent;
|
||||
@ -41,7 +42,6 @@ use pocketmine\nbt\tag\ByteTag;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\world\World;
|
||||
use function assert;
|
||||
use function atan2;
|
||||
use function ceil;
|
||||
@ -57,8 +57,8 @@ abstract class Projectile extends Entity{
|
||||
/** @var Block|null */
|
||||
protected $blockHit;
|
||||
|
||||
public function __construct(World $world, CompoundTag $nbt, ?Entity $shootingEntity = null){
|
||||
parent::__construct($world, $nbt);
|
||||
public function __construct(Location $location, ?Entity $shootingEntity, CompoundTag $nbt){
|
||||
parent::__construct($location, $nbt);
|
||||
if($shootingEntity !== null){
|
||||
$this->setOwningEntity($shootingEntity);
|
||||
}
|
||||
|
@ -23,12 +23,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\item;
|
||||
|
||||
use pocketmine\entity\EntityFactory;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\entity\projectile\Arrow as ArrowEntity;
|
||||
use pocketmine\entity\projectile\Projectile;
|
||||
use pocketmine\event\entity\EntityShootBowEvent;
|
||||
use pocketmine\event\entity\ProjectileLaunchEvent;
|
||||
use pocketmine\item\enchantment\Enchantment;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\sound\BowShootSound;
|
||||
use function intdiv;
|
||||
@ -51,18 +52,18 @@ class Bow extends Tool{
|
||||
}
|
||||
|
||||
$location = $player->getLocation();
|
||||
$nbt = EntityFactory::createBaseNBT(
|
||||
$player->getEyePos(),
|
||||
$player->getDirectionVector(),
|
||||
($location->yaw > 180 ? 360 : 0) - $location->yaw,
|
||||
-$location->pitch
|
||||
);
|
||||
|
||||
$diff = $player->getItemUseDuration();
|
||||
$p = $diff / 20;
|
||||
$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());
|
||||
if($infinity){
|
||||
|
@ -23,10 +23,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\item;
|
||||
|
||||
use pocketmine\entity\EntityFactory;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\entity\projectile\Egg as EggEntity;
|
||||
use pocketmine\entity\projectile\Throwable;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
class Egg extends ProjectileItem{
|
||||
@ -36,11 +36,7 @@ class Egg extends ProjectileItem{
|
||||
}
|
||||
|
||||
protected function createEntity(Location $location, Player $thrower) : Throwable{
|
||||
return new EggEntity(
|
||||
$location->getWorldNonNull(),
|
||||
EntityFactory::createBaseNBT($location, null, $location->yaw, $location->pitch),
|
||||
$thrower
|
||||
);
|
||||
return new EggEntity($location, $thrower, new CompoundTag());
|
||||
}
|
||||
|
||||
public function getThrowForce() : float{
|
||||
|
@ -23,10 +23,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\item;
|
||||
|
||||
use pocketmine\entity\EntityFactory;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\entity\projectile\EnderPearl as EnderPearlEntity;
|
||||
use pocketmine\entity\projectile\Throwable;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
class EnderPearl extends ProjectileItem{
|
||||
@ -36,11 +36,7 @@ class EnderPearl extends ProjectileItem{
|
||||
}
|
||||
|
||||
protected function createEntity(Location $location, Player $thrower) : Throwable{
|
||||
return new EnderPearlEntity(
|
||||
$location->getWorldNonNull(),
|
||||
EntityFactory::createBaseNBT($location, null, $location->yaw, $location->pitch),
|
||||
$thrower
|
||||
);
|
||||
return new EnderPearlEntity($location, $thrower, new CompoundTag());
|
||||
}
|
||||
|
||||
public function getThrowForce() : float{
|
||||
|
@ -23,20 +23,16 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\item;
|
||||
|
||||
use pocketmine\entity\EntityFactory;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\entity\projectile\ExperienceBottle as ExperienceBottleEntity;
|
||||
use pocketmine\entity\projectile\Throwable;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
class ExperienceBottle extends ProjectileItem{
|
||||
|
||||
protected function createEntity(Location $location, Player $thrower) : Throwable{
|
||||
return new ExperienceBottleEntity(
|
||||
$location->getWorldNonNull(),
|
||||
EntityFactory::createBaseNBT($location, null, $location->yaw, $location->pitch),
|
||||
$thrower
|
||||
);
|
||||
return new ExperienceBottleEntity($location, $thrower, new CompoundTag());
|
||||
}
|
||||
|
||||
public function getThrowForce() : float{
|
||||
|
@ -30,7 +30,7 @@ use pocketmine\block\utils\SkullType;
|
||||
use pocketmine\block\utils\TreeType;
|
||||
use pocketmine\block\VanillaBlocks;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\EntityFactory;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\entity\Squid;
|
||||
use pocketmine\entity\Villager;
|
||||
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
|
||||
$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{
|
||||
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{
|
||||
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{
|
||||
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());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -24,11 +24,12 @@ declare(strict_types=1);
|
||||
namespace pocketmine\item;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\entity\EntityFactory;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\entity\object\Painting;
|
||||
use pocketmine\entity\object\PaintingMotive;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\sound\PaintingPlaceSound;
|
||||
use function array_rand;
|
||||
@ -72,28 +73,10 @@ class PaintingItem extends Item{
|
||||
/** @var PaintingMotive $motive */
|
||||
$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();
|
||||
$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();
|
||||
$entity->spawnToAll();
|
||||
|
||||
|
@ -23,10 +23,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\item;
|
||||
|
||||
use pocketmine\entity\EntityFactory;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\entity\projectile\Snowball as SnowballEntity;
|
||||
use pocketmine\entity\projectile\Throwable;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
class Snowball extends ProjectileItem{
|
||||
@ -36,11 +36,7 @@ class Snowball extends ProjectileItem{
|
||||
}
|
||||
|
||||
protected function createEntity(Location $location, Player $thrower) : Throwable{
|
||||
return new SnowballEntity(
|
||||
$location->getWorldNonNull(),
|
||||
EntityFactory::createBaseNBT($location, null, $location->yaw, $location->pitch),
|
||||
$thrower
|
||||
);
|
||||
return new SnowballEntity($location, $thrower, new CompoundTag());
|
||||
}
|
||||
|
||||
public function getThrowForce() : float{
|
||||
|
@ -25,10 +25,8 @@ namespace pocketmine\item;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\EntityFactory;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\world\World;
|
||||
use function lcg_value;
|
||||
|
||||
|
@ -23,10 +23,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\item;
|
||||
|
||||
use pocketmine\entity\EntityFactory;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\entity\projectile\SplashPotion as SplashPotionEntity;
|
||||
use pocketmine\entity\projectile\Throwable;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
class SplashPotion extends ProjectileItem{
|
||||
@ -36,12 +36,7 @@ class SplashPotion extends ProjectileItem{
|
||||
}
|
||||
|
||||
protected function createEntity(Location $location, Player $thrower) : Throwable{
|
||||
$projectile = new SplashPotionEntity(
|
||||
$location->getWorldNonNull(),
|
||||
EntityFactory::createBaseNBT($location, null, $location->yaw, $location->pitch),
|
||||
$thrower
|
||||
);
|
||||
|
||||
$projectile = new SplashPotionEntity($location, $thrower, new CompoundTag());
|
||||
$projectile->setPotionId($this->meta);
|
||||
return $projectile;
|
||||
}
|
||||
|
@ -267,7 +267,6 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
|
||||
$this->networkSession = $session;
|
||||
$this->playerInfo = $playerInfo;
|
||||
$this->authenticated = $authenticated;
|
||||
$this->skin = $this->playerInfo->getSkin();
|
||||
|
||||
$this->username = $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
|
||||
|
||||
$spawnReset = false;
|
||||
|
||||
if($namedtag !== null and ($world = $this->server->getWorldManager()->getWorldByName($namedtag->getString("Level", ""))) !== null){
|
||||
/** @var float[] $pos */
|
||||
$pos = $namedtag->getListTag("Pos")->getAllValues();
|
||||
$spawn = new Vector3($pos[0], $pos[1], $pos[2]);
|
||||
$spawn = EntityFactory::parseLocation($namedtag, $world);
|
||||
}else{
|
||||
$world = $this->server->getWorldManager()->getDefaultWorld(); //TODO: default world might be null
|
||||
$spawn = $world->getSafeSpawn();
|
||||
$spawnReset = true;
|
||||
$world = $this->server->getWorldManager()->getDefaultWorld();
|
||||
$spawn = Location::fromObject($world->getSafeSpawn(), $world);
|
||||
}
|
||||
|
||||
//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();
|
||||
|
||||
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
|
||||
//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->call();
|
||||
|
@ -34,7 +34,7 @@ use pocketmine\block\tile\Spawnable;
|
||||
use pocketmine\block\tile\Tile;
|
||||
use pocketmine\block\UnknownBlock;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\EntityFactory;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\entity\object\ExperienceOrb;
|
||||
use pocketmine\entity\object\ItemEntity;
|
||||
use pocketmine\event\block\BlockBreakEvent;
|
||||
@ -52,6 +52,7 @@ use pocketmine\item\ItemUseResult;
|
||||
use pocketmine\item\LegacyStringToItemParser;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\network\mcpe\protocol\BlockActorDataPacket;
|
||||
use pocketmine\network\mcpe\protocol\ClientboundPacket;
|
||||
use pocketmine\network\mcpe\protocol\UpdateBlockPacket;
|
||||
@ -1385,16 +1386,13 @@ class World implements ChunkManager{
|
||||
return null;
|
||||
}
|
||||
|
||||
$motion = $motion ?? new Vector3(lcg_value() * 0.2 - 0.1, 0.2, lcg_value() * 0.2 - 0.1);
|
||||
$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(Location::fromObject($source, $this, lcg_value() * 360, 0), $item, new CompoundTag());
|
||||
|
||||
$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();
|
||||
return $itemEntity;
|
||||
|
||||
return $itemEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1407,16 +1405,12 @@ class World implements ChunkManager{
|
||||
$orbs = [];
|
||||
|
||||
foreach(ExperienceOrb::splitIntoOrbSizes($amount) as $split){
|
||||
$nbt = EntityFactory::createBaseNBT(
|
||||
$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(Location::fromObject($pos, $this,lcg_value() * 360, 0), new CompoundTag());
|
||||
|
||||
$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();
|
||||
|
||||
$orbs[] = $orb;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user