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

package com.hypixel.hytale.builtin.crafting.state;

import com.hypixel.hytale.builtin.crafting.window.BenchWindow;
import com.hypixel.hytale.math.vector.Vector3i;
import com.hypixel.hytale.server.core.universe.world.SoundUtil;
import com.hypixel.hytale.protocol.SoundCategory;
import com.hypixel.hytale.protocol.Transform;
import com.hypixel.hytale.protocol.packets.worldmap.ContextMenuItem;
import com.hypixel.hytale.protocol.packets.worldmap.MapMarker;
import java.util.UUID;
import com.hypixel.hytale.server.core.util.PositionUtil;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.universe.world.meta.BlockState;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.server.core.asset.type.item.config.Item;
import org.bson.BsonDocument;
import com.google.common.flogger.LazyArgs;
import java.util.Objects;
import java.util.Collections;
import java.util.Comparator;
import com.hypixel.hytale.server.core.inventory.container.InternalContainerUtilMaterial;
import com.hypixel.hytale.math.util.MathUtil;
import com.hypixel.hytale.builtin.crafting.window.ProcessingBenchWindow;
import com.hypixel.hytale.server.core.modules.entity.item.ItemComponent;
import com.hypixel.hytale.math.vector.Vector3f;
import java.util.concurrent.ThreadLocalRandom;
import com.hypixel.hytale.server.core.asset.type.blockhitbox.BlockBoundingBoxes;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.RotationTuple;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.bench.BenchTierLevel;
import com.hypixel.hytale.server.core.inventory.transaction.MaterialTransaction;
import com.hypixel.hytale.server.core.inventory.transaction.MaterialSlotTransaction;
import com.hypixel.hytale.server.core.inventory.transaction.ListTransaction;
import com.hypixel.hytale.server.core.inventory.transaction.ResourceTransaction;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import com.hypixel.hytale.server.core.inventory.transaction.ItemStackTransaction;
import com.hypixel.hytale.server.core.inventory.container.TestRemoveItemSlotResult;
import com.hypixel.hytale.server.core.universe.world.accessor.BlockAccessor;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import com.hypixel.hytale.component.ArchetypeChunk;
import java.util.Iterator;
import com.hypixel.hytale.server.core.inventory.container.filter.FilterType;
import com.hypixel.hytale.builtin.crafting.component.CraftingManager;
import com.hypixel.hytale.builtin.crafting.CraftingPlugin;
import com.hypixel.hytale.server.core.inventory.MaterialQuantity;
import com.hypixel.hytale.server.core.inventory.container.filter.SlotFilter;
import com.hypixel.hytale.server.core.inventory.container.filter.ResourceFilter;
import com.hypixel.hytale.server.core.inventory.ResourceQuantity;
import com.hypixel.hytale.server.core.inventory.container.filter.FilterActionType;
import com.hypixel.hytale.event.EventPriority;
import com.hypixel.hytale.server.core.inventory.container.SimpleItemContainer;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.core.universe.world.World;
import java.util.List;
import java.util.logging.Level;
import com.hypixel.hytale.component.Holder;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.ComponentAccessor;
import java.util.Collection;
import com.hypixel.hytale.server.core.inventory.ItemStack;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import java.util.HashSet;
import com.hypixel.hytale.server.core.asset.type.item.config.CraftingRecipe;
import javax.annotation.Nullable;
import java.util.Set;
import com.hypixel.hytale.server.core.inventory.container.CombinedItemContainer;
import com.hypixel.hytale.server.core.inventory.container.ItemContainer;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.bench.ProcessingBench;
import com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapManager;
import com.hypixel.hytale.codec.Codec;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.server.core.universe.world.meta.state.PlacedByBlockState;
import com.hypixel.hytale.server.core.universe.world.meta.state.MarkerBlockState;
import com.hypixel.hytale.server.core.universe.world.meta.state.DestroyableBlockState;
import com.hypixel.hytale.server.core.universe.world.meta.state.ItemContainerBlockState;
import com.hypixel.hytale.server.core.universe.world.chunk.state.TickableBlockState;

public class ProcessingBenchState extends BenchState implements TickableBlockState, ItemContainerBlockState, DestroyableBlockState, MarkerBlockState, PlacedByBlockState
{
    public static final HytaleLogger LOGGER;
    public static final boolean EXACT_RESOURCE_AMOUNTS = true;
    public static final Codec<ProcessingBenchState> CODEC;
    private static final float EJECT_VELOCITY = 2.0f;
    private static final float EJECT_SPREAD_VELOCITY = 1.0f;
    private static final float EJECT_VERTICAL_VELOCITY = 3.25f;
    public static final String PROCESSING = "Processing";
    public static final String PROCESS_COMPLETED = "ProcessCompleted";
    protected WorldMapManager.MarkerReference marker;
    private ProcessingBench processingBench;
    private ItemContainer inputContainer;
    private ItemContainer fuelContainer;
    private ItemContainer outputContainer;
    private CombinedItemContainer combinedItemContainer;
    private float inputProgress;
    private float fuelTime;
    private int lastConsumedFuelTotal;
    private int nextExtra;
    private final Set<Short> processingSlots;
    private final Set<Short> processingFuelSlots;
    @Nullable
    private String recipeId;
    @Nullable
    private CraftingRecipe recipe;
    private boolean active;
    
    public ProcessingBenchState() {
        this.nextExtra = -1;
        this.processingSlots = new HashSet<Short>();
        this.processingFuelSlots = new HashSet<Short>();
        this.active = false;
    }
    
