// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.server.core.inventory;

import com.hypixel.hytale.protocol.ItemQuantity;
import org.bson.BsonValue;
import com.hypixel.hytale.codec.Codec;
import com.hypixel.hytale.codec.KeyedCodec;
import com.hypixel.hytale.math.util.MathUtil;
import com.hypixel.hytale.server.core.asset.type.item.config.Item;
import javax.annotation.Nullable;
import org.bson.BsonDocument;
import com.hypixel.hytale.codec.builder.BuilderCodec;
import javax.annotation.Nonnull;
import com.hypixel.hytale.protocol.ItemWithAllMetadata;
import com.hypixel.hytale.server.core.io.NetworkSerializable;

public class ItemStack implements NetworkSerializable<ItemWithAllMetadata>
{
    @Nonnull
    public static final ItemStack[] EMPTY_ARRAY;
    @Nonnull
    public static final BuilderCodec<ItemStack> CODEC;
    @Nonnull
    public static final ItemStack EMPTY;
    protected String itemId;
    protected int quantity;
    protected double durability;
    protected double maxDurability;
    protected boolean overrideDroppedItemAnimation;
    @Nullable
    protected BsonDocument metadata;
    @Nullable
    private ItemWithAllMetadata cachedPacket;
    
    public ItemStack(@Nonnull final String itemId, final int quantity, @Nullable final BsonDocument metadata) {
        this.quantity = 1;
        if (quantity <= 0) {
            throw new IllegalArgumentException(String.format("quantity %s must be >0!", quantity));
        }
        if (itemId == null) {
            throw new IllegalArgumentException("itemId cannot be null!");
        }
        if (itemId.equals("Empty")) {
            throw new IllegalArgumentException("itemId cannot be BlockTypeKey.EMPTY!");
        }
        this.itemId = itemId;
        this.quantity = quantity;
        final double maxDurability = this.getItem().getMaxDurability();
        this.durability = maxDurability;
        this.maxDurability = maxDurability;
        this.metadata = metadata;
    }
    
    public ItemStack(@Nonnull final String itemId, final int quantity, final double durability, final double maxDurability, @Nullable final BsonDocument metadata) {
        this(itemId, quantity, metadata);
        this.durability = durability;
        this.maxDurability = maxDurability;
    }
    
    public ItemStack(@Nonnull final String itemId) {
        this(itemId, 1);
    }
    
    public ItemStack(@Nonnull final String itemId, final int quantity) {
        this(itemId, quantity, null);
    }
    
    protected ItemStack() {
        this.quantity = 1;
    }
    
    @Nonnull
    public String getItemId() {
        return this.itemId;
    }
    
    public int getQuantity() {
        return this.quantity;
    }
    
    @Nullable
    @Deprecated
    public BsonDocument getMetadata() {
        if (this.metadata == null) {
            return null;
        }
        return this.metadata.clone();
    }
    
    public boolean isUnbreakable() {
        return this.maxDurability <= 0.0;
    }
    
    public boolean isBroken() {
        return !this.isUnbreakable() && this.durability == 0.0;
    }
    
    public double getMaxDurability() {
        return this.maxDurability;
    }
    
    public double getDurability() {
        return this.durability;
    }
    
    public boolean isEmpty() {
        return this.itemId.equals("Empty");
    }
    
    public boolean getOverrideDroppedItemAnimation() {
        return this.overrideDroppedItemAnimation;
    }
    
    public void setOverrideDroppedItemAnimation(final boolean b) {
        this.overrideDroppedItemAnimation = b;
    }
    
    @Nullable
    public String getBlockKey() {
        if (this.isEmpty()) {
            return "Empty";
        }
        final Item item = this.getItem();
        if (item == null) {
            return null;
        }
        return item.hasBlockType() ? item.getBlockId() : null;
    }
    
    @Nonnull
    public Item getItem() {
        final Item item = Item.getAssetMap().getAsset(this.itemId);
        if (item != null) {
            return item;
        }
        return Item.UNKNOWN;
    }
    
    public boolean isValid() {
        return this.isEmpty() || this.getItem() != null;
    }
    
