All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.nukkit.item.Item Maven / Gradle / Ivy

Go to download

A Minecraft Bedrock Edition server software implementation made in Java from scratch which supports all new features.

There is a newer version: 1.6.0.1-PN
Show newest version
package cn.nukkit.item;

import cn.nukkit.Player;
import cn.nukkit.Server;
import cn.nukkit.api.PowerNukkitDifference;
import cn.nukkit.api.PowerNukkitOnly;
import cn.nukkit.api.Since;
import cn.nukkit.block.Block;
import cn.nukkit.block.BlockID;
import cn.nukkit.blockproperty.UnknownRuntimeIdException;
import cn.nukkit.blockproperty.exception.InvalidBlockPropertyMetaException;
import cn.nukkit.blockstate.BlockState;
import cn.nukkit.blockstate.BlockStateRegistry;
import cn.nukkit.blockstate.exception.InvalidBlockStateException;
import cn.nukkit.entity.Entity;
import cn.nukkit.inventory.Fuel;
import cn.nukkit.item.enchantment.Enchantment;
import cn.nukkit.level.Level;
import cn.nukkit.math.BlockFace;
import cn.nukkit.math.Vector3;
import cn.nukkit.nbt.NBTIO;
import cn.nukkit.nbt.tag.CompoundTag;
import cn.nukkit.nbt.tag.ListTag;
import cn.nukkit.nbt.tag.StringTag;
import cn.nukkit.nbt.tag.Tag;
import cn.nukkit.utils.Binary;
import cn.nukkit.utils.Config;
import cn.nukkit.utils.MainLogger;
import cn.nukkit.utils.Utils;
import io.netty.util.internal.EmptyArrays;
import it.unimi.dsi.fastutil.ints.Int2IntArrayMap;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import lombok.extern.log4j.Log4j2;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.reflect.Modifier;
import java.nio.ByteOrder;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author MagicDroidX (Nukkit Project)
 */
@Log4j2
public class Item implements Cloneable, BlockID, ItemID {
    //Normal Item IDs
    
    @PowerNukkitOnly
    @Since("1.4.0.0-PN")
    public static final Item[] EMPTY_ARRAY = new Item[0];
    
    protected static String UNKNOWN_STR = "Unknown";
    public static Class[] list = null;
    
    private static Map itemIds = Arrays.stream(ItemID.class.getDeclaredFields())
            .filter(field-> field.getModifiers() == (Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL))
            .filter(field -> field.getType().equals(int.class))
            .collect(Collectors.toMap(
                    field -> field.getName().toLowerCase(),
                    field -> {
                        try {
                            return field.getInt(null);
                        } catch (IllegalAccessException e) {
                            throw new InternalError(e);
                        }
                    },
                    (e1, e2) -> e1, LinkedHashMap::new
            ));

    private static Map blockIds = Arrays.stream(BlockID.class.getDeclaredFields())
            .filter(field-> field.getModifiers() == (Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL))
            .filter(field -> field.getType().equals(int.class))
            .collect(Collectors.toMap(
                    field -> field.getName().toLowerCase(),
                    field -> {
                        try {
                            int blockId = field.getInt(null);
                            if (blockId > 255) {
                                return 255 - blockId;
                            }
                            return blockId;
                        } catch (IllegalAccessException e) {
                            throw new InternalError(e);
                        }
                    },
                    (e1, e2) -> e1, LinkedHashMap::new
            ));

    protected Block block = null;
    protected final int id;
    protected int meta;
    protected boolean hasMeta = true;
    private byte[] tags = EmptyArrays.EMPTY_BYTES;
    private transient CompoundTag cachedNBT = null;
    public int count;
    protected int durability = 0;
    protected String name;

    public Item(int id) {
        this(id, 0, 1, UNKNOWN_STR);
    }

    public Item(int id, Integer meta) {
        this(id, meta, 1, UNKNOWN_STR);
    }

    public Item(int id, Integer meta, int count) {
        this(id, meta, count, UNKNOWN_STR);
    }

    public Item(int id, Integer meta, int count, String name) {
        //this.id = id & 0xffff;
        this.id = id;
        if (meta != null && meta >= 0) {
            this.meta = meta & 0xffff;
        } else {
            this.hasMeta = false;
        }
        this.count = count;
        this.name = name != null? name.intern() : null;
        /*f (this.block != null && this.id <= 0xff && Block.list[id] != null) { //probably useless
            this.block = Block.get(this.id, this.meta);
            this.name = this.block.getName();
        }*/
    }

    public boolean hasMeta() {
        return hasMeta;
    }

    public boolean canBeActivated() {
        return false;
    }