    @Override
    public boolean initialize(@Nonnull final BlockType blockType) {
        if (!super.initialize(blockType)) {
            if (this.bench == null) {
                final List<ItemStack> itemStacks = new ObjectArrayList<ItemStack>();
                if (this.inputContainer != null) {
                    itemStacks.addAll(this.inputContainer.dropAllItemStacks());
                }
                if (this.fuelContainer != null) {
                    itemStacks.addAll(this.fuelContainer.dropAllItemStacks());
                }
                if (this.outputContainer != null) {
                    itemStacks.addAll(this.outputContainer.dropAllItemStacks());
                }
                final World world = this.getChunk().getWorld();
                final Store<EntityStore> store = world.getEntityStore().getStore();
                final Holder<EntityStore>[] itemEntityHolders = this.ejectItems(store, itemStacks);
                if (itemEntityHolders.length > 0) {
                    world.execute(() -> store.addEntities(itemEntityHolders, AddReason.SPAWN));
                }
            }
            return false;
        }
        if (!(this.bench instanceof ProcessingBench)) {
            ProcessingBenchState.LOGGER.at(Level.SEVERE).log("Wrong bench type for processing. Got %s", this.bench.getClass().getName());
            return false;
        }
        this.processingBench = (ProcessingBench)this.bench;
        if (this.nextExtra == -1) {
            this.nextExtra = ((this.processingBench.getExtraOutput() != null) ? this.processingBench.getExtraOutput().getPerFuelItemsConsumed() : 0);
        }
        this.setupSlots();
        return true;
    }
    
    private void setupSlots() {
        final List<ItemStack> remainder = new ObjectArrayList<ItemStack>();
        final int tierLevel = this.getTierLevel();
        final ProcessingBench.ProcessingSlot[] input = this.processingBench.getInput(tierLevel);
        final short inputSlotsCount = (short)input.length;
        (this.inputContainer = ItemContainer.ensureContainerCapacity(this.inputContainer, inputSlotsCount, SimpleItemContainer::getNewContainer, remainder)).registerChangeEvent(EventPriority.LAST, this::onItemChange);
        for (short slot = 0; slot < inputSlotsCount; ++slot) {
            final ProcessingBench.ProcessingSlot inputSlot = input[slot];
            final String resourceTypeId = inputSlot.getResourceTypeId();
            final boolean shouldFilterValidIngredients = inputSlot.shouldFilterValidIngredients();
            if (resourceTypeId != null) {
                this.inputContainer.setSlotFilter(FilterActionType.ADD, slot, new ResourceFilter(new ResourceQuantity(resourceTypeId, 1)));
            }
            else if (shouldFilterValidIngredients) {
                final ObjectArrayList<MaterialQuantity> validIngredients = new ObjectArrayList<MaterialQuantity>();
                final List<CraftingRecipe> recipes = CraftingPlugin.getBenchRecipes(this.bench.getType(), this.bench.getId());
                for (final CraftingRecipe recipe : recipes) {
                    if (recipe.isRestrictedByBenchTierLevel(this.bench.getId(), tierLevel)) {
                        continue;
                    }
                    final List<MaterialQuantity> inputMaterials = CraftingManager.getInputMaterials(recipe);
                    validIngredients.addAll((Collection<?>)inputMaterials);
                }
                this.inputContainer.setSlotFilter(FilterActionType.ADD, slot, (actionType, container, slotIndex, itemStack) -> {
                    if (itemStack == null) {
                        return true;
                    }
                    else {
                        for (final MaterialQuantity ingredient : validIngredients) {
                            if (CraftingManager.matches(ingredient, itemStack)) {
                                return true;
                            }
                        }
                        return false;
                    }
                });
            }
        }
        final ProcessingBench.ProcessingSlot[] benchFuel = this.processingBench.getFuel();
        final short fuelCapacity = (short)((benchFuel != null) ? benchFuel.length : 0);
        (this.fuelContainer = ItemContainer.ensureContainerCapacity(this.fuelContainer, fuelCapacity, SimpleItemContainer::getNewContainer, remainder)).registerChangeEvent(EventPriority.LAST, this::onItemChange);
        if (fuelCapacity > 0) {
            for (int i = 0; i < benchFuel.length; ++i) {
                final ProcessingBench.ProcessingSlot fuel = benchFuel[i];
                final String resourceTypeId = fuel.getResourceTypeId();
                if (resourceTypeId != null) {
                    this.fuelContainer.setSlotFilter(FilterActionType.ADD, (short)i, new ResourceFilter(new ResourceQuantity(resourceTypeId, 1)));
                }
            }
        }
        final short outputSlotsCount = (short)this.processingBench.getOutputSlotsCount(tierLevel);
        (this.outputContainer = ItemContainer.ensureContainerCapacity(this.outputContainer, outputSlotsCount, SimpleItemContainer::getNewContainer, remainder)).registerChangeEvent(EventPriority.LAST, this::onItemChange);
        if (outputSlotsCount > 0) {
            this.outputContainer.setGlobalFilter(FilterType.ALLOW_OUTPUT_ONLY);
        }
        this.combinedItemContainer = new CombinedItemContainer(new ItemContainer[] { this.fuelContainer, this.inputContainer, this.outputContainer });
        final World world = this.getChunk().getWorld();
        final Store<EntityStore> store = world.getEntityStore().getStore();
        final Holder<EntityStore>[] itemEntityHolders = this.ejectItems(store, remainder);
        if (itemEntityHolders.length > 0) {
            world.execute(() -> store.addEntities(itemEntityHolders, AddReason.SPAWN));
        }
        this.inputContainer.registerChangeEvent(EventPriority.LAST, event -> this.updateRecipe());
        if (this.processingBench.getFuel() == null) {
            this.setActive(true);
        }
    }
    