    @Nonnull
    public ItemStack withDurability(final double durability) {
        return new ItemStack(this.itemId, this.quantity, MathUtil.clamp(durability, 0.0, this.maxDurability), this.maxDurability, this.metadata);
    }
    
    @Nonnull
    public ItemStack withMaxDurability(final double maxDurability) {
        return new ItemStack(this.itemId, this.quantity, Math.min(this.durability, maxDurability), maxDurability, this.metadata);
    }
    
    @Nonnull
    public ItemStack withIncreasedDurability(final double inc) {
        return this.withDurability(this.durability + inc);
    }
    
    @Nonnull
    public ItemStack withRestoredDurability(final double maxDurability) {
        return new ItemStack(this.itemId, this.quantity, maxDurability, maxDurability, this.metadata);
    }
    
    @Nonnull
    public ItemStack withState(@Nonnull final String state) {
        final String newItemId = this.getItem().getItemIdForState(state);
        if (newItemId == null) {
            throw new IllegalArgumentException("Invalid state: " + state);
        }
        return new ItemStack(newItemId, this.quantity, this.durability, this.maxDurability, this.metadata);
    }
    
    @Nullable
    public ItemStack withQuantity(final int quantity) {
        if (quantity == 0) {
            return null;
        }
        if (quantity == this.quantity) {
            return this;
        }
        return new ItemStack(this.itemId, quantity, this.durability, this.maxDurability, this.metadata);
    }
    
    @Nonnull
    public ItemStack withMetadata(@Nullable final BsonDocument metadata) {
        return new ItemStack(this.itemId, this.quantity, this.durability, this.maxDurability, metadata);
    }
    
    @Nonnull
    public <T> ItemStack withMetadata(@Nonnull final KeyedCodec<T> keyedCodec, @Nullable final T data) {
        return this.withMetadata(keyedCodec.getKey(), keyedCodec.getChildCodec(), data);
    }
    
    @Nonnull
    public <T> ItemStack withMetadata(@Nonnull final String key, @Nonnull final Codec<T> codec, @Nullable final T data) {
        BsonDocument clonedMeta = (this.metadata == null) ? new BsonDocument() : this.metadata.clone();
        if (data == null) {
            clonedMeta.remove(key);
        }
        else {
            final BsonValue bsonValue = codec.encode(data);
            boolean b = false;
            Label_0085: {
                Label_0080: {
                    if (!bsonValue.isNull()) {
                        if (bsonValue instanceof final BsonDocument doc) {
                            if (doc.isEmpty()) {
                                break Label_0080;
                            }
                        }
                        b = false;
                        break Label_0085;
                    }
                }
                b = true;
            }
            final boolean empty = b;
            if (empty) {
                clonedMeta.remove(key);
            }
            else {
                clonedMeta.put(key, bsonValue);
            }
        }
        if (clonedMeta.isEmpty()) {
            clonedMeta = null;
        }
        return new ItemStack(this.itemId, this.quantity, this.durability, this.maxDurability, clonedMeta);
    }
    
    @Nonnull
    public ItemStack withMetadata(@Nonnull final String key, @Nullable final BsonValue bsonValue) {
        final BsonDocument clonedMeta = (this.metadata == null) ? new BsonDocument() : this.metadata.clone();
        if (bsonValue == null || bsonValue.isNull()) {
            clonedMeta.remove(key);
        }
        else {
            clonedMeta.put(key, bsonValue);
        }
        return new ItemStack(this.itemId, this.quantity, this.durability, this.maxDurability, clonedMeta);
    }
    
    @Override
    public ItemWithAllMetadata toPacket() {
        if (this.cachedPacket != null) {
            return this.cachedPacket;
        }
        final ItemWithAllMetadata packet = new ItemWithAllMetadata();
        packet.itemId = this.itemId.toString();
        packet.quantity = this.quantity;
        packet.durability = this.durability;
        packet.maxDurability = this.maxDurability;
        packet.overrideDroppedItemAnimation = this.overrideDroppedItemAnimation;
        packet.metadata = ((this.metadata != null) ? this.metadata.toJson() : null);
        return this.cachedPacket = packet;
    }
    