    public static void init() {
        if (list == null) {
            list = new Class[65535];
            list[IRON_SHOVEL] = ItemShovelIron.class; //256
            list[IRON_PICKAXE] = ItemPickaxeIron.class; //257
            list[IRON_AXE] = ItemAxeIron.class; //258
            list[FLINT_AND_STEEL] = ItemFlintSteel.class; //259
            list[APPLE] = ItemApple.class; //260
            list[BOW] = ItemBow.class; //261
            list[ARROW] = ItemArrow.class; //262
            list[COAL] = ItemCoal.class; //263
            list[DIAMOND] = ItemDiamond.class; //264
            list[IRON_INGOT] = ItemIngotIron.class; //265
            list[GOLD_INGOT] = ItemIngotGold.class; //266
            list[IRON_SWORD] = ItemSwordIron.class; //267
            list[WOODEN_SWORD] = ItemSwordWood.class; //268
            list[WOODEN_SHOVEL] = ItemShovelWood.class; //269
            list[WOODEN_PICKAXE] = ItemPickaxeWood.class; //270
            list[WOODEN_AXE] = ItemAxeWood.class; //271
            list[STONE_SWORD] = ItemSwordStone.class; //272
            list[STONE_SHOVEL] = ItemShovelStone.class; //273
            list[STONE_PICKAXE] = ItemPickaxeStone.class; //274
            list[STONE_AXE] = ItemAxeStone.class; //275
            list[DIAMOND_SWORD] = ItemSwordDiamond.class; //276
            list[DIAMOND_SHOVEL] = ItemShovelDiamond.class; //277
            list[DIAMOND_PICKAXE] = ItemPickaxeDiamond.class; //278
            list[DIAMOND_AXE] = ItemAxeDiamond.class; //279
            list[STICK] = ItemStick.class; //280
            list[BOWL] = ItemBowl.class; //281
            list[MUSHROOM_STEW] = ItemMushroomStew.class; //282
            list[GOLD_SWORD] = ItemSwordGold.class; //283
            list[GOLD_SHOVEL] = ItemShovelGold.class; //284
            list[GOLD_PICKAXE] = ItemPickaxeGold.class; //285
            list[GOLD_AXE] = ItemAxeGold.class; //286
            list[STRING] = ItemString.class; //287
            list[FEATHER] = ItemFeather.class; //288
            list[GUNPOWDER] = ItemGunpowder.class; //289
            list[WOODEN_HOE] = ItemHoeWood.class; //290
            list[STONE_HOE] = ItemHoeStone.class; //291
            list[IRON_HOE] = ItemHoeIron.class; //292
            list[DIAMOND_HOE] = ItemHoeDiamond.class; //293
            list[GOLD_HOE] = ItemHoeGold.class; //294
            list[WHEAT_SEEDS] = ItemSeedsWheat.class; //295
            list[WHEAT] = ItemWheat.class; //296
            list[BREAD] = ItemBread.class; //297
            list[LEATHER_CAP] = ItemHelmetLeather.class; //298
            list[LEATHER_TUNIC] = ItemChestplateLeather.class; //299
            list[LEATHER_PANTS] = ItemLeggingsLeather.class; //300
            list[LEATHER_BOOTS] = ItemBootsLeather.class; //301
            list[CHAIN_HELMET] = ItemHelmetChain.class; //302
            list[CHAIN_CHESTPLATE] = ItemChestplateChain.class; //303
            list[CHAIN_LEGGINGS] = ItemLeggingsChain.class; //304
            list[CHAIN_BOOTS] = ItemBootsChain.class; //305
            list[IRON_HELMET] = ItemHelmetIron.class; //306
            list[IRON_CHESTPLATE] = ItemChestplateIron.class; //307
            list[IRON_LEGGINGS] = ItemLeggingsIron.class; //308
            list[IRON_BOOTS] = ItemBootsIron.class; //309
            list[DIAMOND_HELMET] = ItemHelmetDiamond.class; //310
            list[DIAMOND_CHESTPLATE] = ItemChestplateDiamond.class; //311
            list[DIAMOND_LEGGINGS] = ItemLeggingsDiamond.class; //312
            list[DIAMOND_BOOTS] = ItemBootsDiamond.class; //313
            list[GOLD_HELMET] = ItemHelmetGold.class; //314
            list[GOLD_CHESTPLATE] = ItemChestplateGold.class; //315
            list[GOLD_LEGGINGS] = ItemLeggingsGold.class; //316
            list[GOLD_BOOTS] = ItemBootsGold.class; //317
            list[FLINT] = ItemFlint.class; //318
            list[RAW_PORKCHOP] = ItemPorkchopRaw.class; //319
            list[COOKED_PORKCHOP] = ItemPorkchopCooked.class; //320
            list[PAINTING] = ItemPainting.class; //321
            list[GOLDEN_APPLE] = ItemAppleGold.class; //322
            list[SIGN] = ItemSign.class; //323
            list[WOODEN_DOOR] = ItemDoorWood.class; //324
            list[BUCKET] = ItemBucket.class; //325
            
            list[MINECART] = ItemMinecart.class; //328
            list[SADDLE] = ItemSaddle.class; //329
            list[IRON_DOOR] = ItemDoorIron.class; //330
            list[REDSTONE] = ItemRedstone.class; //331
            list[SNOWBALL] = ItemSnowball.class; //332
            list[BOAT] = ItemBoat.class; //333
            list[LEATHER] = ItemLeather.class; //334
            list[KELP] = ItemKelp.class; //335

            list[BRICK] = ItemBrick.class; //336
            list[CLAY] = ItemClay.class; //337
            list[SUGARCANE] = ItemSugarcane.class; //338
            list[PAPER] = ItemPaper.class; //339
            list[BOOK] = ItemBook.class; //340
            list[SLIMEBALL] = ItemSlimeball.class; //341
            list[MINECART_WITH_CHEST] = ItemMinecartChest.class; //342

            list[EGG] = ItemEgg.class; //344
            list[COMPASS] = ItemCompass.class; //345
            list[FISHING_ROD] = ItemFishingRod.class; //346
            list[CLOCK] = ItemClock.class; //347
            list[GLOWSTONE_DUST] = ItemGlowstoneDust.class; //348
            list[RAW_FISH] = ItemFish.class; //349
            list[COOKED_FISH] = ItemFishCooked.class; //350
            list[DYE] = ItemDye.class; //351
            list[BONE] = ItemBone.class; //352
            list[SUGAR] = ItemSugar.class; //353
            list[CAKE] = ItemCake.class; //354
            list[BED] = ItemBed.class; //355
            list[REPEATER] = ItemRedstoneRepeater.class; //356
            list[COOKIE] = ItemCookie.class; //357
            list[MAP] = ItemMap.class; //358
            list[SHEARS] = ItemShears.class; //359
            list[MELON] = ItemMelon.class; //360
            list[PUMPKIN_SEEDS] = ItemSeedsPumpkin.class; //361
            list[MELON_SEEDS] = ItemSeedsMelon.class; //362
            list[RAW_BEEF] = ItemBeefRaw.class; //363
            list[STEAK] = ItemSteak.class; //364
            list[RAW_CHICKEN] = ItemChickenRaw.class; //365
            list[COOKED_CHICKEN] = ItemChickenCooked.class; //366
            list[ROTTEN_FLESH] = ItemRottenFlesh.class; //367
            list[ENDER_PEARL] = ItemEnderPearl.class; //368
            list[BLAZE_ROD] = ItemBlazeRod.class; //369
            list[GHAST_TEAR] = ItemGhastTear.class; //370
            list[GOLD_NUGGET] = ItemNuggetGold.class; //371
            list[NETHER_WART] = ItemNetherWart.class; //372
            list[POTION] = ItemPotion.class; //373
            list[GLASS_BOTTLE] = ItemGlassBottle.class; //374
            list[SPIDER_EYE] = ItemSpiderEye.class; //375
            list[FERMENTED_SPIDER_EYE] = ItemSpiderEyeFermented.class; //376
            list[BLAZE_POWDER] = ItemBlazePowder.class; //377
            list[MAGMA_CREAM] = ItemMagmaCream.class; //378
            list[BREWING_STAND] = ItemBrewingStand.class; //379
            list[CAULDRON] = ItemCauldron.class; //380
            list[ENDER_EYE] = ItemEnderEye.class; //381
            list[GLISTERING_MELON] = ItemMelonGlistering.class; //382
            list[SPAWN_EGG] = ItemSpawnEgg.class; //383
            list[EXPERIENCE_BOTTLE] = ItemExpBottle.class; //384
            list[FIRE_CHARGE] = ItemFireCharge.class; //385
            list[BOOK_AND_QUILL] = ItemBookAndQuill.class; //386
            list[WRITTEN_BOOK] = ItemBookWritten.class; //387
            list[EMERALD] = ItemEmerald.class; //388
            list[ITEM_FRAME] = ItemItemFrame.class; //389
            list[FLOWER_POT] = ItemFlowerPot.class; //390
            list[CARROT] = ItemCarrot.class; //391
            list[POTATO] = ItemPotato.class; //392
            list[BAKED_POTATO] = ItemPotatoBaked.class; //393
            list[POISONOUS_POTATO] = ItemPotatoPoisonous.class; //394
            list[EMPTY_MAP] = ItemEmptyMap.class; //395
            list[GOLDEN_CARROT] = ItemCarrotGolden.class; //396
            list[SKULL] = ItemSkull.class; //397
            list[CARROT_ON_A_STICK] = ItemCarrotOnAStick.class; //398
            list[NETHER_STAR] = ItemNetherStar.class; //399
            list[PUMPKIN_PIE] = ItemPumpkinPie.class; //400
            list[FIREWORKS] = ItemFirework.class; //401

            list[ENCHANTED_BOOK] = ItemBookEnchanted.class; //403
            list[COMPARATOR] = ItemRedstoneComparator.class; //404
            list[NETHER_BRICK] = ItemNetherBrick.class; //405
            list[QUARTZ] = ItemQuartz.class; //406
            list[MINECART_WITH_TNT] = ItemMinecartTNT.class; //407
            list[MINECART_WITH_HOPPER] = ItemMinecartHopper.class; //408
            list[PRISMARINE_SHARD] = ItemPrismarineShard.class; //409
            list[HOPPER] = ItemHopper.class;
            list[RAW_RABBIT] = ItemRabbitRaw.class; //411
            list[COOKED_RABBIT] = ItemRabbitCooked.class; //412
            list[RABBIT_STEW] = ItemRabbitStew.class; //413
            list[RABBIT_FOOT] = ItemRabbitFoot.class; //414
            list[RABBIT_HIDE] = ItemRabbitHide.class; //415
            list[LEATHER_HORSE_ARMOR] = ItemHorseArmorLeather.class; //416
            list[IRON_HORSE_ARMOR] = ItemHorseArmorIron.class; //417
            list[GOLD_HORSE_ARMOR] = ItemHorseArmorGold.class; //418
            list[DIAMOND_HORSE_ARMOR] = ItemHorseArmorDiamond.class; //419
            list[LEAD] = ItemLead.class; //420
            list[NAME_TAG] = ItemNameTag.class; //421
            list[PRISMARINE_CRYSTALS] = ItemPrismarineCrystals.class; //422
            list[RAW_MUTTON] = ItemMuttonRaw.class; //423
            list[COOKED_MUTTON] = ItemMuttonCooked.class; //424
            list[Item.ARMOR_STAND] = ItemArmorStand.class; //425
            list[END_CRYSTAL] = ItemEndCrystal.class; //426
            list[SPRUCE_DOOR] = ItemDoorSpruce.class; //427
            list[BIRCH_DOOR] = ItemDoorBirch.class; //428
            list[JUNGLE_DOOR] = ItemDoorJungle.class; //429
            list[ACACIA_DOOR] = ItemDoorAcacia.class; //430
            list[DARK_OAK_DOOR] = ItemDoorDarkOak.class; //431
            list[CHORUS_FRUIT] = ItemChorusFruit.class; //432
            list[POPPED_CHORUS_FRUIT] = ItemChorusFruitPopped.class; //433
            list[BANNER_PATTERN] = ItemBannerPattern.class; //434

            list[DRAGON_BREATH] = ItemDragonBreath.class; //437
            list[SPLASH_POTION] = ItemPotionSplash.class; //438

            list[LINGERING_POTION] = ItemPotionLingering.class; //441

            list[ELYTRA] = ItemElytra.class; //444

            list[SHULKER_SHELL] = ItemShulkerShell.class; //445
            list[BANNER] = ItemBanner.class; //446

            list[TOTEM] = ItemTotem.class; //450
            
            list[IRON_NUGGET] = ItemNuggetIron.class; //452
            
            list[TRIDENT] = ItemTrident.class; //455

            list[BEETROOT] = ItemBeetroot.class; //457
            list[BEETROOT_SEEDS] = ItemSeedsBeetroot.class; //458
            list[BEETROOT_SOUP] = ItemBeetrootSoup.class; //459
            list[RAW_SALMON] = ItemSalmon.class; //460
            list[CLOWNFISH] = ItemClownfish.class; //461
            list[PUFFERFISH] = ItemPufferfish.class; //462
            list[COOKED_SALMON] = ItemSalmonCooked.class; //463
            list[DRIED_KELP] = ItemDriedKelp.class; //464

            list[GOLDEN_APPLE_ENCHANTED] = ItemAppleGoldEnchanted.class; //466
            
            list[TURTLE_SHELL] = ItemTurtleShell.class; //469

            list[SPRUCE_SIGN] = ItemSpruceSign.class; //472
            list[BIRCH_SIGN] = ItemBirchSign.class; //473
            list[JUNGLE_SIGN] = ItemJungleSign.class; //474
            list[ACACIA_SIGN] = ItemAcaciaSign.class; //475
            list[DARKOAK_SIGN] = ItemDarkOakSign.class; //476
            list[SWEET_BERRIES] = ItemSweetBerries.class; //477

            list[RECORD_13] = ItemRecord13.class; //500
            list[RECORD_CAT] = ItemRecordCat.class; //501
            list[RECORD_BLOCKS] = ItemRecordBlocks.class; //502
            list[RECORD_CHIRP] = ItemRecordChirp.class; //503
            list[RECORD_FAR] = ItemRecordFar.class; //504
            list[RECORD_MALL] = ItemRecordMall.class; //505
            list[RECORD_MELLOHI] = ItemRecordMellohi.class; //506
            list[RECORD_STAL] = ItemRecordStal.class; //507
            list[RECORD_STRAD] = ItemRecordStrad.class; //508
            list[RECORD_WARD] = ItemRecordWard.class; //509
            list[RECORD_11] = ItemRecord11.class; //510
            list[RECORD_WAIT] = ItemRecordWait.class; //511

            list[SHIELD] = ItemShield.class; //513

            list[CAMPFIRE] = ItemCampfire.class; //720

            list[SUSPICIOUS_STEW] = ItemSuspiciousStew.class; //734

            list[HONEYCOMB] = ItemHoneycomb.class; //736
            list[HONEY_BOTTLE] = ItemHoneyBottle.class; //737
                        
            list[LODESTONECOMPASS] = ItemCompassLodestone.class; //741;
            list[NETHERITE_INGOT] = ItemIngotNetherite.class; //742
            list[NETHERITE_SWORD] = ItemSwordNetherite.class; //743
            list[NETHERITE_SHOVEL] = ItemShovelNetherite.class; //744
            list[NETHERITE_PICKAXE] = ItemPickaxeNetherite.class; //745
            list[NETHERITE_AXE] = ItemAxeNetherite.class; //746
            list[NETHERITE_HOE] = ItemHoeNetherite.class; //747
            list[NETHERITE_HELMET] = ItemHelmetNetherite.class; //748
            list[NETHERITE_CHESTPLATE] = ItemChestplateNetherite.class; //749
            list[NETHERITE_LEGGINGS] = ItemLeggingsNetherite.class; //750
            list[NETHERITE_BOOTS] = ItemBootsNetherite.class; //751
            list[NETHERITE_SCRAP] = ItemScrapNetherite.class; //752
            list[CRIMSON_SIGN] = ItemCrimsonSign.class; //753
            list[WARPED_SIGN] = ItemWarpedSign.class; //754
            list[CRIMSON_DOOR] = ItemDoorCrimson.class; //755
            list[WARPED_DOOR] = ItemDoorWarped.class; //756
            list[WARPED_FUNGUS_ON_A_STICK] = ItemWarpedFungusOnAStick.class; //757
            list[CHAIN] = ItemChain.class; //758
            list[RECORD_PIGSTEP] = ItemRecordPigstep.class; //759
            list[NETHER_SPROUTS] = ItemNetherSprouts.class; //760
            
            list[SOUL_CAMPFIRE] = ItemCampfireSoul.class; //801
            list[COD_BUCKET] = ItemBucketFishCod.class; //802
            list[GHAST_SPAWN_EGG] = ItemSpawnEggGhast.class; //803
            list[FLOWER_BANNER_PATTERN] = ItemBannerPatternFlower.class; //804
            list[ZOGLIN_SPAWN_EGG] = ItemSpawnEggZoglin.class; //805
            list[BLUE_DYE] = ItemDyeBlue.class; //806
            list[SKULL_BANNER_PATTERN] = ItemBannerPatternSkull.class; //807
            list[ENDERMITE_SPAWN_EGG] = ItemSpawnEggEndermite.class; //808
            list[POLAR_BEAR_SPAWN_EGG] = ItemSpawnEggPolarBear.class; //809
            list[WHITE_DYE] = ItemDyeWhite.class; //810
            list[TROPICAL_FISH_BUCKET] = ItemBucketFishTropical.class; //811
            list[CYAN_DYE] = ItemDyeCyan.class; //812
            list[LIGHT_BLUE_DYE] = ItemDyeLightBlue.class; //813
            list[LIME_DYE] = ItemDyeLime.class; //814
            list[ZOMBIE_VILLAGER_SPAWN_EGG] = ItemSpawnEggZombieVillager.class; //815
            list[STRAY_SPAWN_EGG] = ItemSpawnEggStray.class; //816
            list[GREEN_DYE] = ItemDyeGreen.class; //817
            list[EVOKER_SPAWN_EGG] = ItemSpawnEggEvoker.class; //818
            list[WITHER_SKELETON_SPAWN_EGG] = ItemSpawnEggWitherSkeleton.class; //819
            list[SALMON_BUCKET] = ItemBucketFishSalmon.class; //820
            list[JUNGLE_BOAT] = ItemBoatJungle.class; //821
            list[BLACK_DYE] = ItemDyeBlack.class; //822
            list[MAGMA_CUBE_SPAWN_EGG] = ItemSpawnEggMagmaCube.class; //823
            list[TROPICAL_FISH_SPAWN_EGG] = ItemSpawnEggTropicalFish.class; //824
            list[VEX_SPAWN_EGG] = ItemSpawnEggVex.class; //825
            list[FIELD_MASONED_BANNER_PATTERN] = ItemBannerPatternFieldMasoned.class; //826
            list[WANDERING_TRADER_SPAWN_EGG] = ItemSpawnEggWanderingTrader.class; //827
            list[BROWN_DYE] = ItemDyeBrown.class; //828
            list[PANDA_SPAWN_EGG] = ItemSpawnEggPanda.class; //829
            list[SILVERFISH_SPAWN_EGG] = ItemSpawnEggSilverfish.class; //830
            list[OCELOT_SPAWN_EGG] = ItemSpawnEggOcelot.class; //831
            list[LAVA_BUCKET] = ItemBucketLava.class; //832
            list[SKELETON_SPAWN_EGG] = ItemSpawnEggSkeleton.class; //833
            list[VILLAGER_SPAWN_EGG] = ItemSpawnEggVillager.class; //834
            list[ELDER_GUARDIAN_SPAWN_EGG] = ItemSpawnEggElderGuardian.class; //835
            list[ACACIA_BOAT] = ItemBoatAcacia.class; //836
            list[OAK_BOAT] = ItemBoatOak.class; //837
            list[PHANTOM_SPAWN_EGG] = ItemSpawnEggPhantom.class; //838
            list[HOGLIN_SPAWN_EGG] = ItemSpawnEggHoglin.class; //839
            list[DARK_OAK_BOAT] = ItemBoatDarkOak.class; //840
            list[HUSK_SPAWN_EGG] = ItemSpawnEggHusk.class; //841
            list[BLAZE_SPAWN_EGG] = ItemSpawnEggBlaze.class; //842
            list[BORDURE_INDENTED_BANNER_PATTERN] = ItemBannerPatternBordureIndented.class; //843
            list[MULE_SPAWN_EGG] = ItemSpawnEggMule.class; //844
            list[CREEPER_BANNER_PATTERN] = ItemBannerPatternCreeper.class; //845
            list[ZOMBIE_HORSE_SPAWN_EGG] = ItemSpawnEggZombieHorse.class; //846
            list[BEE_SPAWN_EGG] = ItemSpawnEggBee.class; //847
            list[COD_SPAWN_EGG] = ItemSpawnEggCod.class; //848
            list[LLAMA_SPAWN_EGG] = ItemSpawnEggLlama.class; //849
            list[FOX_SPAWN_EGG] = ItemSpawnEggFox.class; //850
            list[PIGLIN_BRUTE_SPAWN_EGG] = ItemSpawnEggPiglinBrute.class; //851
            list[PIG_SPAWN_EGG] = ItemSpawnEggPig.class; //852
            list[COW_SPAWN_EGG] = ItemSpawnEggCow.class; //853
            list[NPC_SPAWN_EGG] = ItemSpawnEggNpc.class; //854
            list[SQUID_SPAWN_EGG] = ItemSpawnEggSquid.class; //855
            list[MAGENTA_DYE] = ItemDyeMagenta.class; //856
            list[RED_DYE] = ItemDyeRed.class; //857
            list[WITCH_SPAWN_EGG] = ItemSpawnEggWitch.class; //858
            list[INK_SAC] = ItemInkSac.class; //859
            list[ORANGE_DYE] = ItemDyeOrange.class; //860
            list[PILLAGER_SPAWN_EGG] = ItemSpawnEggPillager.class; //861
            list[CAVE_SPIDER_SPAWN_EGG] = ItemSpawnEggCaveSpider.class; //862
            list[BONE_MEAL] = ItemBoneMeal.class; //863
            list[PUFFERFISH_BUCKET] = ItemBucketFishPufferfish.class; //864
            list[BAT_SPAWN_EGG] = ItemSpawnEggBat.class; //865
            list[SPRUCE_BOAT] = ItemBoatSpruce.class; //866
            list[SPIDER_SPAWN_EGG] = ItemSpawnEggSpider.class; //867
            list[PIGLIN_BANNER_PATTERN] = ItemBannerPatternPiglin.class; //868
            list[RABBIT_SPAWN_EGG] = ItemSpawnEggRabbit.class; //869
            list[MOJANG_BANNER_PATTERN] = ItemBannerPatternMojang.class; //870
            list[PIGLIN_SPAWN_EGG] = ItemSpawnEggPiglin.class; //871
            list[TURTLE_SPAWN_EGG] = ItemSpawnEggTurtle.class; //872
            list[MOOSHROOM_SPAWN_EGG] = ItemSpawnEggMooshroom.class; //873
            list[PUFFERFISH_SPAWN_EGG] = ItemSpawnEggPufferfish.class; //874
            list[PARROT_SPAWN_EGG] = ItemSpawnEggParrot.class; //875
            list[ZOMBIE_SPAWN_EGG] = ItemSpawnEggZombie.class; //876
            list[WOLF_SPAWN_EGG] = ItemSpawnEggWolf.class; //877
            list[GRAY_DYE] = ItemDyeGray.class; //878
            list[COCOA_BEANS] = ItemCocoaBeans.class; //879
            list[SKELETON_HORSE_SPAWN_EGG] = ItemSpawnEggSkeletonHorse.class; //880
            list[SHEEP_SPAWN_EGG] = ItemSpawnEggSheep.class; //881
            list[SLIME_SPAWN_EGG] = ItemSpawnEggSlime.class; //882
            list[VINDICATOR_SPAWN_EGG] = ItemSpawnEggVindicator.class; //883
            list[DROWNED_SPAWN_EGG] = ItemSpawnEggDrowned.class; //884
            list[MILK_BUCKET] = ItemBucketMilk.class; //885
            list[DOLPHIN_SPAWN_EGG] = ItemSpawnEggDolphin.class; //886
            list[DONKEY_SPAWN_EGG] = ItemSpawnEggDonkey.class; //887
            list[PURPLE_DYE] = ItemDyePurple.class; //888
            list[BIRCH_BOAT] = ItemBoatBirch.class; //889
            //list[DEBUG_STICK] = Item.Debug_stick.class; //890
            list[ENDERMAN_SPAWN_EGG] = ItemSpawnEggEnderman.class; //891
            list[CHICKEN_SPAWN_EGG] = ItemSpawnEggChicken.class; //892
            list[SHULKER_SPAWN_EGG] = ItemSpawnEggShulker.class; //893
            list[STRIDER_SPAWN_EGG] = ItemSpawnEggStrider.class; //894
            list[ZOMBIE_PIGMAN_SPAWN_EGG] = ItemSpawnEggZombiePigman.class; //895
            list[YELLOW_DYE] = ItemDyeYellow.class; //896
            list[CAT_SPAWN_EGG] = ItemSpawnEggCat.class; //897
            list[GUARDIAN_SPAWN_EGG] = ItemSpawnEggGuardian.class; //898
            list[PINK_DYE] = ItemDyePink.class; //899
            list[SALMON_SPAWN_EGG] = ItemSpawnEggSalmon.class; //900
            list[CREEPER_SPAWN_EGG] = ItemSpawnEggCreeper.class; //901
            list[HORSE_SPAWN_EGG] = ItemSpawnEggHorse.class; //902
            list[LAPIS_LAZULI] = ItemLapisLazuli.class; //903
            list[RAVAGER_SPAWN_EGG] = ItemSpawnEggRavager.class; //904
            list[WATER_BUCKET] = ItemBucketWater.class; //905
            list[LIGHT_GRAY_DYE] = ItemDyeLightGray.class; //906
            list[CHARCOAL] = ItemCharcoal.class; //907
            list[AGENT_SPAWN_EGG] = ItemSpawnEggAgent.class; //908

            for (int i = 0; i < 256; ++i) {
                if (Block.list[i] != null) {
                    list[i] = Block.list[i];
                }
            }
        }

        initCreativeItems();
    }