    @Override
    public void tick(final float dt, final int index, final ArchetypeChunk<ChunkStore> archetypeChunk, @Nonnull final Store<ChunkStore> store, final CommandBuffer<ChunkStore> commandBuffer) {
        final World world = store.getExternalData().getWorld();
        final Store<EntityStore> entityStore = world.getEntityStore().getStore();
        final BlockType blockType = this.getBlockType();
        final String currentState = BlockAccessor.getCurrentInteractionState(blockType);
        List<ItemStack> outputItemStacks = null;
        List<MaterialQuantity> inputMaterials = null;
        this.processingSlots.clear();
        this.checkForRecipeUpdate();
        if (this.recipe != null) {
            outputItemStacks = CraftingManager.getOutputItemStacks(this.recipe);
            if (!this.outputContainer.canAddItemStacks(outputItemStacks, false, false)) {
                if ("Processing".equals(currentState)) {
                    this.setBlockInteractionState("default", blockType);
                    this.playSound(world, this.processingBench.getFailedSoundEventIndex(), entityStore);
                }
                else if ("ProcessCompleted".equals(currentState)) {
                    this.setBlockInteractionState("default", blockType);
                    this.playSound(world, this.processingBench.getEndSoundEventIndex(), entityStore);
                }
                this.setActive(false);
                return;
            }
            inputMaterials = CraftingManager.getInputMaterials(this.recipe);
            final List<TestRemoveItemSlotResult> result = this.inputContainer.getSlotMaterialsToRemove(inputMaterials, true, true);
            if (result.isEmpty()) {
                if ("Processing".equals(currentState)) {
                    this.setBlockInteractionState("default", blockType);
                    this.playSound(world, this.processingBench.getFailedSoundEventIndex(), entityStore);
                }
                else if ("ProcessCompleted".equals(currentState)) {
                    this.setBlockInteractionState("default", blockType);
                    this.playSound(world, this.processingBench.getEndSoundEventIndex(), entityStore);
                }
                this.inputProgress = 0.0f;
                this.setActive(false);
                this.recipeId = null;
                this.recipe = null;
                return;
            }
            for (final TestRemoveItemSlotResult item : result) {
                this.processingSlots.addAll(item.getPickedSlots());
            }
            this.sendProcessingSlots();
        }
        else {
            if (this.processingBench.getFuel() == null) {
                if ("Processing".equals(currentState)) {
                    this.setBlockInteractionState("default", blockType);
                    this.playSound(world, this.processingBench.getFailedSoundEventIndex(), entityStore);
                }
                else if ("ProcessCompleted".equals(currentState)) {
                    this.setBlockInteractionState("default", blockType);
                    this.playSound(world, this.processingBench.getEndSoundEventIndex(), entityStore);
                }
                return;
            }
            final boolean allowNoInputProcessing = this.processingBench.shouldAllowNoInputProcessing();
            if (!allowNoInputProcessing && "Processing".equals(currentState)) {
                this.setBlockInteractionState("default", blockType);
                this.playSound(world, this.processingBench.getFailedSoundEventIndex(), entityStore);
            }
            else if ("ProcessCompleted".equals(currentState)) {
                this.setBlockInteractionState("default", blockType);
                this.playSound(world, this.processingBench.getEndSoundEventIndex(), entityStore);
                this.setActive(false);
                this.sendProgress(0.0f);
                return;
            }
            this.sendProgress(0.0f);
            if (!allowNoInputProcessing) {
                this.setActive(false);
                return;
            }
        }
        boolean needsUpdate = false;
        if (this.fuelTime > 0.0f && this.active) {
            this.fuelTime -= dt;
            if (this.fuelTime < 0.0f) {
                this.fuelTime = 0.0f;
            }
            needsUpdate = true;
        }
        final ProcessingBench.ProcessingSlot[] fuelSlots = this.processingBench.getFuel();
        final boolean hasFuelSlots = fuelSlots != null && fuelSlots.length > 0;
        if ((this.processingBench.getMaxFuel() <= 0 || this.fuelTime < this.processingBench.getMaxFuel()) && !this.fuelContainer.isEmpty()) {
            if (!hasFuelSlots) {
                return;
            }
            if (this.active) {
                if (this.fuelTime > 0.0f) {
                    for (int i = 0; i < fuelSlots.length; ++i) {
                        final ItemStack itemInSlot = this.fuelContainer.getItemStack((short)i);
                        if (itemInSlot != null) {
                            this.processingFuelSlots.add((short)i);
                            break;
                        }
                    }
                }
                else {
                    if (this.fuelTime < 0.0f) {
                        this.fuelTime = 0.0f;
                    }
                    this.processingFuelSlots.clear();
                    for (int i = 0; i < fuelSlots.length; ++i) {
                        final ProcessingBench.ProcessingSlot fuelSlot = fuelSlots[i];
                        final String resourceTypeId = (fuelSlot.getResourceTypeId() != null) ? fuelSlot.getResourceTypeId() : "Fuel";
                        final ResourceQuantity resourceQuantity = new ResourceQuantity(resourceTypeId, 1);
                        final ItemStack slot = this.fuelContainer.getItemStack((short)i);
                        if (slot != null) {
                            final double fuelQuality = slot.getItem().getFuelQuality();
                            final ResourceTransaction transaction = this.fuelContainer.removeResource(resourceQuantity, true, true, true);
                            this.processingFuelSlots.add((short)i);
                            if (transaction.getRemainder() <= 0) {
                                final ProcessingBench.ExtraOutput extra = this.processingBench.getExtraOutput();
                                if (extra != null && !extra.isIgnoredFuelSource(slot.getItem())) {
                                    --this.nextExtra;
                                    if (this.nextExtra <= 0) {
                                        this.nextExtra = extra.getPerFuelItemsConsumed();
                                        final ObjectArrayList<ItemStack> extraItemStacks = new ObjectArrayList<ItemStack>(extra.getOutputs().length);
                                        for (final MaterialQuantity e : extra.getOutputs()) {
                                            extraItemStacks.add(e.toItemStack());
                                        }
                                        final ListTransaction<ItemStackTransaction> addTransaction = this.outputContainer.addItemStacks(extraItemStacks, false, false, false);
                                        final List<ItemStack> remainderItems = new ObjectArrayList<ItemStack>();
                                        for (final ItemStackTransaction itemStackTransaction : addTransaction.getList()) {
                                            final ItemStack remainder = itemStackTransaction.getRemainder();
                                            if (remainder != null && !remainder.isEmpty()) {
                                                remainderItems.add(remainder);
                                            }
                                        }
                                        if (!remainderItems.isEmpty()) {
                                            ProcessingBenchState.LOGGER.at(Level.WARNING).log("Dropping excess items at %s", this.getBlockPosition());
                                            final Holder<EntityStore>[] itemEntityHolders = this.ejectItems(entityStore, remainderItems);
                                            entityStore.addEntities(itemEntityHolders, AddReason.SPAWN);
                                        }
                                    }
                                }
                                this.fuelTime += (float)(transaction.getConsumed() * fuelQuality);
                                needsUpdate = true;
                                break;
                            }
                        }
                    }
                }
            }
        }
        if (needsUpdate) {
            this.updateFuelValues();
        }
        if (hasFuelSlots && (!this.active || this.fuelTime <= 0.0f)) {
            this.lastConsumedFuelTotal = 0;
            if ("Processing".equals(currentState)) {
                this.setBlockInteractionState("default", blockType);
                this.playSound(world, this.processingBench.getFailedSoundEventIndex(), entityStore);
                if (this.processingBench.getFuel() != null) {
                    this.setActive(false);
                }
            }
            else if ("ProcessCompleted".equals(currentState)) {
                this.setBlockInteractionState("default", blockType);
                this.playSound(world, this.processingBench.getFailedSoundEventIndex(), entityStore);
                if (this.processingBench.getFuel() != null) {
                    this.setActive(false);
                }
            }
            return;
        }
        if (!"Processing".equals(currentState)) {
            this.setBlockInteractionState("Processing", blockType);
        }
        if (this.recipe != null && (this.fuelTime > 0.0f || this.processingBench.getFuel() == null)) {
            this.inputProgress += dt;
        }
        if (this.recipe != null) {
            float recipeTime = this.recipe.getTimeSeconds();
            final float craftingTimeReductionModifier = this.getCraftingTimeReductionModifier();
            if (craftingTimeReductionModifier > 0.0f) {
                recipeTime -= recipeTime * craftingTimeReductionModifier;
            }
            if (this.inputProgress > recipeTime) {
                if (recipeTime > 0.0f) {
                    this.inputProgress -= recipeTime;
                    final float progressPercent = this.inputProgress / recipeTime;
                    this.sendProgress(progressPercent);
                }
                else {
                    this.sendProgress(this.inputProgress = 0.0f);
                }
                ProcessingBenchState.LOGGER.at(Level.FINE).log("Do Process for %s %s", this.recipeId, this.recipe);
                if (inputMaterials != null) {
                    final List<ItemStack> remainderItems2 = new ObjectArrayList<ItemStack>();
                    int success = 0;
                    final IntArrayList slots = new IntArrayList();
                    for (int j = 0; j < this.inputContainer.getCapacity(); ++j) {
                        slots.add(j);
                    }
                    for (final MaterialQuantity material : inputMaterials) {
                        for (int k = 0; k < slots.size(); ++k) {
                            final int slot2 = slots.getInt(k);
                            final MaterialSlotTransaction transaction2 = this.inputContainer.removeMaterialFromSlot((short)slot2, material, true, true, true);
                            if (transaction2.succeeded()) {
                                ++success;
                                slots.removeInt(k);
                                break;
                            }
                        }
                    }
                    final ListTransaction<ItemStackTransaction> addTransaction2 = this.outputContainer.addItemStacks(outputItemStacks, false, false, false);
                    if (!addTransaction2.succeeded()) {
                        return;
                    }
                    for (final ItemStackTransaction itemStackTransaction2 : addTransaction2.getList()) {
                        final ItemStack remainder2 = itemStackTransaction2.getRemainder();
                        if (remainder2 != null && !remainder2.isEmpty()) {
                            remainderItems2.add(remainder2);
                        }
                    }
                    if (success == inputMaterials.size()) {
                        this.setBlockInteractionState("ProcessCompleted", blockType);
                        this.playSound(world, this.bench.getCompletedSoundEventIndex(), entityStore);
                        if (!remainderItems2.isEmpty()) {
                            ProcessingBenchState.LOGGER.at(Level.WARNING).log("Dropping excess items at %s", this.getBlockPosition());
                            final Holder<EntityStore>[] itemEntityHolders2 = this.ejectItems(entityStore, remainderItems2);
                            entityStore.addEntities(itemEntityHolders2, AddReason.SPAWN);
                        }
                        return;
                    }
                }
                final List<ItemStack> remainderItems2 = new ObjectArrayList<ItemStack>();
                final ListTransaction<MaterialTransaction> transaction3 = this.inputContainer.removeMaterials(inputMaterials, true, true, true);
                if (!transaction3.succeeded()) {
                    ProcessingBenchState.LOGGER.at(Level.WARNING).log("Failed to remove input materials at %s", this.getBlockPosition());
                    this.setBlockInteractionState("default", blockType);
                    this.playSound(world, this.processingBench.getFailedSoundEventIndex(), entityStore);
                    return;
                }
                this.setBlockInteractionState("ProcessCompleted", blockType);
                this.playSound(world, this.bench.getCompletedSoundEventIndex(), entityStore);
                final ListTransaction<ItemStackTransaction> addTransaction3 = this.outputContainer.addItemStacks(outputItemStacks, false, false, false);
                if (addTransaction3.succeeded()) {
                    return;
                }
                ProcessingBenchState.LOGGER.at(Level.WARNING).log("Dropping excess items at %s", this.getBlockPosition());
                for (final ItemStackTransaction itemStackTransaction3 : addTransaction3.getList()) {
                    final ItemStack remainder3 = itemStackTransaction3.getRemainder();
                    if (remainder3 != null && !remainder3.isEmpty()) {
                        remainderItems2.add(remainder3);
                    }
                }
                final Holder<EntityStore>[] itemEntityHolders3 = this.ejectItems(entityStore, remainderItems2);
                entityStore.addEntities(itemEntityHolders3, AddReason.SPAWN);
            }
            else if (this.recipe != null && recipeTime > 0.0f) {
                final float progressPercent = this.inputProgress / recipeTime;
                this.sendProgress(progressPercent);
            }
            else {
                this.sendProgress(0.0f);
            }
        }
    }
    
