diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index ece48518e8..9126a382cd 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -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(); diff --git a/src/pocketmine/block/Fallable.php b/src/pocketmine/block/Fallable.php index 32dac2a970..1d8c693af7 100644 --- a/src/pocketmine/block/Fallable.php +++ b/src/pocketmine/block/Fallable.php @@ -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(); } } diff --git a/src/pocketmine/block/TNT.php b/src/pocketmine/block/TNT.php index 50b67f4173..773592452e 100644 --- a/src/pocketmine/block/TNT.php +++ b/src/pocketmine/block/TNT.php @@ -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(); } diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index 136b40bcb3..7c4e68d957 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -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()); diff --git a/src/pocketmine/entity/EntityFactory.php b/src/pocketmine/entity/EntityFactory.php new file mode 100644 index 0000000000..30f3f78ccc --- /dev/null +++ b/src/pocketmine/entity/EntityFactory.php @@ -0,0 +1,265 @@ + 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) + ]) + ]); + } +} diff --git a/src/pocketmine/item/Bow.php b/src/pocketmine/item/Bow.php index 5105434a55..9cc3cb44e0 100644 --- a/src/pocketmine/item/Bow.php +++ b/src/pocketmine/item/Bow.php @@ -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){ diff --git a/src/pocketmine/item/ItemFactory.php b/src/pocketmine/item/ItemFactory.php index 0fbafa9b77..fadadbad1c 100644 --- a/src/pocketmine/item/ItemFactory.php +++ b/src/pocketmine/item/ItemFactory.php @@ -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")); diff --git a/src/pocketmine/item/PaintingItem.php b/src/pocketmine/item/PaintingItem.php index 69f833031b..2856b7f925 100644 --- a/src/pocketmine/item/PaintingItem.php +++ b/src/pocketmine/item/PaintingItem.php @@ -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(); diff --git a/src/pocketmine/item/ProjectileItem.php b/src/pocketmine/item/ProjectileItem.php index 3a6316a713..14bb8e5875 100644 --- a/src/pocketmine/item/ProjectileItem.php +++ b/src/pocketmine/item/ProjectileItem.php @@ -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); diff --git a/src/pocketmine/item/SpawnEgg.php b/src/pocketmine/item/SpawnEgg.php index 8b25b82445..7c7d86d288 100644 --- a/src/pocketmine/item/SpawnEgg.php +++ b/src/pocketmine/item/SpawnEgg.php @@ -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; diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 0ba50b7947..374ece7d84 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -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; } diff --git a/src/pocketmine/level/format/Chunk.php b/src/pocketmine/level/format/Chunk.php index 2800d745d1..bba26c00a1 100644 --- a/src/pocketmine/level/format/Chunk.php +++ b/src/pocketmine/level/format/Chunk.php @@ -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; diff --git a/src/pocketmine/level/particle/FloatingTextParticle.php b/src/pocketmine/level/particle/FloatingTextParticle.php index 7423670484..727b75cc09 100644 --- a/src/pocketmine/level/particle/FloatingTextParticle.php +++ b/src/pocketmine/level/particle/FloatingTextParticle.php @@ -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;