    private static List itemList;

    @PowerNukkitOnly
    @Since("1.4.0.0-PN")
    public static List rebuildItemList() {
        return itemList = Collections.unmodifiableList(Stream.of(
                BlockStateRegistry.getPersistenceNames().stream()
                        .map(name-> name.substring(name.indexOf(':') + 1)),
                itemIds.keySet().stream()
        ).flatMap(Function.identity()).distinct().collect(Collectors.toList()));
    }

    @PowerNukkitOnly
    @Since("1.4.0.0-PN")
    public static List getItemList() {
        List itemList = Item.itemList;
        if (itemList == null) {
            return rebuildItemList();
        }
        return itemList;
    }

    private static final ArrayList creative = new ArrayList<>();

    @SuppressWarnings("unchecked")
    private static void initCreativeItems() {
        clearCreativeItems();

        Config config = new Config(Config.JSON);
        config.load(Server.class.getClassLoader().getResourceAsStream("creativeitems.json"));
        List list = config.getMapList("items");

        for (Map map : list) {
            try {
                addCreativeItem(fromJson(map));
            } catch (Exception e) {
                MainLogger.getLogger().logException(e);
            }
        }
    }

    public static void clearCreativeItems() {
        Item.creative.clear();
    }

    public static ArrayList getCreativeItems() {
        return new ArrayList<>(Item.creative);
    }