    public boolean isStackableWith(@Nullable final ItemStack itemStack) {
        return itemStack != null && Double.compare(itemStack.durability, this.durability) == 0 && Double.compare(itemStack.maxDurability, this.maxDurability) == 0 && this.itemId.equals(itemStack.itemId) && ((this.metadata != null) ? this.metadata.equals(itemStack.metadata) : (itemStack.metadata == null));
    }
    
    public boolean isEquivalentType(@Nullable final ItemStack itemStack) {
        return itemStack != null && this.itemId.equals(itemStack.itemId) && ((this.metadata != null) ? this.metadata.equals(itemStack.metadata) : (itemStack.metadata == null));
    }
    
    @Nullable
    public <T> T getFromMetadataOrNull(@Nonnull final KeyedCodec<T> keyedCodec) {
        return keyedCodec.getOrNull(this.metadata);
    }
    
    @Nullable
    public <T> T getFromMetadataOrNull(@Nonnull final String key, @Nonnull final Codec<T> codec) {
        final BsonValue bsonValue = (this.metadata == null) ? null : this.metadata.get(key);
        return (bsonValue == null) ? null : codec.decode(bsonValue);
    }
    
    public <T> T getFromMetadataOrDefault(@Nonnull final String key, @Nonnull final BuilderCodec<T> codec) {
        final BsonDocument clonedMeta = (this.metadata == null) ? new BsonDocument() : this.metadata.clone();
        if (clonedMeta == null) {
            return codec.getDefaultValue();
        }
        final BsonValue bsonValue = clonedMeta.get(key);
        return (bsonValue == null) ? codec.getDefaultValue() : codec.decode(bsonValue);
    }
    