    private float getCraftingTimeReductionModifier() {
        final BenchTierLevel levelData = this.bench.getTierLevel(this.getTierLevel());
        return (levelData != null) ? levelData.getCraftingTimeReductionModifier() : 0.0f;
    }
    
    @Nonnull
    private Holder<EntityStore>[] ejectItems(@Nonnull final ComponentAccessor<EntityStore> accessor, @Nonnull final List<ItemStack> itemStacks) {
        if (itemStacks.isEmpty()) {
            return Holder.emptyArray();
        }
        final RotationTuple rotation = RotationTuple.get(this.getRotationIndex());
        final Vector3d frontDir = new Vector3d(0.0, 0.0, 1.0);
        rotation.yaw().rotateY(frontDir, frontDir);
        final BlockType blockType = this.getBlockType();
        Vector3d dropPosition;
        if (blockType == null) {
            dropPosition = this.getBlockPosition().toVector3d().add(0.5, 0.0, 0.5);
        }
        else {
            final BlockBoundingBoxes hitboxAsset = BlockBoundingBoxes.getAssetMap().getAsset(blockType.getHitboxTypeIndex());
            if (hitboxAsset == null) {
                dropPosition = this.getBlockPosition().toVector3d().add(0.5, 0.0, 0.5);
            }
            else {
                final double depth = hitboxAsset.get(0).getBoundingBox().depth();
                final double frontOffset = depth / 2.0 + 0.10000000149011612;
                dropPosition = this.getCenteredBlockPosition();
                dropPosition.add(frontDir.x * frontOffset, 0.0, frontDir.z * frontOffset);
            }
        }
        final ThreadLocalRandom random = ThreadLocalRandom.current();
        final ObjectArrayList<Holder<EntityStore>> result = new ObjectArrayList<Holder<EntityStore>>(itemStacks.size());
        for (final ItemStack item : itemStacks) {
            final float velocityX = (float)(frontDir.x * 2.0 + 2.0 * (random.nextDouble() - 0.5));
            final float velocityZ = (float)(frontDir.z * 2.0 + 2.0 * (random.nextDouble() - 0.5));
            final Holder<EntityStore> holder = ItemComponent.generateItemDrop(accessor, item, dropPosition, Vector3f.ZERO, velocityX, 3.25f, velocityZ);
            if (holder != null) {
                result.add(holder);
            }
        }
        return result.toArray(Holder[]::new);
    }
    