    public static void addCreativeItem(Item item) {
        Item.creative.add(item.clone());
    }

    public static void removeCreativeItem(Item item) {
        int index = getCreativeItemIndex(item);
        if (index != -1) {
            Item.creative.remove(index);
        }
    }

    public static boolean isCreativeItem(Item item) {
        for (Item aCreative : Item.creative) {
            if (item.equals(aCreative, !item.isTool())) {
                return true;
            }
        }
        return false;
    }

    public static Item getCreativeItem(int index) {
        return (index >= 0 && index < Item.creative.size()) ? Item.creative.get(index) : null;
    }

    public static int getCreativeItemIndex(Item item) {
        for (int i = 0; i < Item.creative.size(); i++) {
            if (item.equals(Item.creative.get(i), !item.isTool())) {
                return i;
            }
        }
        return -1;
    }

    public static Item getBlock(int id) {
        return getBlock(id, 0);
    }

    public static Item getBlock(int id, Integer meta) {
        return getBlock(id, meta, 1);
    }

    public static Item getBlock(int id, Integer meta, int count) {
        return getBlock(id, meta, count, EmptyArrays.EMPTY_BYTES);
    }

    public static Item getBlock(int id, Integer meta, int count, byte[] tags) {
        if (id > 255) {
            id = 255 - id;
        }
        return get(id, meta, count, tags);
    }

