isAbstract()){ $shortName = $class->getShortName(); if(!in_array($shortName, $saveNames, true)){ $saveNames[] = $shortName; } foreach($saveNames as $name){ self::$knownTiles[$name] = $className; } self::$saveNames[$className] = $saveNames; return true; } return false; } /** * Returns the short save name * @return string */ public static function getSaveId() : string{ if(!isset(self::$saveNames[static::class])){ throw new \InvalidStateException("Tile is not registered"); } reset(self::$saveNames[static::class]); return current(self::$saveNames[static::class]); } public function __construct(Level $level, CompoundTag $nbt){ $this->timings = Timings::getTileEntityTimings($this); $this->server = $level->getServer(); $this->name = ""; $this->id = Tile::$tileCount++; parent::__construct($nbt->getInt(self::TAG_X), $nbt->getInt(self::TAG_Y), $nbt->getInt(self::TAG_Z), $level); $this->readSaveData($nbt); $this->getLevel()->addTile($this); } public function getId() : int{ return $this->id; } /** * Reads additional data from the CompoundTag on tile creation. * * @param CompoundTag $nbt */ abstract protected function readSaveData(CompoundTag $nbt) : void; /** * Writes additional save data to a CompoundTag, not including generic things like ID and coordinates. * * @param CompoundTag $nbt */ abstract protected function writeSaveData(CompoundTag $nbt) : void; public function saveNBT() : CompoundTag{ $nbt = new CompoundTag(); $nbt->setString(self::TAG_ID, static::getSaveId()); $nbt->setInt(self::TAG_X, $this->x); $nbt->setInt(self::TAG_Y, $this->y); $nbt->setInt(self::TAG_Z, $this->z); $this->writeSaveData($nbt); return $nbt; } public function getCleanedNBT() : ?CompoundTag{ $this->writeSaveData($tag = new CompoundTag()); return $tag->getCount() > 0 ? $tag : null; } /** * Creates and returns a CompoundTag containing the necessary information to spawn a tile of this type. * * @param Vector3 $pos * @param int|null $face * @param Item|null $item * @param Player|null $player * * @return CompoundTag */ public static function createNBT(Vector3 $pos, ?int $face = null, ?Item $item = null, ?Player $player = null) : CompoundTag{ if(static::class === self::class){ throw new \BadMethodCallException(__METHOD__ . " must be called from the scope of a child class"); } $nbt = new CompoundTag("", [ new StringTag(self::TAG_ID, static::getSaveId()), new IntTag(self::TAG_X, (int) $pos->x), new IntTag(self::TAG_Y, (int) $pos->y), new IntTag(self::TAG_Z, (int) $pos->z) ]); static::createAdditionalNBT($nbt, $pos, $face, $item, $player); if($item !== null){ $customBlockData = $item->getCustomBlockData(); if($customBlockData !== null){ foreach($customBlockData as $customBlockDataTag){ $nbt->setTag(clone $customBlockDataTag); } } } return $nbt; } /** * Called by createNBT() to allow descendent classes to add their own base NBT using the parameters provided. * * @param CompoundTag $nbt * @param Vector3 $pos * @param int|null $face * @param Item|null $item * @param Player|null $player */ protected static function createAdditionalNBT(CompoundTag $nbt, Vector3 $pos, ?int $face = null, ?Item $item = null, ?Player $player = null) : void{ } /** * @return Block */ public function getBlock() : Block{ return $this->level->getBlockAt($this->x, $this->y, $this->z); } /** * @return bool */ public function onUpdate() : bool{ return false; } final public function scheduleUpdate() : void{ if($this->closed){ throw new \InvalidStateException("Cannot schedule update on garbage tile " . get_class($this)); } $this->level->updateTiles[$this->id] = $this; } public function isClosed() : bool{ return $this->closed; } public function __destruct(){ $this->close(); } public function close() : void{ if(!$this->closed){ $this->closed = true; if($this->isValid()){ $this->level->removeTile($this); $this->setLevel(null); } } } public function getName() : string{ return $this->name; } }