    private void sendProgress(final float progress) {
        this.windows.forEach((uuid, window) -> ((ProcessingBenchWindow)window).setProgress(progress));
    }
    
    private void sendProcessingSlots() {
        this.windows.forEach((uuid, window) -> ((ProcessingBenchWindow)window).setProcessingSlots(this.processingSlots));
    }
    
    private void sendProcessingFuelSlots() {
        this.windows.forEach((uuid, window) -> ((ProcessingBenchWindow)window).setProcessingFuelSlots(this.processingFuelSlots));
    }
    
    public boolean isActive() {
        return this.active;
    }
    
    public boolean setActive(final boolean active) {
        if (this.active == active) {
            return false;
        }
        if (active && this.processingBench.getFuel() != null && this.fuelContainer.isEmpty()) {
            return false;
        }
        if (!(this.active = active)) {
            this.processingSlots.clear();
            this.processingFuelSlots.clear();
            this.sendProcessingSlots();
            this.sendProcessingFuelSlots();
        }
        this.updateRecipe();
        this.windows.forEach((uuid, window) -> ((ProcessingBenchWindow)window).setActive(active));
        this.markNeedsSave();
        return true;
    }
    
    public void updateFuelValues() {
        if (this.fuelTime > this.lastConsumedFuelTotal) {
            this.lastConsumedFuelTotal = MathUtil.ceil(this.fuelTime);
        }
        final float fuelPercent = (this.lastConsumedFuelTotal > 0) ? (this.fuelTime / this.lastConsumedFuelTotal) : 0.0f;
        this.windows.forEach((uuid, window) -> {
            final ProcessingBenchWindow processingBenchWindow = (ProcessingBenchWindow)window;
            processingBenchWindow.setFuelTime(fuelPercent);
            processingBenchWindow.setMaxFuel(this.lastConsumedFuelTotal);
            processingBenchWindow.setProcessingFuelSlots(this.processingFuelSlots);
        });
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        if (this.combinedItemContainer != null) {
            final List<ItemStack> itemStacks = this.combinedItemContainer.dropAllItemStacks();
            this.dropFuelItems(itemStacks);
            final World world = this.getChunk().getWorld();
            final Store<EntityStore> entityStore = world.getEntityStore().getStore();
            final Vector3d dropPosition = this.getBlockPosition().toVector3d().add(0.5, 0.0, 0.5);
            final Holder<EntityStore>[] itemEntityHolders = ItemComponent.generateItemDrops(entityStore, itemStacks, dropPosition, Vector3f.ZERO);
            if (itemEntityHolders.length > 0) {
                world.execute(() -> entityStore.addEntities(itemEntityHolders, AddReason.SPAWN));
            }
        }
        if (this.marker != null) {
            this.marker.remove();
        }
    }
    