    public static Item get(int id) {
        return get(id, 0);
    }

    public static Item get(int id, Integer meta) {
        return get(id, meta, 1);
    }

    public static Item get(int id, Integer meta, int count) {
        return get(id, meta, count, EmptyArrays.EMPTY_BYTES);
    }

    @PowerNukkitDifference(
            info = "Prevents players from getting invalid items by limiting the return to the maximum damage defined in Block.getMaxItemDamage()",
            since = "1.4.0.0-PN")
    public static Item get(int id, Integer meta, int count, byte[] tags) {
        try {
            Class c = null;
            if (id < 0) {
                int blockId = 255 - id;
                c = Block.list[blockId];
            } else {
                c = list[id];
            }
            Item item;

            if (id < 256) {
                int blockId = id < 0? 255 - id : id;
                if (meta == 0) {
                    item = new ItemBlock(Block.get(blockId), 0, count);
                } else if (meta == -1) {
                    // Special case for item instances used in fuzzy recipes
                    item = new ItemBlock(Block.get(blockId), -1);
                } else {
                    BlockState state = BlockState.of(blockId, meta);
                    try {
                        state.validate();
                        item = state.asItemBlock(count);
                    } catch (InvalidBlockPropertyMetaException | InvalidBlockStateException e) {
                        log.warn("Attempted to get an ItemBlock with invalid block state in memory: "+state+", trying to repair the block state...");
                        Block repaired = state.getBlockRepairing(null, 0, 0, 0);
                        item = repaired.asItemBlock(count);
                        log.error("Attempted to get an illegal item block " + id + ":" + meta + " ("+blockId+"), the meta was changed to " + item.getDamage());
                    } catch (UnknownRuntimeIdException e) {
                        log.warn("Attempted to get an illegal item block "+id+":"+meta+ " ("+blockId+"), the runtime id was unknown and the meta was changed to 0");
                        item = BlockState.of(id).asItemBlock(count);
                    }
                }
            } else if (c == null) {
                item = new Item(id, meta, count);
            } else {
                if (meta == -1) {
                    item = ((Item) c.getConstructor(Integer.class, int.class).newInstance(0, count)).createFuzzyCraftingRecipe();
                } else {
                    item = ((Item) c.getConstructor(Integer.class, int.class).newInstance(meta, count));
                }
            }

            if (tags.length != 0) {
                item.setCompoundTag(tags);
            }

            return item.selfUpgrade();
        } catch (Exception e) {
            log.error("Error getting the item " + id + ":" + meta + (id < 0? " ("+(255 - id)+")":"") + "! Returning an unsafe item stack!", e);
            return new Item(id, meta, count).setCompoundTag(tags);
        }
    }