    @Override
    public boolean equals(@Nullable final Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || this.getClass() != o.getClass()) {
            return false;
        }
        final ItemStack itemStack = (ItemStack)o;
        return this.quantity == itemStack.quantity && Double.compare(itemStack.durability, this.durability) == 0 && Double.compare(itemStack.maxDurability, this.maxDurability) == 0 && this.itemId.equals(itemStack.itemId) && ((this.metadata != null) ? this.metadata.equals(itemStack.metadata) : (itemStack.metadata == null));
    }
    
    @Override
    public int hashCode() {
        int result = this.itemId.hashCode();
        result = 31 * result + this.quantity;
        long temp = Double.doubleToLongBits(this.durability);
        result = 31 * result + (int)(temp ^ temp >>> 32);
        temp = Double.doubleToLongBits(this.maxDurability);
        result = 31 * result + (int)(temp ^ temp >>> 32);
        result = 31 * result + ((this.metadata != null) ? this.metadata.hashCode() : 0);
        return result;
    }
    
    @Nonnull
    @Override
    public String toString() {
        return "ItemStack{itemId=" + this.itemId + ", quantity=" + this.quantity + ", maxDurability=" + this.maxDurability + ", durability=" + this.durability + ", metadata=" + String.valueOf(this.metadata);
    }
    
    public static boolean isEmpty(@Nullable final ItemStack itemFrom) {
        return itemFrom == null || itemFrom.isEmpty();
    }
    
    public static boolean isStackableWith(@Nullable final ItemStack a, final ItemStack b) {
        return a == b || (a != null && a.isStackableWith(b));
    }
    
    public static boolean isEquivalentType(@Nullable final ItemStack a, final ItemStack b) {
        return a == b || (a != null && a.isEquivalentType(b));
    }
    
    public static boolean isSameItemType(@Nullable final ItemStack a, @Nullable final ItemStack b) {
        return a == b || (a != null && b != null && a.itemId.equals(b.itemId));
    }
    
    @Nullable
    public static ItemStack fromPacket(@Nullable final ItemQuantity packet) {
        if (packet == null) {
            return null;
        }
        final int quantity = packet.quantity;
        if (quantity <= 0) {
            return null;
        }
        return new ItemStack(packet.itemId, quantity, null);
    }
    
    static {
        // 
        // This method could not be decompiled.
        // 
        // Original Bytecode:
        // 
        //     1: anewarray       Lcom/hypixel/hytale/server/core/inventory/ItemStack;
        //     4: putstatic       com/hypixel/hytale/server/core/inventory/ItemStack.EMPTY_ARRAY:[Lcom/hypixel/hytale/server/core/inventory/ItemStack;
        //     7: ldc             Lcom/hypixel/hytale/server/core/inventory/ItemStack;.class
        //     9: invokedynamic   BootstrapMethod #2, get:()Ljava/util/function/Supplier;
        //    14: invokestatic    com/hypixel/hytale/codec/builder/BuilderCodec.builder:(Ljava/lang/Class;Ljava/util/function/Supplier;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //    17: new             Lcom/hypixel/hytale/codec/KeyedCodec;
        //    20: dup            
        //    21: ldc_w           "Id"
        //    24: getstatic       com/hypixel/hytale/codec/Codec.STRING:Lcom/hypixel/hytale/codec/codecs/simple/StringCodec;
        //    27: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
        //    30: invokedynamic   BootstrapMethod #3, accept:()Ljava/util/function/BiConsumer;
        //    35: invokedynamic   BootstrapMethod #4, apply:()Ljava/util/function/Function;
        //    40: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.append:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderField$FieldBuilder;
        //    43: invokestatic    com/hypixel/hytale/codec/validation/Validators.nonNull:()Lcom/hypixel/hytale/codec/validation/Validator;
        //    46: invokevirtual   com/hypixel/hytale/codec/builder/BuilderField$FieldBuilder.addValidator:(Lcom/hypixel/hytale/codec/validation/Validator;)Lcom/hypixel/hytale/codec/builder/BuilderField$FieldBuilder;
        //    49: getstatic       com/hypixel/hytale/server/core/asset/type/item/config/Item.VALIDATOR_CACHE:Lcom/hypixel/hytale/codec/validation/ValidatorCache;
        //    52: invokevirtual   com/hypixel/hytale/codec/validation/ValidatorCache.getValidator:()Lcom/hypixel/hytale/codec/validation/Validator;
        //    55: invokeinterface com/hypixel/hytale/codec/validation/Validator.late:()Lcom/hypixel/hytale/codec/validation/LateValidator;
        //    60: invokevirtual   com/hypixel/hytale/codec/builder/BuilderField$FieldBuilder.addValidator:(Lcom/hypixel/hytale/codec/validation/Validator;)Lcom/hypixel/hytale/codec/builder/BuilderField$FieldBuilder;
        //    63: invokevirtual   com/hypixel/hytale/codec/builder/BuilderField$FieldBuilder.add:()Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
        //    66: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //    69: new             Lcom/hypixel/hytale/codec/KeyedCodec;
        //    72: dup            
        //    73: ldc_w           "Quantity"
        //    76: getstatic       com/hypixel/hytale/codec/Codec.INTEGER:Lcom/hypixel/hytale/codec/codecs/simple/IntegerCodec;
        //    79: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
        //    82: invokedynamic   BootstrapMethod #5, accept:()Ljava/util/function/BiConsumer;
        //    87: invokedynamic   BootstrapMethod #6, apply:()Ljava/util/function/Function;
        //    92: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.append:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderField$FieldBuilder;
        //    95: iconst_0       
        //    96: invokestatic    java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        //    99: invokestatic    com/hypixel/hytale/codec/validation/Validators.greaterThan:(Ljava/lang/Comparable;)Lcom/hypixel/hytale/codec/validation/Validator;
        //   102: invokevirtual   com/hypixel/hytale/codec/builder/BuilderField$FieldBuilder.addValidator:(Lcom/hypixel/hytale/codec/validation/Validator;)Lcom/hypixel/hytale/codec/builder/BuilderField$FieldBuilder;
        //   105: invokevirtual   com/hypixel/hytale/codec/builder/BuilderField$FieldBuilder.add:()Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
        //   108: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //   111: new             Lcom/hypixel/hytale/codec/KeyedCodec;
        //   114: dup            
        //   115: ldc_w           "Durability"
        //   118: getstatic       com/hypixel/hytale/codec/Codec.DOUBLE:Lcom/hypixel/hytale/codec/codecs/simple/DoubleCodec;
        //   121: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
        //   124: invokedynamic   BootstrapMethod #7, accept:()Ljava/util/function/BiConsumer;
        //   129: invokedynamic   BootstrapMethod #8, apply:()Ljava/util/function/Function;
        //   134: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.append:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderField$FieldBuilder;
        //   137: dconst_0       
        //   138: invokestatic    java/lang/Double.valueOf:(D)Ljava/lang/Double;
        //   141: invokestatic    com/hypixel/hytale/codec/validation/Validators.greaterThanOrEqual:(Ljava/lang/Comparable;)Lcom/hypixel/hytale/codec/validation/Validator;
        //   144: invokevirtual   com/hypixel/hytale/codec/builder/BuilderField$FieldBuilder.addValidator:(Lcom/hypixel/hytale/codec/validation/Validator;)Lcom/hypixel/hytale/codec/builder/BuilderField$FieldBuilder;
        //   147: invokevirtual   com/hypixel/hytale/codec/builder/BuilderField$FieldBuilder.add:()Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
        //   150: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //   153: new             Lcom/hypixel/hytale/codec/KeyedCodec;
        //   156: dup            
        //   157: ldc_w           "MaxDurability"
        //   160: getstatic       com/hypixel/hytale/codec/Codec.DOUBLE:Lcom/hypixel/hytale/codec/codecs/simple/DoubleCodec;
        //   163: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
        //   166: invokedynamic   BootstrapMethod #9, accept:()Ljava/util/function/BiConsumer;
        //   171: invokedynamic   BootstrapMethod #10, apply:()Ljava/util/function/Function;
        //   176: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.append:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderField$FieldBuilder;
        //   179: dconst_0       
        //   180: invokestatic    java/lang/Double.valueOf:(D)Ljava/lang/Double;
        //   183: invokestatic    com/hypixel/hytale/codec/validation/Validators.greaterThanOrEqual:(Ljava/lang/Comparable;)Lcom/hypixel/hytale/codec/validation/Validator;
        //   186: invokevirtual   com/hypixel/hytale/codec/builder/BuilderField$FieldBuilder.addValidator:(Lcom/hypixel/hytale/codec/validation/Validator;)Lcom/hypixel/hytale/codec/builder/BuilderField$FieldBuilder;
        //   189: invokevirtual   com/hypixel/hytale/codec/builder/BuilderField$FieldBuilder.add:()Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
        //   192: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //   195: new             Lcom/hypixel/hytale/codec/KeyedCodec;
        //   198: dup            
        //   199: ldc_w           "Metadata"
        //   202: getstatic       com/hypixel/hytale/codec/Codec.BSON_DOCUMENT:Lcom/hypixel/hytale/codec/codecs/BsonDocumentCodec;
        //   205: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
        //   208: invokedynamic   BootstrapMethod #11, accept:()Ljava/util/function/BiConsumer;
        //   213: invokedynamic   BootstrapMethod #12, apply:()Ljava/util/function/Function;
        //   218: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.append:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderField$FieldBuilder;
        //   221: invokevirtual   com/hypixel/hytale/codec/builder/BuilderField$FieldBuilder.add:()Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
        //   224: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //   227: new             Lcom/hypixel/hytale/codec/KeyedCodec;
        //   230: dup            
        //   231: ldc_w           "OverrideDroppedItemAnimation"
        //   234: getstatic       com/hypixel/hytale/codec/Codec.BOOLEAN:Lcom/hypixel/hytale/codec/codecs/simple/BooleanCodec;
        //   237: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
        //   240: invokedynamic   BootstrapMethod #13, accept:()Ljava/util/function/BiConsumer;
        //   245: invokedynamic   BootstrapMethod #14, apply:()Ljava/util/function/Function;
        //   250: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.append:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderField$FieldBuilder;
        //   253: invokevirtual   com/hypixel/hytale/codec/builder/BuilderField$FieldBuilder.add:()Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
        //   256: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //   259: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.build:()Lcom/hypixel/hytale/codec/builder/BuilderCodec;
        //   262: putstatic       com/hypixel/hytale/server/core/inventory/ItemStack.CODEC:Lcom/hypixel/hytale/codec/builder/BuilderCodec;
        //   265: new             Lcom/hypixel/hytale/server/core/inventory/ItemStack$1;
        //   268: dup            
        //   269: invokespecial   com/hypixel/hytale/server/core/inventory/ItemStack$1.<init>:()V
        //   272: putstatic       com/hypixel/hytale/server/core/inventory/ItemStack.EMPTY:Lcom/hypixel/hytale/server/core/inventory/ItemStack;
        //   275: return         
        // 
        // The error that occurred was:
        // 
        // java.lang.UnsupportedOperationException: The requested operation is not supported.
        //     at com.strobel.util.ContractUtils.unsupported(ContractUtils.java:27)
        //     at com.strobel.assembler.metadata.TypeReference.getRawType(TypeReference.java:284)
        //     at com.strobel.assembler.metadata.TypeReference.getRawType(TypeReference.java:279)
        //     at com.strobel.assembler.metadata.TypeReference.makeGenericType(TypeReference.java:154)
        //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitParameterizedType(TypeSubstitutionVisitor.java:225)
        //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitParameterizedType(TypeSubstitutionVisitor.java:25)
        //     at com.strobel.assembler.metadata.ParameterizedType.accept(ParameterizedType.java:103)
        //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visit(TypeSubstitutionVisitor.java:40)
        //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitParameterizedType(TypeSubstitutionVisitor.java:211)
        //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitParameterizedType(TypeSubstitutionVisitor.java:25)
        //     at com.strobel.assembler.metadata.ParameterizedType.accept(ParameterizedType.java:103)
        //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visit(TypeSubstitutionVisitor.java:40)
        //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitMethod(TypeSubstitutionVisitor.java:314)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2611)
        //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:790)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2689)
        //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
        //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:790)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2689)
        //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:790)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2689)
        //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
        //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:790)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2689)
        //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
        //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1083)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
        //     at com.strobel.decompiler.ast.TypeAnalysis.runInference(TypeAnalysis.java:684)
        //     at com.strobel.decompiler.ast.TypeAnalysis.runInference(TypeAnalysis.java:667)
        //     at com.strobel.decompiler.ast.TypeAnalysis.runInference(TypeAnalysis.java:373)
        //     at com.strobel.decompiler.ast.TypeAnalysis.run(TypeAnalysis.java:95)
        //     at com.strobel.decompiler.ast.AstOptimizer.optimize(AstOptimizer.java:344)
        //     at com.strobel.decompiler.ast.AstOptimizer.optimize(AstOptimizer.java:42)
        //     at com.strobel.decompiler.languages.java.ast.AstMethodBodyBuilder.createMethodBody(AstMethodBodyBuilder.java:206)
        //     at com.strobel.decompiler.languages.java.ast.AstMethodBodyBuilder.createMethodBody(AstMethodBodyBuilder.java:93)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createMethodBody(AstBuilder.java:868)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createMethod(AstBuilder.java:761)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.addTypeMembers(AstBuilder.java:638)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeCore(AstBuilder.java:605)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeNoCache(AstBuilder.java:195)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createType(AstBuilder.java:162)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.addType(AstBuilder.java:137)
        //     at com.strobel.decompiler.languages.java.JavaLanguage.buildAst(JavaLanguage.java:71)
        //     at com.strobel.decompiler.languages.java.JavaLanguage.decompileType(JavaLanguage.java:59)
        //     at com.strobel.decompiler.DecompilerDriver.decompileType(DecompilerDriver.java:333)
        //     at com.strobel.decompiler.DecompilerDriver.decompileJar(DecompilerDriver.java:254)
        //     at com.strobel.decompiler.DecompilerDriver.main(DecompilerDriver.java:129)
        // 
        throw new IllegalStateException("An error occurred while decompiling this method.");
    }
    
    public static class Metadata
    {
        public static final String BLOCK_STATE = "BlockState";
    }
}
