Introduce EntityFactory

This contains all of the static stuff that was previously embedded in the Entity static root. This solves a bunch of problems like circular dependencies between parent and child classes, encapsulating logic and reducing the size of the enormous Entity.php.
This commit is contained in:
Dylan K. Taylor 2019-01-06 23:54:29 +00:00
parent b1cef8509a
commit 7d827a1c65
13 changed files with 298 additions and 247 deletions

View File

@ -34,6 +34,7 @@ use pocketmine\command\ConsoleCommandSender;
use pocketmine\command\PluginIdentifiableCommand;
use pocketmine\command\SimpleCommandMap;
use pocketmine\entity\Entity;
use pocketmine\entity\EntityFactory;
use pocketmine\entity\Skin;
use pocketmine\event\HandlerList;
use pocketmine\event\level\LevelInitEvent;
@ -1695,7 +1696,7 @@ class Server{
$this->commandMap = new SimpleCommandMap($this);
Entity::init();
EntityFactory::init();
Tile::init();
BlockFactory::init();
BlockFactory::registerStaticRuntimeIdMappings();

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\entity\Entity;
use pocketmine\entity\EntityFactory;
use pocketmine\entity\object\FallingBlock;
use pocketmine\math\Facing;
@ -34,12 +34,12 @@ abstract class Fallable extends Solid{
if($down->getId() === self::AIR or $down instanceof Liquid or $down instanceof Fire){
$this->level->setBlock($this, BlockFactory::get(Block::AIR));
$nbt = Entity::createBaseNBT($this->add(0.5, 0, 0.5));
$nbt = EntityFactory::createBaseNBT($this->add(0.5, 0, 0.5));
$nbt->setInt("TileID", $this->getId());
$nbt->setByte("Data", $this->getDamage());
/** @var FallingBlock $fall */
$fall = Entity::create(FallingBlock::class, $this->getLevel(), $nbt);
$fall = EntityFactory::create(FallingBlock::class, $this->getLevel(), $nbt);
$fall->spawnToAll();
}
}

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\entity\Entity;
use pocketmine\entity\EntityFactory;
use pocketmine\entity\object\PrimedTNT;
use pocketmine\entity\projectile\Arrow;
use pocketmine\item\FlintSteel;
@ -75,11 +76,11 @@ class TNT extends Solid{
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR));
$mot = (new Random())->nextSignedFloat() * M_PI * 2;
$nbt = Entity::createBaseNBT($this->add(0.5, 0, 0.5), new Vector3(-sin($mot) * 0.02, 0.2, -cos($mot) * 0.02));
$nbt = EntityFactory::createBaseNBT($this->add(0.5, 0, 0.5), new Vector3(-sin($mot) * 0.02, 0.2, -cos($mot) * 0.02));
$nbt->setShort("Fuse", $fuse);
/** @var PrimedTNT $tnt */
$tnt = Entity::create(PrimedTNT::class, $this->getLevel(), $nbt);
$tnt = EntityFactory::create(PrimedTNT::class, $this->getLevel(), $nbt);
$tnt->spawnToAll();
}

View File

