public new BarrelRecipeIngredient Clone()
        {
            BarrelRecipeIngredient stack = new BarrelRecipeIngredient()
            {
                Code              = Code.Clone(),
                Type              = Type,
                Name              = Name,
                Quantity          = Quantity,
                ConsumeQuantity   = ConsumeQuantity,
                ConsumeLitres     = ConsumeLitres,
                IsWildCard        = IsWildCard,
                IsTool            = IsTool,
                Litres            = Litres,
                AllowedVariants   = AllowedVariants == null ? null : (string[])AllowedVariants.Clone(),
                ResolvedItemstack = ResolvedItemstack?.Clone(),
                ReturnedStack     = ReturnedStack?.Clone()
            };

            if (Attributes != null)
            {
                stack.Attributes = Attributes.Clone();
            }

            return(stack);
        }
        List <KeyValuePair <ItemSlot, BarrelRecipeIngredient> > pairInput(ItemSlot[] inputStacks)
        {
            List <BarrelRecipeIngredient> ingredientList = new List <BarrelRecipeIngredient>(Ingredients);

            Queue <ItemSlot> inputSlotsList = new Queue <ItemSlot>();

            foreach (var val in inputStacks)
            {
                if (!val.Empty)
                {
                    inputSlotsList.Enqueue(val);
                }
            }

            if (inputSlotsList.Count != Ingredients.Length)
            {
                return(null);
            }

            List <KeyValuePair <ItemSlot, BarrelRecipeIngredient> > matched = new List <KeyValuePair <ItemSlot, BarrelRecipeIngredient> >();

            while (inputSlotsList.Count > 0)
            {
                ItemSlot inputSlot = inputSlotsList.Dequeue();
                bool     found     = false;

                for (int i = 0; i < ingredientList.Count; i++)
                {
                    BarrelRecipeIngredient ingred = ingredientList[i];

                    if (ingred.SatisfiesAsIngredient(inputSlot.Itemstack))
                    {
                        matched.Add(new KeyValuePair <ItemSlot, BarrelRecipeIngredient>(inputSlot, ingred));
                        found = true;
                        ingredientList.RemoveAt(i);
                        break;
                    }
                }

                if (!found)
                {
                    return(null);
                }
            }

            // We're missing ingredients
            if (ingredientList.Count > 0)
            {
                return(null);
            }

            return(matched);
        }
        int getOutputSize(List <KeyValuePair <ItemSlot, BarrelRecipeIngredient> > matched)
        {
            int outQuantityMul = -1;

            foreach (var val in matched)
            {
                ItemSlot inputSlot            = val.Key;
                BarrelRecipeIngredient ingred = val.Value;

                if (ingred.ConsumeQuantity == null)
                {
                    outQuantityMul = inputSlot.StackSize / ingred.Quantity;
                }
            }

            if (outQuantityMul == -1)
            {
                return(-1);
            }


            foreach (var val in matched)
            {
                ItemSlot inputSlot            = val.Key;
                BarrelRecipeIngredient ingred = val.Value;

                if (ingred.ConsumeQuantity == null)
                {
                    // Input stack size must be equal or a multiple of the ingredient stack size
                    if ((inputSlot.StackSize % ingred.Quantity) != 0)
                    {
                        return(-1);
                    }

                    // Ingredients must be at the same ratio
                    if (outQuantityMul != inputSlot.StackSize / ingred.Quantity)
                    {
                        return(-1);
                    }
                }
                else
                {
                    // Must have same or more than the total crafted amount
                    if (inputSlot.StackSize < ingred.Quantity * outQuantityMul)
                    {
                        return(-1);
                    }
                }
            }

            return(Output.StackSize * outQuantityMul);
        }
        /// <summary>
        /// Deserializes the alloy
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="resolver"></param>
        public void FromBytes(BinaryReader reader, IWorldAccessor resolver)
        {
            Code        = reader.ReadString();
            Ingredients = new BarrelRecipeIngredient[reader.ReadInt32()];

            for (int i = 0; i < Ingredients.Length; i++)
            {
                Ingredients[i] = new BarrelRecipeIngredient();
                Ingredients[i].FromBytes(reader, resolver);
                Ingredients[i].Resolve(resolver, "Barrel Recipe (FromBytes)");
            }

            Output = new BarrelOutputStack();
            Output.FromBytes(reader, resolver.ClassRegistry);
            Output.Resolve(resolver, "Barrel Recipe (FromBytes)");

            SealHours = reader.ReadDouble();
        }
        public BarrelRecipe Clone()
        {
            BarrelRecipeIngredient[] ingredients = new BarrelRecipeIngredient[Ingredients.Length];
            for (int i = 0; i < Ingredients.Length; i++)
            {
                ingredients[i] = Ingredients[i].Clone();
            }

            return(new BarrelRecipe()
            {
                SealHours = SealHours,
                Output = Output.Clone(),
                Code = Code,
                Enabled = Enabled,
                Name = Name,
                RecipeId = RecipeId,
                Ingredients = ingredients
            });
        }