    @Override
    public CombinedItemContainer getItemContainer() {
        return this.combinedItemContainer;
    }
    
    private void checkForRecipeUpdate() {
        if (this.recipe == null && this.recipeId != null) {
            this.updateRecipe();
        }
    }
    
    private void updateRecipe() {
        final List<CraftingRecipe> recipes = CraftingPlugin.getBenchRecipes(this.bench.getType(), this.bench.getId());
        if (recipes.isEmpty()) {
            this.clearRecipe();
            return;
        }
        final List<CraftingRecipe> matching = new ObjectArrayList<CraftingRecipe>();
        for (final CraftingRecipe recipe : recipes) {
            if (recipe.isRestrictedByBenchTierLevel(this.bench.getId(), this.getTierLevel())) {
                continue;
            }
            final MaterialQuantity[] input = recipe.getInput();
            int matches = 0;
            final IntArrayList slots = new IntArrayList();
            for (int j = 0; j < this.inputContainer.getCapacity(); ++j) {
                slots.add(j);
            }
            for (final MaterialQuantity craftingMaterial : input) {
                final String itemId = craftingMaterial.getItemId();
                final String resourceTypeId = craftingMaterial.getResourceTypeId();
                final int materialQuantity = craftingMaterial.getQuantity();
                final BsonDocument metadata = craftingMaterial.getMetadata();
                final MaterialQuantity material = new MaterialQuantity(itemId, resourceTypeId, null, materialQuantity, metadata);
                for (int k = 0; k < slots.size(); ++k) {
                    final int i = slots.getInt(k);
                    final int out = InternalContainerUtilMaterial.testRemoveMaterialFromSlot(this.inputContainer, (short)i, material, material.getQuantity(), true);
                    if (out == 0) {
                        ++matches;
                        slots.removeInt(k);
                        break;
                    }
                }
            }
            if (matches != input.length) {
                continue;
            }
            matching.add(recipe);
        }
        if (matching.isEmpty()) {
            this.clearRecipe();
            return;
        }
        matching.sort(Comparator.comparingInt(o -> CraftingManager.getInputMaterials(o).size()));
        Collections.reverse(matching);
        if (this.recipeId != null) {
            for (final CraftingRecipe rec : matching) {
                if (Objects.equals(this.recipeId, rec.getId())) {
                    ProcessingBenchState.LOGGER.at(Level.FINE).log("%s - Keeping existing Recipe %s %s", LazyArgs.lazy(this::getBlockPosition), this.recipeId, rec);
                    this.recipe = rec;
                    return;
                }
            }
        }
        final CraftingRecipe recipe2 = matching.getFirst();
        if (this.recipeId == null || !Objects.equals(this.recipeId, recipe2.getId())) {
            this.sendProgress(this.inputProgress = 0.0f);
        }
        this.recipeId = recipe2.getId();
        this.recipe = recipe2;
        ProcessingBenchState.LOGGER.at(Level.FINE).log("%s - Found Recipe %s %s", LazyArgs.lazy(this::getBlockPosition), this.recipeId, this.recipe);
    }
    
    private void clearRecipe() {
        this.recipeId = null;
        this.recipe = null;
        this.lastConsumedFuelTotal = 0;
        this.sendProgress(this.inputProgress = 0.0f);
        ProcessingBenchState.LOGGER.at(Level.FINE).log("%s - Cleared Recipe", LazyArgs.lazy(this::getBlockPosition));
    }
    
    public void dropFuelItems(@Nonnull final List<ItemStack> itemStacks) {
        final String fuelDropItemId = this.processingBench.getFuelDropItemId();
        if (fuelDropItemId != null) {
            final Item item = Item.getAssetMap().getAsset(fuelDropItemId);
            int dropAmount = (int)this.fuelTime;
            this.fuelTime = 0.0f;
            while (dropAmount > 0) {
                final int quantity = Math.min(dropAmount, item.getMaxStack());
                itemStacks.add(new ItemStack(fuelDropItemId, quantity));
                dropAmount -= quantity;
            }
        }
        else {
            ProcessingBenchState.LOGGER.at(Level.WARNING).log("No FuelDropItemId defined for %s fuel value of %s will be lost!", this.bench.getId(), this.fuelTime);
        }
    }
    
