73    public const TAG_IDENTIFIER = 
"identifier"; 
 
   74    public const TAG_LEGACY_ID = 
"id"; 
 
   80    private array $creationFuncs = [];
 
   85    private array $saveNames = [];
 
   87    public function __construct(){
 
   93        }, [
'AreaEffectCloud', 
'minecraft:area_effect_cloud']);
 
   96            return new Arrow(Helper::parseLocation($nbt, $world), 
null, $nbt->getByte(Arrow::TAG_CRIT, 0) === 1, $nbt);
 
   97        }, [
'Arrow', 
'minecraft:arrow']);
 
  100            return new Egg(Helper::parseLocation($nbt, $world), 
null, $nbt);
 
  101        }, [
'Egg', 
'minecraft:egg']);
 
  104            return new EndCrystal(Helper::parseLocation($nbt, $world), $nbt);
 
  105        }, [
'EnderCrystal', 
'minecraft:ender_crystal']);
 
  108            return new EnderPearl(Helper::parseLocation($nbt, $world), 
null, $nbt);
 
  109        }, [
'ThrownEnderpearl', 
'minecraft:ender_pearl']);
 
  112            return new ExperienceBottle(Helper::parseLocation($nbt, $world), 
null, $nbt);
 
  113        }, [
'ThrownExpBottle', 
'minecraft:xp_bottle']);
 
  117            if(($valuePcTag = $nbt->getTag(ExperienceOrb::TAG_VALUE_PC)) instanceof 
ShortTag){ 
 
  118                $value = $valuePcTag->getValue();
 
  119            }elseif(($valuePeTag = $nbt->getTag(ExperienceOrb::TAG_VALUE_PE)) instanceof 
IntTag){ 
 
  120                $value = $valuePeTag->getValue();
 
  123            return new ExperienceOrb(Helper::parseLocation($nbt, $world), $value, $nbt);
 
  124        }, [
'XPOrb', 
'minecraft:xp_orb']);
 
  127            return new FallingBlock(Helper::parseLocation($nbt, $world), FallingBlock::parseBlockNBT(RuntimeBlockStateRegistry::getInstance(), $nbt), $nbt);
 
  128        }, [
'FallingSand', 
'minecraft:falling_block']);
 
  131            return new IceBomb(Helper::parseLocation($nbt, $world), 
null, $nbt);
 
  132        }, [
'minecraft:ice_bomb']);
 
  135            $itemTag = $nbt->getCompoundTag(ItemEntity::TAG_ITEM);
 
  136            if($itemTag === 
null){
 
  140            $item = Item::nbtDeserialize($itemTag);
 
  144            return new ItemEntity(Helper::parseLocation($nbt, $world), $item, $nbt);
 
  145        }, [
'Item', 
'minecraft:item']);
 
  148            $motive = PaintingMotive::getMotiveByName($nbt->getString(Painting::TAG_MOTIVE));
 
  149            if($motive === 
null){
 
  152            $blockIn = 
new Vector3($nbt->getInt(Painting::TAG_TILE_X), $nbt->getInt(Painting::TAG_TILE_Y), $nbt->getInt(Painting::TAG_TILE_Z));
 
  153            if(($directionTag = $nbt->getTag(Painting::TAG_DIRECTION_BE)) instanceof 
ByteTag){
 
  154                $facing = Painting::DATA_TO_FACING[$directionTag->getValue()] ?? Facing::NORTH;
 
  155            }elseif(($facingTag = $nbt->getTag(Painting::TAG_FACING_JE)) instanceof 
ByteTag){
 
  156                $facing = Painting::DATA_TO_FACING[$facingTag->getValue()] ?? Facing::NORTH;
 
  161            return new Painting(Helper::parseLocation($nbt, $world), $blockIn, $facing, $motive, $nbt);
 
  162        }, [
'Painting', 
'minecraft:painting']);
 
  165            return new PrimedTNT(Helper::parseLocation($nbt, $world), $nbt);
 
  166        }, [
'PrimedTnt', 
'PrimedTNT', 
'minecraft:tnt']);
 
  169            return new Snowball(Helper::parseLocation($nbt, $world), 
null, $nbt);
 
  170        }, [
'Snowball', 
'minecraft:snowball']);
 
  173            $potionType = PotionTypeIdMap::getInstance()->fromId($nbt->getShort(SplashPotion::TAG_POTION_ID, PotionTypeIds::WATER));
 
  174            if($potionType === 
null){
 
  177            return new SplashPotion(Helper::parseLocation($nbt, $world), 
null, $potionType, $nbt);
 
  178        }, [
'ThrownPotion', 
'minecraft:potion', 
'thrownpotion']);
 
  181            $itemTag = $nbt->getCompoundTag(Trident::TAG_ITEM);
 
  182            if($itemTag === 
null){
 
  186            $item = Item::nbtDeserialize($itemTag);
 
  190            return new Trident(Helper::parseLocation($nbt, $world), $item, 
null, $nbt);
 
  193            'minecraft:thrown_trident', 
 
  199            return new Squid(Helper::parseLocation($nbt, $world), $nbt);
 
  200        }, [
'Squid', 
'minecraft:squid']);
 
  203            return new Villager(Helper::parseLocation($nbt, $world), $nbt);
 
  204        }, [
'Villager', 
'minecraft:villager']);
 
  207            return new Zombie(Helper::parseLocation($nbt, $world), $nbt);
 
  208        }, [
'Zombie', 
'minecraft:zombie']);
 
  228    public function register(
string $className, \Closure $creationFunc, array $saveNames) : void{
 
  229        if(count($saveNames) === 0){
 
  230            throw new \InvalidArgumentException(
"At least one save name must be provided");
 
  232        Utils::testValidInstance($className, Entity::class);
 
  239        foreach($saveNames as $name){
 
  240            $this->creationFuncs[$name] = $creationFunc;
 
  243        $this->saveNames[$className] = reset($saveNames);
 
 
  250        return isset($this->saveNames[$class]);
 
 
  261            $saveId = $nbt->getTag(self::TAG_IDENTIFIER) ?? $nbt->getTag(self::TAG_LEGACY_ID);
 
  264                $func = $this->creationFuncs[$saveId->getValue()] ?? 
null;
 
  265            }elseif($saveId instanceof 
IntTag){ 
 
  266                $stringId = LegacyEntityIdToStringIdMap::getInstance()->legacyToString($saveId->getValue() & 0xff);
 
  267                $func = $stringId !== 
null ? $this->creationFuncs[$stringId] ?? null : 
null;
 
  273            $entity = $func($world, $nbt);
 
  276        }
catch(NbtException $e){
 
  277            throw new SavedDataLoadingException($e->getMessage(), 0, $e);
 
 
  281    public function injectSaveId(
string $class, CompoundTag $saveData) : void{
 
  282        if(isset($this->saveNames[$class])){
 
  283            $saveData->setTag(self::TAG_IDENTIFIER, 
new StringTag($this->saveNames[$class]));
 
  285            throw new \InvalidArgumentException(
"Entity $class is not registered");
 
  293        if(isset($this->saveNames[$class])){
 
  294            return $this->saveNames[$class];
 
  296        throw new \InvalidArgumentException(
"Entity $class is not registered");