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");