    private static final Pattern NAMESPACED = Pattern.compile("^(?:([a-zA-Z][a-zA-Z0-9_-]*):)?([a-zA-Z][a-zA-Z0-9_-]*)(?::(\\d+))?$");
    private static final Pattern ITEM_ID = Pattern.compile("^(-?[1-9]\\d*)(?::(\\d+))?$");
    
    @PowerNukkitDifference(since = "1.4.0.0-PN", info = "Improve namespaced name handling and allows to get custom blocks by name")
    public static Item fromString(String str) {
        Matcher matcher = NAMESPACED.matcher(str);
        int id = 0;
        int meta = 0;
        String metaNumber;
        if (matcher.matches()) {
            String namespace = matcher.group(1);
            String itemName = matcher.group(2).toLowerCase();
            metaNumber = matcher.group(3);
            if (namespace == null || namespace.isEmpty()) {
                namespace = "minecraft";
            } else {
                namespace = namespace.toLowerCase();
            }
            
            Integer idFound;
            if (namespace.equals("minecraft") && (idFound = itemIds.get(itemName)) != null) {
                id = idFound;
            } else {
                Integer blockId = BlockStateRegistry.getBlockId(namespace + ":" + itemName);
                if (blockId != null) {
                    id = blockId;
                    if (id > 255) {
                        id = 255 - id;
                    }
                } else if (namespace.equals("minecraft") && (idFound = blockIds.get(itemName)) != null) {
                    id = idFound;
                } else {
                    return get(0, 0);
                }
            }
        } else {
            matcher = ITEM_ID.matcher(str);
            if (matcher.matches()) {
                String itemId = matcher.group(1);
                metaNumber = matcher.group(2);
                id = Integer.parseInt(itemId);
            } else {
                return get(0, 0);
            }
        }
        
        if (metaNumber != null && !metaNumber.isEmpty()) {
            meta = Integer.parseInt(metaNumber) & 0xFFFF;
        }
        
        return get(id, meta);
    }

    public static Item fromJson(Map data) {
        String nbt = (String) data.get("nbt_b64");
        byte[] nbtBytes;
        if (nbt != null) {
            nbtBytes = Base64.getDecoder().decode(nbt);
        } else { // Support old format for backwards compat
            nbt = (String) data.getOrDefault("nbt_hex", null);
            if (nbt == null) {
                nbtBytes = EmptyArrays.EMPTY_BYTES;
            } else {
                nbtBytes = Utils.parseHexBinary(nbt);
            }
        }

        return get(Utils.toInt(data.get("id")), Utils.toInt(data.getOrDefault("damage", 0)), Utils.toInt(data.getOrDefault("count", 1)), nbtBytes);
    }

    public static Item[] fromStringMultiple(String str) {
        String[] b = str.split(",");
        Item[] items = new Item[b.length - 1];
        for (int i = 0; i < b.length; i++) {
            items[i] = fromString(b[i]);
        }
        return items;
    }

    public Item setCompoundTag(CompoundTag tag) {
        this.setNamedTag(tag);
        return this;
    }

    public Item setCompoundTag(byte[] tags) {
        this.tags = tags;
        this.cachedNBT = null;
        return this;
    }

    public byte[] getCompoundTag() {
        return tags;
    }

    public boolean hasCompoundTag() {
        return this.tags != null && this.tags.length > 0;
    }

    public boolean hasCustomBlockData() {
        if (!this.hasCompoundTag()) {
            return false;
        }

        CompoundTag tag = this.getNamedTag();
        return tag.contains("BlockEntityTag") && tag.get("BlockEntityTag") instanceof CompoundTag;

    }

    public Item clearCustomBlockData() {
        if (!this.hasCompoundTag()) {
            return this;
        }
        CompoundTag tag = this.getNamedTag();

        if (tag.contains("BlockEntityTag") && tag.get("BlockEntityTag") instanceof CompoundTag) {
            tag.remove("BlockEntityTag");
            this.setNamedTag(tag);
        }

        return this;
    }

    public Item setCustomBlockData(CompoundTag compoundTag) {
        CompoundTag tags = compoundTag.copy();
        tags.setName("BlockEntityTag");

        CompoundTag tag;
        if (!this.hasCompoundTag()) {
            tag = new CompoundTag();
        } else {
            tag = this.getNamedTag();
        }

        tag.putCompound("BlockEntityTag", tags);
        this.setNamedTag(tag);

        return this;
    }

    public CompoundTag getCustomBlockData() {
        if (!this.hasCompoundTag()) {
            return null;
        }

        CompoundTag tag = this.getNamedTag();

        if (tag.contains("BlockEntityTag")) {
            Tag bet = tag.get("BlockEntityTag");
            if (bet instanceof CompoundTag) {
                return (CompoundTag) bet;
            }
        }

        return null;
    }

    public boolean hasEnchantments() {
        if (!this.hasCompoundTag()) {
            return false;
        }

        CompoundTag tag = this.getNamedTag();

        if (tag.contains("ench")) {
            Tag enchTag = tag.get("ench");
            return enchTag instanceof ListTag;
        }

        return false;
    }

    /**
     * Convenience method to check if the item stack has positive level on a specific enchantment by it's id.
     * @param id The enchantment ID from {@link Enchantment} constants.
     */
    @PowerNukkitOnly
    @Since("1.3.2.0-PN")
    public boolean hasEnchantment(int id) {
        return getEnchantmentLevel(id) > 0;
    }

    /**
     * Find the enchantment level by the enchantment id.
     * @param id The enchantment ID from {@link Enchantment} constants.
     * @return {@code 0} if the item don't have that enchantment or the current level of the given enchantment.
     */
    @PowerNukkitOnly
    @Since("1.4.0.0-PN")
    public int getEnchantmentLevel(int id) {
        if (!this.hasEnchantments()) {
            return 0;
        }

        for (CompoundTag entry : this.getNamedTag().getList("ench", CompoundTag.class).getAll()) {
            if (entry.getShort("id") == id) {
                return entry.getShort("lvl");
            }
        }
        
        return 0;
    }