@ -28,18 +28,6 @@ namespace pocketmine\entity;
use pocketmine\block\Block;
use pocketmine\block\Water;
use pocketmine\entity\object\ExperienceOrb;
use pocketmine\entity\object\FallingBlock;
use pocketmine\entity\object\ItemEntity;
use pocketmine\entity\object\Painting;
use pocketmine\entity\object\PaintingMotive;
use pocketmine\entity\object\PrimedTNT;
use pocketmine\entity\projectile\Arrow;
use pocketmine\entity\projectile\Egg;
use pocketmine\entity\projectile\EnderPearl;
use pocketmine\entity\projectile\ExperienceBottle;
use pocketmine\entity\projectile\Snowball;
use pocketmine\entity\projectile\SplashPotion;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\EntityDespawnEvent;
use pocketmine\event\entity\EntityLevelChangeEvent;
@ -61,7 +49,6 @@ use pocketmine\metadata\MetadataValue;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\protocol\AddEntityPacket;
@ -76,23 +63,17 @@ use pocketmine\plugin\Plugin;
use pocketmine\Server;
use pocketmine\timings\Timings;
use pocketmine\timings\TimingsHandler;
use pocketmine\utils\Utils;
use function abs;
use function array_keys;
use function assert;
use function cos;
use function count;
use function current;
use function deg2rad;
use function floor;
use function get_class;
use function in_array;
use function is_a;
use function is_array;
use function is_infinite;
use function is_nan;
use function lcg_value;
use function reset;
use function sin;
use const M_PI_2;
@ -279,194 +260,6 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
public const DATA_FLAG_OVER_SCAFFOLDING = 69;
public const DATA_FLAG_FALL_THROUGH_SCAFFOLDING = 70;
public static $entityCount = 1;
/** @var Entity[] */
private static $knownEntities = [];
/** @var string[][] */
private static $saveNames = [];
/** @var string[] base class => currently used class for construction */
private static $classMapping = [];
/**
* Called on server startup to register default entity types.
*/
public static function init() : void{
//define legacy save IDs first - use them for saving for maximum compatibility with Minecraft PC
//TODO: index them by version to allow proper multi-save compatibility
self::register(Arrow::class, false, ['Arrow', 'minecraft:arrow']);
self::register(Egg::class, false, ['Egg', 'minecraft:egg']);
self::register(EnderPearl::class, false, ['ThrownEnderpearl', 'minecraft:ender_pearl']);
self::register(ExperienceBottle::class, false, ['ThrownExpBottle', 'minecraft:xp_bottle']);
self::register(ExperienceOrb::class, false, ['XPOrb', 'minecraft:xp_orb']);
self::register(FallingBlock::class, false, ['FallingSand', 'minecraft:falling_block']);
self::register(ItemEntity::class, false, ['Item', 'minecraft:item']);
self::register(Painting::class, false, ['Painting', 'minecraft:painting']);
self::register(PrimedTNT::class, false, ['PrimedTnt', 'PrimedTNT', 'minecraft:tnt']);
self::register(Snowball::class, false, ['Snowball', 'minecraft:snowball']);
self::register(SplashPotion::class, false, ['ThrownPotion', 'minecraft:potion', 'thrownpotion']);
self::register(Squid::class, false, ['Squid', 'minecraft:squid']);
self::register(Villager::class, false, ['Villager', 'minecraft:villager']);
self::register(Zombie::class, false, ['Zombie', 'minecraft:zombie']);
self::register(Human::class, true);
Attribute::init();
Effect::init();
PaintingMotive::init();
}
/**
* Creates an entity with the specified type, level and NBT, with optional additional arguments to pass to the
* entity's constructor.
*
* TODO: make this NBT-independent
*
* @param string $baseClass
* @param Level $level
* @param CompoundTag $nbt
* @param mixed ...$args
*
* @return Entity instanceof $baseClass
* @throws \InvalidArgumentException if the class doesn't exist or is not registered
*/
public static function create(string $baseClass, Level $level, CompoundTag $nbt, ...$args) : Entity{
if(isset(self::$classMapping[$baseClass])){
$class = self::$classMapping[$baseClass];
assert(is_a($class, $baseClass, true));
/**
* @var Entity $entity
* @see Entity::__construct()
*/
$entity = new $class($level, $nbt, ...$args);
return $entity;
}
throw new \InvalidArgumentException("Class $baseClass is not a registered entity");
}
/**
* Creates an entity from data stored on a chunk.
* @internal
*
* @param Level $level
* @param CompoundTag $nbt
*
* @return Entity|null
* @throws \RuntimeException
*/
public static function createFromData(Level $level, CompoundTag $nbt) : ?Entity{
$saveId = $nbt->getTag("id");
$baseClass = null;
if($saveId instanceof StringTag){
$baseClass = self::$knownEntities[$saveId->getValue()] ?? null;
}elseif($saveId instanceof IntTag){ //legacy MCPE format
$baseClass = self::$knownEntities[$saveId->getValue() & 0xff] ?? null;
}
if($baseClass === null){
return null;
}
$class = self::$classMapping[$baseClass];
assert(is_a($class, $baseClass, true));
/**
* @var Entity $entity
* @see Entity::__construct()
*/
$entity = new $class($level, $nbt);
return $entity;
}
/**
* Registers an entity type into the index.
*
* @param string $className Class that extends Entity
* @param bool $force Force registration even if the entity does not have a valid network ID
* @param string[] $saveNames An array of save names which this entity might be saved under. Defaults to the short name of the class itself if empty.
*
* NOTE: The first save name in the $saveNames array will be used when saving the entity to disk. The reflection
* name of the class will be appended to the end and only used if no other save names are specified.
*
* @throws \InvalidArgumentException
*/
public static function register(string $className, bool $force = false, array $saveNames = []) : void{
Utils::testValidInstance($className, Entity::class);
/** @var Entity $className */
if($className::NETWORK_ID !== -1){
self::$knownEntities[$className::NETWORK_ID] = $className;
}elseif(!$force){
throw new \InvalidArgumentException("Class $className does not declare a valid NETWORK_ID and not force-registering");
}
self::$classMapping[$className] = $className;
$shortName = (new \ReflectionClass($className))->getShortName();
if(!in_array($shortName, $saveNames, true)){
$saveNames[] = $shortName;
}
foreach($saveNames as $name){
self::$knownEntities[$name] = $className;
}
self::$saveNames[$className] = $saveNames;
}
/**
* Registers a class override for the given class. When a new entity is constructed using the factory, the new class
* will be used instead of the base class.
*
* @param string $baseClass Already-registered entity class to override
* @param string $newClass Class which extends the base class
*
* @throws \InvalidArgumentException
*/
public static function override(string $baseClass, string $newClass) : void{
if(!isset(self::$classMapping[$baseClass])){
throw new \InvalidArgumentException("Class $baseClass is not a registered entity");
}
Utils::testValidInstance($newClass, $baseClass);
self::$classMapping[$baseClass] = $newClass;
}
/**
* Returns an array of all registered entity classpaths.
*
* @return string[]
*/
public static function getKnownTypes() : array{
return array_keys(self::$classMapping);
}
/**
* Helper function which creates minimal NBT needed to spawn an entity.
*
* @param Vector3 $pos
* @param Vector3|null $motion
* @param float $yaw
* @param float $pitch
*
* @return CompoundTag
*/
public static function createBaseNBT(Vector3 $pos, ?Vector3 $motion = null, float $yaw = 0.0, float $pitch = 0.0) : CompoundTag{
return new CompoundTag("", [
new ListTag("Pos", [
new DoubleTag("", $pos->x),
new DoubleTag("", $pos->y),
new DoubleTag("", $pos->z)
]),
new ListTag("Motion", [
new DoubleTag("", $motion ? $motion->x : 0.0),
new DoubleTag("", $motion ? $motion->y : 0.0),
new DoubleTag("", $motion ? $motion->z : 0.0)
]),
new ListTag("Rotation", [
new FloatTag("", $yaw),
new FloatTag("", $pitch)
])
]);
}
/**
* @var Player[]
@ -591,7 +384,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
$this->eyeHeight = $this->height / 2 + 0.1;
}
$this->id = Entity::$entityCount++;
$this->id = EntityFactory::nextRuntimeId();
$this->server = $level->getServer();
/** @var float[] $pos */
@ -924,23 +717,10 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
$this->savedWithChunk = $value;
}
/**
* Returns the short save name
*
* @return string
*/
public function getSaveId() : string{
if(!isset(self::$saveNames[static::class])){
throw new \InvalidStateException("Entity is not registered");
}
reset(self::$saveNames[static::class]);
return current(self::$saveNames[static::class]);
}
public function saveNBT() : CompoundTag{
$nbt = new CompoundTag();
if(!($this instanceof Player)){
$nbt->setString("id", $this->getSaveId());
$nbt->setString("id", EntityFactory::getSaveId(get_class($this)));
if($this->getNameTag() !== ""){
$nbt->setString("CustomName", $this->getNameTag());

View File

@ -0,0 +1,265 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\entity;
use pocketmine\entity\object\ExperienceOrb;
use pocketmine\entity\object\FallingBlock;
use pocketmine\entity\object\ItemEntity;
use pocketmine\entity\object\Painting;
use pocketmine\entity\object\PaintingMotive;
use pocketmine\entity\object\PrimedTNT;
use pocketmine\entity\projectile\Arrow;
use pocketmine\entity\projectile\Egg;
use pocketmine\entity\projectile\EnderPearl;
use pocketmine\entity\projectile\ExperienceBottle;
use pocketmine\entity\projectile\Snowball;
use pocketmine\entity\projectile\SplashPotion;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\utils\Utils;
use function array_keys;
use function assert;
use function in_array;
use function is_a;
use function reset;
final class EntityFactory{
private static $entityCount = 1;
/** @var string[] base class => currently used class for construction */
private static $classMapping = [];
/** @var Entity[] */
private static $knownEntities = [];
/** @var string[][] */
private static $saveNames = [];
private function __construct(){
//NOOP
}
/**
* Called on server startup to register default entity types.
*/
public static function init() : void{
//define legacy save IDs first - use them for saving for maximum compatibility with Minecraft PC
//TODO: index them by version to allow proper multi-save compatibility
self::register(Arrow::class, false, ['Arrow', 'minecraft:arrow']);
self::register(Egg::class, false, ['Egg', 'minecraft:egg']);
self::register(EnderPearl::class, false, ['ThrownEnderpearl', 'minecraft:ender_pearl']);
self::register(ExperienceBottle::class, false, ['ThrownExpBottle', 'minecraft:xp_bottle']);
self::register(ExperienceOrb::class, false, ['XPOrb', 'minecraft:xp_orb']);
self::register(FallingBlock::class, false, ['FallingSand', 'minecraft:falling_block']);
self::register(ItemEntity::class, false, ['Item', 'minecraft:item']);
self::register(Painting::class, false, ['Painting', 'minecraft:painting']);
self::register(PrimedTNT::class, false, ['PrimedTnt', 'PrimedTNT', 'minecraft:tnt']);
self::register(Snowball::class, false, ['Snowball', 'minecraft:snowball']);
self::register(SplashPotion::class, false, ['ThrownPotion', 'minecraft:potion', 'thrownpotion']);
self::register(Squid::class, false, ['Squid', 'minecraft:squid']);
self::register(Villager::class, false, ['Villager', 'minecraft:villager']);
self::register(Zombie::class, false, ['Zombie', 'minecraft:zombie']);
self::register(Human::class, true);
Attribute::init();
Effect::init();
PaintingMotive::init();
}
/**
* Registers an entity type into the index.
*
* @param string $className Class that extends Entity
* @param bool $force Force registration even if the entity does not have a valid network ID
* @param string[] $saveNames An array of save names which this entity might be saved under. Defaults to the short name of the class itself if empty.
*
* NOTE: The first save name in the $saveNames array will be used when saving the entity to disk. The reflection
* name of the class will be appended to the end and only used if no other save names are specified.
*
* @throws \InvalidArgumentException
*/
public static function register(string $className, bool $force = false, array $saveNames = []) : void{
Utils::testValidInstance($className, Entity::class);
/** @var Entity $className */
if($className::NETWORK_ID !== -1){
self::$knownEntities[$className::NETWORK_ID] = $className;
}elseif(!$force){
throw new \InvalidArgumentException("Class $className does not declare a valid NETWORK_ID and not force-registering");
}
self::$classMapping[$className] = $className;
$shortName = (new \ReflectionClass($className))->getShortName();
if(!in_array($shortName, $saveNames, true)){
$saveNames[] = $shortName;
}
foreach($saveNames as $name){
self::$knownEntities[$name] = $className;
}
self::$saveNames[$className] = $saveNames;
}
/**
* Registers a class override for the given class. When a new entity is constructed using the factory, the new class
* will be used instead of the base class.
*
* @param string $baseClass Already-registered entity class to override
* @param string $newClass Class which extends the base class
*
* @throws \InvalidArgumentException
*/
public static function override(string $baseClass, string $newClass) : void{
if(!isset(self::$classMapping[$baseClass])){
throw new \InvalidArgumentException("Class $baseClass is not a registered entity");
}
Utils::testValidInstance($newClass, $baseClass);
self::$classMapping[$baseClass] = $newClass;
}
/**
* Returns an array of all registered entity classpaths.
*
* @return string[]
*/
public static function getKnownTypes() : array{
return array_keys(self::$classMapping);
}
/**
* Returns a new runtime entity ID for a new entity.
*
* @return int
*/
public static function nextRuntimeId() : int{
return self::$entityCount++;
}
/**
* Creates an entity with the specified type, level and NBT, with optional additional arguments to pass to the
* entity's constructor.
*
* TODO: make this NBT-independent
*
* @param string $baseClass
* @param Level $level
* @param CompoundTag $nbt
* @param mixed ...$args
*
* @return Entity instanceof $baseClass
* @throws \InvalidArgumentException if the class doesn't exist or is not registered
*/
public static function create(string $baseClass, Level $level, CompoundTag $nbt, ...$args) : Entity{
if(isset(self::$classMapping[$baseClass])){
$class = self::$classMapping[$baseClass];
assert(is_a($class, $baseClass, true));
/**
* @var Entity $entity
* @see Entity::__construct()
*/
$entity = new $class($level, $nbt, ...$args);
return $entity;
}
throw new \InvalidArgumentException("Class $baseClass is not a registered entity");
}
/**
* Creates an entity from data stored on a chunk.
* @internal
*
* @param Level $level
* @param CompoundTag $nbt
*
* @return Entity|null
* @throws \RuntimeException
*/
public static function createFromData(Level $level, CompoundTag $nbt) : ?Entity{
$saveId = $nbt->getTag("id");
$baseClass = null;
if($saveId instanceof StringTag){
$baseClass = self::$knownEntities[$saveId->getValue()] ?? null;
}elseif($saveId instanceof IntTag){ //legacy MCPE format
$baseClass = self::$knownEntities[$saveId->getValue() & 0xff] ?? null;
}
if($baseClass === null){
return null;
}
$class = self::$classMapping[$baseClass];
assert(is_a($class, $baseClass, true));
/**
* @var Entity $entity
* @see Entity::__construct()
*/
$entity = new $class($level, $nbt);
return $entity;
}
public static function getSaveId(string $class) : string{
if(isset(self::$saveNames[$class])){
return reset(self::$saveNames[$class]);
}
throw new \InvalidArgumentException("Entity $class is not registered");
}
/**
* Helper function which creates minimal NBT needed to spawn an entity.
*
* @param Vector3 $pos
* @param Vector3|null $motion
* @param float $yaw
* @param float $pitch
*
* @return CompoundTag
*/
public static function createBaseNBT(Vector3 $pos, ?Vector3 $motion = null, float $yaw = 0.0, float $pitch = 0.0) : CompoundTag{
return new CompoundTag("", [
new ListTag("Pos", [
new DoubleTag("", $pos->x),
new DoubleTag("", $pos->y),
new DoubleTag("", $pos->z)
]),
new ListTag("Motion", [
new DoubleTag("", $motion ? $motion->x : 0.0),
new DoubleTag("", $motion ? $motion->y : 0.0),
new DoubleTag("", $motion ? $motion->z : 0.0)
]),
new ListTag("Rotation", [
new FloatTag("", $yaw),
new FloatTag("", $pitch)
])
]);
}
}

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine\item;
use pocketmine\entity\Entity;
use pocketmine\entity\EntityFactory;
use pocketmine\entity\projectile\Arrow as ArrowEntity;
use pocketmine\entity\projectile\Projectile;
use pocketmine\event\entity\EntityShootBowEvent;
@ -53,7 +53,7 @@ class Bow extends Tool{
return false;
}
$nbt = Entity::createBaseNBT(
$nbt = EntityFactory::createBaseNBT(
$player->add(0, $player->getEyeHeight(), 0),
$player->getDirectionVector(),
($player->yaw > 180 ? 360 : 0) - $player->yaw,
@ -66,7 +66,7 @@ class Bow extends Tool{
$force = min((($p ** 2) + $p * 2) / 3, 1) * 2;
/** @var ArrowEntity $entity */
$entity = Entity::create(ArrowEntity::class, $player->getLevel(), $nbt, $player, $force == 2);
$entity = EntityFactory::create(ArrowEntity::class, $player->getLevel(), $nbt, $player, $force == 2);
$infinity = $this->hasEnchantment(Enchantment::INFINITY);
if($infinity){

View File

@ -25,7 +25,7 @@ namespace pocketmine\item;
use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\entity\Entity;
use pocketmine\entity\EntityFactory;
use pocketmine\entity\Living;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\tile\Skull;
@ -194,7 +194,7 @@ class ItemFactory{
//TODO: ENDER_EYE
self::registerItem(new Item(Item::GLISTERING_MELON, 0, "Glistering Melon"));
foreach(Entity::getKnownTypes() as $className){
foreach(EntityFactory::getKnownTypes() as $className){
/** @var Living|string $className */
if(is_a($className, Living::class, true) and $className::NETWORK_ID !== -1){
self::registerItem(new SpawnEgg(Item::SPAWN_EGG, $className::NETWORK_ID, $className, "Spawn Egg"));

View File

@ -24,7 +24,7 @@ declare(strict_types=1);
namespace pocketmine\item;
use pocketmine\block\Block;
use pocketmine\entity\Entity;
use pocketmine\entity\EntityFactory;
use pocketmine\entity\object\Painting;
use pocketmine\entity\object\PaintingMotive;
use pocketmine\math\Facing;
@ -86,7 +86,7 @@ class PaintingItem extends Item{
return false;
}
$nbt = Entity::createBaseNBT($blockReplace, null, $direction * 90, 0);
$nbt = EntityFactory::createBaseNBT($blockReplace, null, $direction * 90, 0);
$nbt->setByte("Direction", $direction);
$nbt->setString("Motive", $motive->getName());
$nbt->setInt("TileX", $blockClicked->getFloorX());
@ -94,7 +94,7 @@ class PaintingItem extends Item{
$nbt->setInt("TileZ", $blockClicked->getFloorZ());
/** @var Painting $entity */
$entity = Entity::create(Painting::class, $blockReplace->getLevel(), $nbt);
$entity = EntityFactory::create(Painting::class, $blockReplace->getLevel(), $nbt);
$this->pop();
$entity->spawnToAll();

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine\item;
use pocketmine\entity\Entity;
use pocketmine\entity\EntityFactory;
use pocketmine\entity\EntityIds;
use pocketmine\entity\projectile\Throwable;
use pocketmine\event\entity\ProjectileLaunchEvent;
@ -54,14 +54,14 @@ abstract class ProjectileItem extends Item{
}
public function onClickAir(Player $player, Vector3 $directionVector) : bool{
$nbt = Entity::createBaseNBT($player->add(0, $player->getEyeHeight(), 0), $directionVector, $player->yaw, $player->pitch);
$nbt = EntityFactory::createBaseNBT($player->add(0, $player->getEyeHeight(), 0), $directionVector, $player->yaw, $player->pitch);
$this->addExtraTags($nbt);
$class = $this->getProjectileEntityClass();
Utils::testValidInstance($class, Throwable::class);
/** @var Throwable $projectile */
$projectile = Entity::create($class, $player->getLevel(), $nbt, $player);
$projectile = EntityFactory::create($class, $player->getLevel(), $nbt, $player);
$projectile->setMotion($projectile->getMotion()->multiply($this->getThrowForce()));
$projectileEv = new ProjectileLaunchEvent($projectile);

View File

@ -25,6 +25,7 @@ namespace pocketmine\item;
use pocketmine\block\Block;
use pocketmine\entity\Entity;
use pocketmine\entity\EntityFactory;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\utils\Utils;
@ -50,13 +51,13 @@ class SpawnEgg extends Item{
}
public function onActivate(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : bool{
$nbt = Entity::createBaseNBT($blockReplace->add(0.5, 0, 0.5), null, lcg_value() * 360, 0);
$nbt = EntityFactory::createBaseNBT($blockReplace->add(0.5, 0, 0.5), null, lcg_value() * 360, 0);
if($this->hasCustomName()){
$nbt->setString("CustomName", $this->getCustomName());
}
$entity = Entity::create($this->entityClass, $player->getLevel(), $nbt);
$entity = EntityFactory::create($this->entityClass, $player->getLevel(), $nbt);
$this->pop();
$entity->spawnToAll();
return true;

View File

@ -30,6 +30,7 @@ use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\block\UnknownBlock;
use pocketmine\entity\Entity;
use pocketmine\entity\EntityFactory;
use pocketmine\entity\object\ExperienceOrb;
use pocketmine\entity\object\ItemEntity;
use pocketmine\event\block\BlockBreakEvent;
@ -1630,13 +1631,13 @@ class Level implements ChunkManager, Metadatable{
$itemTag->setName("Item");
if(!$item->isNull()){
$nbt = Entity::createBaseNBT($source, $motion, lcg_value() * 360, 0);
$nbt = EntityFactory::createBaseNBT($source, $motion, lcg_value() * 360, 0);
$nbt->setShort("Health", 5);
$nbt->setShort("PickupDelay", $delay);
$nbt->setTag($itemTag);
/** @var ItemEntity $itemEntity */
$itemEntity = Entity::create(ItemEntity::class, $this, $nbt);
$itemEntity = EntityFactory::create(ItemEntity::class, $this, $nbt);
$itemEntity->spawnToAll();
return $itemEntity;
}
@ -1656,7 +1657,7 @@ class Level implements ChunkManager, Metadatable{
$orbs = [];
foreach(ExperienceOrb::splitIntoOrbSizes($amount) as $split){
$nbt = Entity::createBaseNBT(
$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,
@ -1665,7 +1666,7 @@ class Level implements ChunkManager, Metadatable{
$nbt->setShort(ExperienceOrb::TAG_VALUE_PC, $split);
/** @var ExperienceOrb $orb */
$orb = Entity::create(ExperienceOrb::class, $this, $nbt);
$orb = EntityFactory::create(ExperienceOrb::class, $this, $nbt);
$orb->spawnToAll();
$orbs[] = $orb;
}

View File

@ -28,6 +28,7 @@ namespace pocketmine\level\format;
use pocketmine\block\BlockFactory;
use pocketmine\entity\Entity;
use pocketmine\entity\EntityFactory;
use pocketmine\level\Level;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\Player;
@ -601,7 +602,7 @@ class Chunk{
foreach($this->NBTentities as $nbt){
if($nbt instanceof CompoundTag){
try{
$entity = Entity::createFromData($level, $nbt);
$entity = EntityFactory::createFromData($level, $nbt);
if(!($entity instanceof Entity)){
$changed = true;
continue;

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\level\particle;
use pocketmine\entity\Entity;
use pocketmine\entity\EntityFactory;
use pocketmine\entity\Skin;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
@ -80,7 +81,7 @@ class FloatingTextParticle extends Particle{
$p = [];
if($this->entityId === null){
$this->entityId = Entity::$entityCount++;
$this->entityId = EntityFactory::nextRuntimeId();
}else{
$pk0 = new RemoveEntityPacket();
$pk0->entityUniqueId = $this->entityId;