getId(); if(!$override and self::isRegistered($id)){ throw new \RuntimeException("Trying to overwrite an already registered item"); } self::$list[self::getListOffset($id)] = clone $item; } /** * Returns an instance of the Item with the specified id, meta, count and NBT. * * @param int $id * @param int $meta * @param int $count * @param CompoundTag|string $tags * * @return Item * @throws \TypeError */ public static function get(int $id, int $meta = 0, int $count = 1, $tags = "") : Item{ if(!is_string($tags) and !($tags instanceof CompoundTag)){ throw new \TypeError("`tags` argument must be a string or CompoundTag instance, " . (is_object($tags) ? "instance of " . get_class($tags) : gettype($tags)) . " given"); } try{ /** @var Item|null $listed */ $listed = self::$list[self::getListOffset($id)]; if($listed !== null){ $item = clone $listed; }elseif($id < 256){ //intentionally includes negatives, for extended block IDs /* Blocks must have a damage value 0-15, but items can have damage value -1 to indicate that they are * crafting ingredients with any-damage. */ $item = new ItemBlock($id, $meta); }else{ $item = new Item($id, $meta); } }catch(\RuntimeException $e){ throw new \InvalidArgumentException("Item ID $id is invalid or out of bounds"); } $item->setDamage($meta); $item->setCount($count); $item->setCompoundTag($tags); return $item; } /** * Tries to parse the specified string into Item ID/meta identifiers, and returns Item instances it created. * * Example accepted formats: * - `diamond_pickaxe:5` * - `minecraft:string` * - `351:4 (lapis lazuli ID:meta)` * * If multiple item instances are to be created, their identifiers must be comma-separated, for example: * `diamond_pickaxe,wooden_shovel:18,iron_ingot` * * @param string $str * @param bool $multiple * * @return Item[]|Item * * @throws \InvalidArgumentException if the given string cannot be parsed as an item identifier */ public static function fromString(string $str, bool $multiple = false){ if($multiple){ $blocks = []; foreach(explode(",", $str) as $b){ $blocks[] = self::fromString($b, false); } return $blocks; }else{ $b = explode(":", str_replace([" ", "minecraft:"], ["_", ""], trim($str))); if(!isset($b[1])){ $meta = 0; }elseif(is_numeric($b[1])){ $meta = (int) $b[1]; }else{ throw new \InvalidArgumentException("Unable to parse \"" . $b[1] . "\" from \"" . $str . "\" as a valid meta value"); } if(is_numeric($b[0])){ $item = self::get((int) $b[0], $meta); }elseif(defined(ItemIds::class . "::" . strtoupper($b[0]))){ $item = self::get(constant(ItemIds::class . "::" . strtoupper($b[0])), $meta); }else{ throw new \InvalidArgumentException("Unable to resolve \"" . $str . "\" to a valid item"); } return $item; } } /** * Returns whether the specified item ID is already registered in the item factory. * * @param int $id * @return bool */ public static function isRegistered(int $id) : bool{ if($id < 256){ return BlockFactory::isRegistered($id); } return self::$list[self::getListOffset($id)] !== null; } private static function getListOffset(int $id) : int{ if($id < -0x8000 or $id > 0x7fff){ throw new \InvalidArgumentException("ID must be in range " . -0x8000 . " - " . 0x7fff); } return $id & 0xffff; } }