    public Enchantment getEnchantment(int id) {
        return getEnchantment((short) (id & 0xffff));
    }

    public Enchantment getEnchantment(short id) {
        if (!this.hasEnchantments()) {
            return null;
        }

        for (CompoundTag entry : this.getNamedTag().getList("ench", CompoundTag.class).getAll()) {
            if (entry.getShort("id") == id) {
                Enchantment e = Enchantment.getEnchantment(entry.getShort("id"));
                if (e != null) {
                    e.setLevel(entry.getShort("lvl"), false);
                    return e;
                }
            }
        }

        return null;
    }

    public void addEnchantment(Enchantment... enchantments) {
        CompoundTag tag;
        if (!this.hasCompoundTag()) {
            tag = new CompoundTag();
        } else {
            tag = this.getNamedTag();
        }

        ListTag ench;
        if (!tag.contains("ench")) {
            ench = new ListTag<>("ench");
            tag.putList(ench);
        } else {
            ench = tag.getList("ench", CompoundTag.class);
        }

        for (Enchantment enchantment : enchantments) {
            boolean found = false;

            for (int k = 0; k < ench.size(); k++) {
                CompoundTag entry = ench.get(k);
                if (entry.getShort("id") == enchantment.getId()) {
                    ench.add(k, new CompoundTag()
                            .putShort("id", enchantment.getId())
                            .putShort("lvl", enchantment.getLevel())
                    );
                    found = true;
                    break;
                }
            }

            if (!found) {
                ench.add(new CompoundTag()
                        .putShort("id", enchantment.getId())
                        .putShort("lvl", enchantment.getLevel())
                );
            }
        }

        this.setNamedTag(tag);
    }

    public Enchantment[] getEnchantments() {
        if (!this.hasEnchantments()) {
            return Enchantment.EMPTY_ARRAY;
        }

        List enchantments = new ArrayList<>();

        ListTag ench = this.getNamedTag().getList("ench", CompoundTag.class);
        for (CompoundTag entry : ench.getAll()) {
            Enchantment e = Enchantment.getEnchantment(entry.getShort("id"));
            if (e != null) {
                e.setLevel(entry.getShort("lvl"), false);
                enchantments.add(e);
            }
        }

        return enchantments.toArray(Enchantment.EMPTY_ARRAY);
    }

    public boolean hasCustomName() {
        if (!this.hasCompoundTag()) {
            return false;
        }

        CompoundTag tag = this.getNamedTag();
        if (tag.contains("display")) {
            Tag tag1 = tag.get("display");
            return tag1 instanceof CompoundTag && ((CompoundTag) tag1).contains("Name") && ((CompoundTag) tag1).get("Name") instanceof StringTag;
        }

        return false;
    }

    public String getCustomName() {
        if (!this.hasCompoundTag()) {
            return "";
        }

        CompoundTag tag = this.getNamedTag();
        if (tag.contains("display")) {
            Tag tag1 = tag.get("display");
            if (tag1 instanceof CompoundTag && ((CompoundTag) tag1).contains("Name") && ((CompoundTag) tag1).get("Name") instanceof StringTag) {
                return ((CompoundTag) tag1).getString("Name");
            }
        }

        return "";
    }

    public Item setCustomName(String name) {
        if (name == null || name.equals("")) {
            this.clearCustomName();
        }

        CompoundTag tag;
        if (!this.hasCompoundTag()) {
            tag = new CompoundTag();
        } else {
            tag = this.getNamedTag();
        }
        if (tag.contains("display") && tag.get("display") instanceof CompoundTag) {
            tag.getCompound("display").putString("Name", name);
        } else {
            tag.putCompound("display", new CompoundTag("display")
                    .putString("Name", name)
            );
        }
        this.setNamedTag(tag);
        return this;
    }

    public Item clearCustomName() {
        if (!this.hasCompoundTag()) {
            return this;
        }

        CompoundTag tag = this.getNamedTag();

        if (tag.contains("display") && tag.get("display") instanceof CompoundTag) {
            tag.getCompound("display").remove("Name");
            if (tag.getCompound("display").isEmpty()) {
                tag.remove("display");
            }

            this.setNamedTag(tag);
        }

        return this;
    }

    public String[] getLore() {
        Tag tag = this.getNamedTagEntry("display");
        ArrayList lines = new ArrayList<>();

        if (tag instanceof CompoundTag) {
            CompoundTag nbt = (CompoundTag) tag;
            ListTag lore = nbt.getList("Lore", StringTag.class);

            if (lore.size() > 0) {
                for (StringTag stringTag : lore.getAll()) {
                    lines.add(stringTag.data);
                }
            }
        }

        return lines.toArray(EmptyArrays.EMPTY_STRINGS);
    }

    public Item setLore(String... lines) {
        CompoundTag tag;
        if (!this.hasCompoundTag()) {
            tag = new CompoundTag();
        } else {
            tag = this.getNamedTag();
        }
        ListTag lore = new ListTag<>("Lore");

        for (String line : lines) {
            lore.add(new StringTag("", line));
        }

        if (!tag.contains("display")) {
            tag.putCompound("display", new CompoundTag("display").putList(lore));
        } else {
            tag.getCompound("display").putList(lore);
        }

        this.setNamedTag(tag);
        return this;
    }

    public Tag getNamedTagEntry(String name) {
        CompoundTag tag = this.getNamedTag();
        if (tag != null) {
            return tag.contains(name) ? tag.get(name) : null;
        }

        return null;
    }

    public CompoundTag getNamedTag() {
        if (!this.hasCompoundTag()) {
            return null;
        }

        if (this.cachedNBT == null) {
            this.cachedNBT = parseCompoundTag(this.tags);
        }

        if (this.cachedNBT != null) {
            this.cachedNBT.setName("");
        }

        return this.cachedNBT;
    }

    public Item setNamedTag(CompoundTag tag) {
        if (tag.isEmpty()) {
            return this.clearNamedTag();
        }
        tag.setName(null);

        this.cachedNBT = tag;
        this.tags = writeCompoundTag(tag);

        return this;
    }

    public Item clearNamedTag() {
        return this.setCompoundTag(EmptyArrays.EMPTY_BYTES);
    }