    @Nullable
    public CraftingRecipe getRecipe() {
        return this.recipe;
    }
    
    public float getInputProgress() {
        return this.inputProgress;
    }
    
    public void onItemChange(final ItemContainer.ItemContainerChangeEvent event) {
        this.markNeedsSave();
    }
    
    public void setBlockInteractionState(@Nonnull final String state, @Nonnull final BlockType blockType) {
        this.getChunk().setBlockInteractionState(this.getBlockPosition(), blockType, state);
    }
    
    @Override
    public void setMarker(final WorldMapManager.MarkerReference marker) {
        this.marker = marker;
        this.markNeedsSave();
    }
    
    @Override
    public void placedBy(@Nonnull final Ref<EntityStore> playerRef, @Nonnull final String blockTypeKey, @Nonnull final BlockState blockState, @Nonnull final ComponentAccessor<EntityStore> componentAccessor) {
        if (blockTypeKey.equals(this.processingBench.getIconItem()) && this.processingBench.getIcon() != null) {
            final Player playerComponent = componentAccessor.getComponent(playerRef, Player.getComponentType());
            assert playerComponent != null;
            final TransformComponent transformComponent = componentAccessor.getComponent(playerRef, TransformComponent.getComponentType());
            assert transformComponent != null;
            final Transform transformPacket = PositionUtil.toTransformPacket(transformComponent.getTransform());
            transformPacket.orientation.yaw = 0.0f;
            transformPacket.orientation.pitch = 0.0f;
            transformPacket.orientation.roll = 0.0f;
            final MapMarker marker = new MapMarker(this.processingBench.getIconId() + "-" + String.valueOf(UUID.randomUUID()), this.processingBench.getIconName(), this.processingBench.getIcon(), transformPacket, (ContextMenuItem[])null);
            ((MarkerBlockState)blockState).setMarker(WorldMapManager.createPlayerMarker(playerRef, marker, componentAccessor));
        }
    }
    
    private void playSound(@Nonnull final World world, final int soundEventIndex, @Nonnull final ComponentAccessor<EntityStore> componentAccessor) {
        if (soundEventIndex == 0) {
            return;
        }
        final Vector3i pos = this.getBlockPosition();
        SoundUtil.playSoundEvent3d(soundEventIndex, SoundCategory.SFX, pos.x + 0.5, pos.y + 0.5, pos.z + 0.5, componentAccessor);
    }
    
    @Override
    protected void onTierLevelChange() {
        super.onTierLevelChange();
        this.setupSlots();
    }
    
    static {
        // 
        // This method could not be decompiled.
        // 
        // Original Bytecode:
        // 
        //     2: invokevirtual   java/lang/Class.desiredAssertionStatus:()Z
        //     5: ifne            12
        //     8: iconst_1       
        //     9: goto            13
        //    12: iconst_0       
        //    13: putstatic       com/hypixel/hytale/builtin/crafting/state/ProcessingBenchState.$assertionsDisabled:Z
        //    16: invokestatic    com/hypixel/hytale/logger/HytaleLogger.forEnclosingClass:()Lcom/hypixel/hytale/logger/HytaleLogger;
        //    19: putstatic       com/hypixel/hytale/builtin/crafting/state/ProcessingBenchState.LOGGER:Lcom/hypixel/hytale/logger/HytaleLogger;
        //    22: ldc             Lcom/hypixel/hytale/builtin/crafting/state/ProcessingBenchState;.class
        //    24: invokedynamic   BootstrapMethod #16, get:()Ljava/util/function/Supplier;
        //    29: getstatic       com/hypixel/hytale/builtin/crafting/state/BenchState.CODEC:Lcom/hypixel/hytale/codec/builder/BuilderCodec;
        //    32: invokestatic    com/hypixel/hytale/codec/builder/BuilderCodec.builder:(Ljava/lang/Class;Ljava/util/function/Supplier;Lcom/hypixel/hytale/codec/builder/BuilderCodec;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //    35: new             Lcom/hypixel/hytale/codec/KeyedCodec;
        //    38: dup            
        //    39: ldc_w           "InputContainer"
        //    42: getstatic       com/hypixel/hytale/server/core/inventory/container/ItemContainer.CODEC:Lcom/hypixel/hytale/codec/lookup/CodecMapCodec;
        //    45: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
        //    48: invokedynamic   BootstrapMethod #17, accept:()Ljava/util/function/BiConsumer;
        //    53: invokedynamic   BootstrapMethod #18, apply:()Ljava/util/function/Function;
        //    58: 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;
        //    61: invokevirtual   com/hypixel/hytale/codec/builder/BuilderField$FieldBuilder.add:()Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
        //    64: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //    67: new             Lcom/hypixel/hytale/codec/KeyedCodec;
        //    70: dup            
        //    71: ldc_w           "FuelContainer"
        //    74: getstatic       com/hypixel/hytale/server/core/inventory/container/ItemContainer.CODEC:Lcom/hypixel/hytale/codec/lookup/CodecMapCodec;
        //    77: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
        //    80: invokedynamic   BootstrapMethod #19, accept:()Ljava/util/function/BiConsumer;
        //    85: invokedynamic   BootstrapMethod #20, apply:()Ljava/util/function/Function;
        //    90: 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;
        //    93: invokevirtual   com/hypixel/hytale/codec/builder/BuilderField$FieldBuilder.add:()Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
        //    96: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //    99: new             Lcom/hypixel/hytale/codec/KeyedCodec;
        //   102: dup            
        //   103: ldc_w           "OutputContainer"
        //   106: getstatic       com/hypixel/hytale/server/core/inventory/container/ItemContainer.CODEC:Lcom/hypixel/hytale/codec/lookup/CodecMapCodec;
        //   109: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
        //   112: invokedynamic   BootstrapMethod #21, accept:()Ljava/util/function/BiConsumer;
        //   117: invokedynamic   BootstrapMethod #22, apply:()Ljava/util/function/Function;
        //   122: 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;
        //   125: invokevirtual   com/hypixel/hytale/codec/builder/BuilderField$FieldBuilder.add:()Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
        //   128: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //   131: new             Lcom/hypixel/hytale/codec/KeyedCodec;
        //   134: dup            
        //   135: ldc_w           "Progress"
        //   138: getstatic       com/hypixel/hytale/codec/Codec.DOUBLE:Lcom/hypixel/hytale/codec/codecs/simple/DoubleCodec;
        //   141: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
        //   144: invokedynamic   BootstrapMethod #23, accept:()Ljava/util/function/BiConsumer;
        //   149: invokedynamic   BootstrapMethod #24, apply:()Ljava/util/function/Function;
        //   154: 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;
        //   157: invokevirtual   com/hypixel/hytale/codec/builder/BuilderField$FieldBuilder.add:()Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
        //   160: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //   163: new             Lcom/hypixel/hytale/codec/KeyedCodec;
        //   166: dup            
        //   167: ldc_w           "FuelTime"
        //   170: getstatic       com/hypixel/hytale/codec/Codec.DOUBLE:Lcom/hypixel/hytale/codec/codecs/simple/DoubleCodec;
        //   173: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
        //   176: invokedynamic   BootstrapMethod #25, accept:()Ljava/util/function/BiConsumer;
        //   181: invokedynamic   BootstrapMethod #26, apply:()Ljava/util/function/Function;
        //   186: 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;
        //   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           "Active"
        //   202: getstatic       com/hypixel/hytale/codec/Codec.BOOLEAN:Lcom/hypixel/hytale/codec/codecs/simple/BooleanCodec;
        //   205: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
        //   208: invokedynamic   BootstrapMethod #27, accept:()Ljava/util/function/BiConsumer;
        //   213: invokedynamic   BootstrapMethod #28, 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           "NextExtra"
        //   234: getstatic       com/hypixel/hytale/codec/Codec.INTEGER:Lcom/hypixel/hytale/codec/codecs/simple/IntegerCodec;
        //   237: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
        //   240: invokedynamic   BootstrapMethod #29, accept:()Ljava/util/function/BiConsumer;
        //   245: invokedynamic   BootstrapMethod #30, 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: new             Lcom/hypixel/hytale/codec/KeyedCodec;
        //   262: dup            
        //   263: ldc_w           "Marker"
        //   266: getstatic       com/hypixel/hytale/server/core/universe/world/worldmap/WorldMapManager$MarkerReference.CODEC:Lcom/hypixel/hytale/codec/lookup/CodecMapCodec;
        //   269: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
        //   272: invokedynamic   BootstrapMethod #31, accept:()Ljava/util/function/BiConsumer;
        //   277: invokedynamic   BootstrapMethod #32, apply:()Ljava/util/function/Function;
        //   282: 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;
        //   285: invokevirtual   com/hypixel/hytale/codec/builder/BuilderField$FieldBuilder.add:()Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
        //   288: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //   291: new             Lcom/hypixel/hytale/codec/KeyedCodec;
        //   294: dup            
        //   295: ldc_w           "RecipeId"
        //   298: getstatic       com/hypixel/hytale/codec/Codec.STRING:Lcom/hypixel/hytale/codec/codecs/simple/StringCodec;
        //   301: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
        //   304: invokedynamic   BootstrapMethod #33, accept:()Ljava/util/function/BiConsumer;
        //   309: invokedynamic   BootstrapMethod #34, apply:()Ljava/util/function/Function;
        //   314: 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;
        //   317: invokevirtual   com/hypixel/hytale/codec/builder/BuilderField$FieldBuilder.add:()Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
        //   320: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //   323: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.build:()Lcom/hypixel/hytale/codec/builder/BuilderCodec;
        //   326: putstatic       com/hypixel/hytale/builtin/crafting/state/ProcessingBenchState.CODEC:Lcom/hypixel/hytale/codec/Codec;
        //   329: return         
        //    StackMapTable: 00 02 0C 40 01
        // 
        // 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.visitClassType(TypeSubstitutionVisitor.java:267)
        //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitClassType(TypeSubstitutionVisitor.java:25)
        //     at com.strobel.assembler.metadata.TypeDefinition.accept(TypeDefinition.java:189)
        //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visit(TypeSubstitutionVisitor.java:40)
        //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitMethod(TypeSubstitutionVisitor.java:324)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2586)
        //     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: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: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.inferCall(TypeAnalysis.java:2483)
        //     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:782)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2483)
        //     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.inferCall(TypeAnalysis.java:2483)
        //     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:782)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2483)
        //     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.inferCall(TypeAnalysis.java:2483)
        //     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:782)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2483)
        //     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.");
    }
}