    public static CompoundTag parseCompoundTag(byte[] tag) {
        try {
            return NBTIO.read(tag, ByteOrder.LITTLE_ENDIAN);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    public byte[] writeCompoundTag(CompoundTag tag) {
        try {
            tag.setName("");
            return NBTIO.write(tag, ByteOrder.LITTLE_ENDIAN);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public boolean isNull() {
        return this.count <= 0 || this.id == AIR;
    }

    final public String getName() {
        return this.hasCustomName() ? this.getCustomName() : this.name;
    }

    final public boolean canBePlaced() {
        return ((this.block != null) && this.block.canBePlaced());
    }

    public Block getBlock() {
        if (this.block != null) {
            return this.block.clone();
        } else {
            return Block.get(BlockID.AIR);
        }
    }

    public int getId() {
        return id;
    }
    
    @PowerNukkitOnly
    @Since("1.4.0.0-PN")
    public int getBlockId() {
        if (block != null) {
            return block.getId();
        } else {
            return -1;
        }
    }

    public int getDamage() {
        return meta;
    }

    public void setDamage(Integer meta) {
        if (meta != null) {
            this.meta = meta & 0xffff;
        } else {
            this.hasMeta = false;
        }
    }
    
    @PowerNukkitOnly
    @Since("1.4.0.0-PN")
    public Item createFuzzyCraftingRecipe() {
        Item item = clone();
        item.meta = 0;
        item.hasMeta = false;
        return item;
    }

    public int getMaxStackSize() {
        return block == null? 64 : block.getItemMaxStackSize();
    }

    final public Short getFuelTime() {
        if (!Fuel.duration.containsKey(id)) {
            return null;
        }
        if (this.id != BUCKET || this.meta == 10) {
            return Fuel.duration.get(this.id);
        }
        return null;
    }

    public boolean useOn(Entity entity) {
        return false;
    }

    public boolean useOn(Block block) {
        return false;
    }

    public boolean isTool() {
        return false;
    }

    public int getMaxDurability() {
        return -1;
    }

    public int getTier() {
        return 0;
    }

    public boolean isPickaxe() {
        return false;
    }

    public boolean isAxe() {
        return false;
    }

    public boolean isSword() {
        return false;
    }

    public boolean isShovel() {
        return false;
    }

    public boolean isHoe() {
        return false;
    }

    public boolean isShears() {
        return false;
    }

    public boolean isArmor() {
        return false;
    }

    public boolean isHelmet() {
        return false;
    }

    public boolean isChestplate() {
        return false;
    }

    public boolean isLeggings() {
        return false;
    }

    public boolean isBoots() {
        return false;
    }

    public int getEnchantAbility() {
        return 0;
    }

    public int getAttackDamage() {
        return 1;
    }

    public int getArmorPoints() {
        return 0;
    }

    public int getToughness() {
        return 0;
    }

    public boolean isUnbreakable() {
        return false;
    }

    /**
     * If the item is resistant to lava and fire and can float on lava like if it was on water.
     * @since 1.4.0.0-PN
     */
    @PowerNukkitOnly
    @Since("1.4.0.0-PN")
    public boolean isLavaResistant() {
        return false;
    }
    
    public boolean onUse(Player player, int ticksUsed) {
        return false;
    }

    public boolean onRelease(Player player, int ticksUsed) {
        return false;
    }

    public boolean damageWhenBreaking() { return true; }

    @Override
    final public String toString() {
        return "Item " + this.name + " (" + this.id + ":" + (!this.hasMeta ? "?" : this.meta) + ")x" + this.count + (this.hasCompoundTag() ? " tags:0x" + Binary.bytesToHexString(this.getCompoundTag()) : "");
    }

    public int getDestroySpeed(Block block, Player player) {
        return 1;
    }

    public boolean onActivate(Level level, Player player, Block block, Block target, BlockFace face, double fx, double fy, double fz) {
        return false;
    }

    /**
     * When true, this item can be used to reduce growing times like a bone meal.
     * @return {@code true} if it can act like a bone meal
     */
    @Since("1.3.2.0-PN")
    @PowerNukkitOnly
    public boolean isFertilizer() {
        return false;
    }

    /**
     * Called when a player uses the item on air, for example throwing a projectile.
     * Returns whether the item was changed, for example count decrease or durability change.
     *
     * @param player player
     * @param directionVector direction
     * @return item changed
     */
    public boolean onClickAir(Player player, Vector3 directionVector) {
        return false;
    }

    @PowerNukkitOnly
    @Since("1.3.2.0-PN")
    public Item selfUpgrade() {
        return this;
    }

    @Override
    public final boolean equals(Object item) {
        return item instanceof Item && this.equals((Item) item, true);
    }

    public final boolean equals(Item item, boolean checkDamage) {
        return equals(item, checkDamage, true);
    }

    public final boolean equals(Item item, boolean checkDamage, boolean checkCompound) {
        if (this.getId() == item.getId() && (!checkDamage || this.getDamage() == item.getDamage())) {
            if (checkCompound) {
                if (Arrays.equals(this.getCompoundTag(), item.getCompoundTag())) {
                    return true;
                } else if (this.hasCompoundTag() && item.hasCompoundTag()) {
                    return this.getNamedTag().equals(item.getNamedTag());
                }
            } else {
                return true;
            }
        }

        return false;
    }

    /**
     * Returns whether the specified item stack has the same ID, damage, NBT and count as this item stack.
     *
     * @param other item
     * @return equal
     */
    public final boolean equalsExact(Item other) {
        return this.equals(other, true, true) && this.count == other.count;
    }

    /**
     * Same as {@link #equals(Item, boolean)} but the enchantment order of the items does not affect the result.
     * @since 1.2.1.0-PN
     */
    public final boolean equalsIgnoringEnchantmentOrder(Item item, boolean checkDamage) {
        if (!this.equals(item, checkDamage, false)) {
            return false;
        }

        if (Arrays.equals(this.getCompoundTag(), item.getCompoundTag())) {
            return true;
        }

        if (!this.hasCompoundTag() || !item.hasCompoundTag()) {
            return false;
        }

        CompoundTag thisTags = this.getNamedTag();
        CompoundTag otherTags = item.getNamedTag();
        if (thisTags.equals(otherTags)) {
            return true;
        }

        if (!thisTags.contains("ench") || !otherTags.contains("ench")
                || !(thisTags.get("ench") instanceof ListTag)
                || !(otherTags.get("ench") instanceof ListTag)
                || thisTags.getList("ench").size() != otherTags.getList("ench").size()) {
            return false;
        }

        ListTag thisEnchantmentTags = thisTags.getList("ench", CompoundTag.class);
        ListTag otherEnchantmentTags = otherTags.getList("ench", CompoundTag.class);

        int size = thisEnchantmentTags.size();
        Int2IntMap enchantments = new Int2IntArrayMap(size);
        enchantments.defaultReturnValue(Integer.MIN_VALUE);

        for (int i = 0; i < size; i++) {
            CompoundTag tag = thisEnchantmentTags.get(i);
            enchantments.put(tag.getShort("id"), tag.getShort("lvl"));
        }

        for (int i = 0; i < size; i++) {
            CompoundTag tag = otherEnchantmentTags.get(i);
            if (enchantments.get(tag.getShort("id")) != tag.getShort("lvl")) {
                return false;
            }
        }

        return true;
    }

    @Deprecated
    public final boolean deepEquals(Item item) {
        return equals(item, true);
    }

    @Deprecated
    public final boolean deepEquals(Item item, boolean checkDamage) {
        return equals(item, checkDamage, true);
    }

    @Deprecated
    public final boolean deepEquals(Item item, boolean checkDamage, boolean checkCompound) {
        return equals(item, checkDamage, checkCompound);
    }

    @Override
    public Item clone() {
        try {
            Item item = (Item) super.clone();
            item.tags = this.tags.clone();
            item.cachedNBT = null;
            return item;
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy