Not compiling after update

165 QuickSmelt - Failed to compile: 'ItemModCookable' does not contain a definition for 'CanBeCookedByAtTemperature' and no accessible extension method 'CanBeCookedByAtTemperature' accepting a first argument of type 'ItemModCookable' could be found (are you missing a using directive or an assembly reference?) | Line: 495, Pos: 35

I'm getting this error. Looking to see if there is an update for this plugin. 
Error while compiling QuickSmelt: 'ItemModCookable' does not contain a definition for 'CanBeCookedByAtTemperature' and no accessible extension method 'CanBeCookedByAtTemperature' accepting a first argument of type 'ItemModCookable' could be found (are you missing a using directive or an assembly reference?) | Line: 478, Pos: 35

same here, need normal fix

I did fix that but now it wast more wood instand

I used to use Umod QuickSmelt, but because of this type of issue I started to use Quick Smelt by Scalbox from DigitalMarketPlay. Unfortunately it's also broken since the update, but unlike this developer Scalbox keeps his up to date, but it's weekend now, so this will only happen next week I assume. However, it's also a free plugin, and I fixed it temporarily by editing line 604:

if ((temperature < cookable.lowTemp || temperature > cookable.highTemp) && isAllowed == null)

Open the CS file. Hit Ctrl+F. Enter the following in the search tab and hit ENTER: CanBeCookedByAtTemperature

You'll see the following: if (!cookable.CanBeCookedByAtTemperature(temperature) && isAllowed == null)

Change this to: if ((temperature < cookable.lowTemp || temperature > cookable.highTemp) && isAllowed == null)

These plugins are both exactly the same (fork) so it should work on this one too.

using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
using Random = UnityEngine.Random;

namespace Oxide.Plugins
{
    [Info("Quick Smelt", "misticos", "5.1.5")]
    [Description("Increases the speed of the furnace smelting")]
    class QuickSmelt : RustPlugin
    {
        #region Variables

        private static QuickSmelt _instance;

        private const string PermissionUse = "quicksmelt.use";

        #endregion

        #region Configuration

        private static Configuration _config;

        private class Configuration
        {
            [JsonProperty(PropertyName = "Use Permission")]
            public bool UsePermission = true;

            [JsonProperty(PropertyName = "Speed Multipliers", ObjectCreationHandling = ObjectCreationHandling.Replace)]
            public Dictionary<string, float> SpeedMultipliers = new Dictionary<string, float>
            {
                { "global", 1.0f },
                { "furnace.shortname", 1.0f }
            };

            [JsonProperty(PropertyName = "Fuel Usage Speed Multipliers",
                ObjectCreationHandling = ObjectCreationHandling.Replace)]
            public Dictionary<string, float> FuelSpeedMultipliers = new Dictionary<string, float>
            {
                { "global", 1.0f },
                { "furnace.shortname", 1.0f }
            };

            [JsonProperty(PropertyName = "Fuel Usage Multipliers",
                ObjectCreationHandling = ObjectCreationHandling.Replace)]
            public Dictionary<string, int> FuelUsageMultipliers = new Dictionary<string, int>
            {
                { "global", 1 },
                { "furnace.shortname", 1 }
            };

            [JsonProperty(PropertyName = "Output Multipliers", ObjectCreationHandling = ObjectCreationHandling.Replace)]
            public Dictionary<string, Dictionary<string, float>> OutputMultipliers =
                new Dictionary<string, Dictionary<string, float>>
                {
                    {
                        "global", new Dictionary<string, float>
                        {
                            { "global", 1.0f }
                        }
                    },
                    {
                        "furnace.shortname", new Dictionary<string, float>
                        {
                            { "item.shortname", 1.0f }
                        }
                    }
                };

            [JsonProperty(PropertyName = "Whitelist", ObjectCreationHandling = ObjectCreationHandling.Replace)]
            public Dictionary<string, List<string>> Whitelist = new Dictionary<string, List<string>>
            {
                {
                    "global", new List<string>
                    {
                        "item.shortname"
                    }
                },
                {
                    "furnace.shortname", new List<string>
                    {
                        "item.shortname"
                    }
                }
            };

            [JsonProperty(PropertyName = "Blacklist", ObjectCreationHandling = ObjectCreationHandling.Replace)]
            public Dictionary<string, List<string>> Blacklist = new Dictionary<string, List<string>>
            {
                {
                    "global", new List<string>
                    {
                        "item.shortname"
                    }
                },
                {
                    "furnace.shortname", new List<string>
                    {
                        "item.shortname"
                    }
                }
            };

            [JsonProperty(PropertyName = "Smelting Frequencies (Smelt items every N smelting ticks)",
                ObjectCreationHandling = ObjectCreationHandling.Replace)]
            public Dictionary<string, int> SmeltingFrequencies = new Dictionary<string, int>
            {
                { "global", 1 },
                { "furnace.shortname", 1 }
            };

            [JsonProperty(PropertyName = "Debug")]
            public bool Debug = false;
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                _config = Config.ReadObject<Configuration>();
                if (_config == null) throw new Exception();
            }
            catch
            {
                PrintError("Your configuration file contains an error. Using default configuration values.");
                LoadDefaultConfig();
            }
        }

        protected override void LoadDefaultConfig() => _config = new Configuration();

        protected override void SaveConfig() => Config.WriteObject(_config);

        #endregion

        #region Hooks

        private void Unload()
        {
            var ovens = UnityEngine.Object.FindObjectsOfType<BaseOven>();
            PrintDebug($"Processing BaseOven(s).. Amount: {ovens.Length}.");

            for (var i = 0; i < ovens.Length; i++)
            {
                var oven = ovens[i];
                var component = oven.GetComponent<FurnaceController>();

                if (oven.IsOn())
                {
                    PrintDebug("Oven is on. Restarted cooking");
                    component.StopCooking();
                    oven.StartCooking();
                }

                UnityEngine.Object.Destroy(component);
            }

            PrintDebug("Done.");
        }

        private void OnServerInitialized()
        {
            _instance = this;
            permission.RegisterPermission(PermissionUse, this);

            var ovens = UnityEngine.Object.FindObjectsOfType<BaseOven>();
            PrintDebug($"Processing BaseOven(s).. Amount: {ovens.Length}.");

            for (var i = 0; i < ovens.Length; i++)
            {
                var oven = ovens[i];

                OnEntitySpawned(oven);
            }

            timer.Once(1f, () =>
            {
                for (var i = 0; i < ovens.Length; i++)
                {
                    var oven = ovens[i];
                    if (oven == null)
                    {
                        continue;
                    }

                    var component = oven.gameObject.GetComponent<FurnaceController>();

                    if (oven.IsDestroyed || !oven.IsOn() || !CanUse(oven.OwnerID))
                        continue;

                    component.StartCooking();
                }
            });
        }

        private void OnEntitySpawned(BaseNetworkable entity)
        {
            var oven = entity as BaseOven;
            if (oven == null)
                return;

            oven.gameObject.AddComponent<FurnaceController>();
        }

        private object OnOvenToggle(StorageContainer oven, BasePlayer player)
        {
            if (oven is BaseFuelLightSource || oven.needsBuildingPrivilegeToUse && !player.CanBuild())
                return null;

            PrintDebug("OnOvenToggle called");
            var component = oven.gameObject.GetComponent<FurnaceController>();
            var canUse = CanUse(oven.OwnerID) || CanUse(player.userID);
            if (oven.IsOn())
            {
                component.StopCooking();
            }
            else
            {
                if (canUse)
                    component.StartCooking();
                else
                {
                    PrintDebug($"No permission ({player.userID})");
                    return null;
                }
            }

            return false;
        }

        #endregion

        #region Helpers

        private bool CanUse(ulong id) =>
            !_config.UsePermission || permission.UserHasPermission(id.ToString(), PermissionUse);

        private static void PrintDebug(string message)
        {
            if (_config.Debug)
                Debug.Log($"DEBUG ({_instance.Name}) > " + message);
        }

        #endregion

        #region Controller

        public class FurnaceController : FacepunchBehaviour
        {
            private int _ticks;

            private BaseOven _oven;

            private BaseOven Furnace
            {
                get
                {
                    if (_oven == null)
                        _oven = GetComponent<BaseOven>();

                    return _oven;
                }
            }

            private float _speedMultiplier;

            private float _fuelSpeedMultiplier;

            private int _fuelUsageMultiplier;

            private int _smeltingFrequency;

            private Dictionary<string, float> _outputModifiers;

            private float OutputMultiplier(string shortname)
            {
                float modifier;
                if (_outputModifiers == null || !_outputModifiers.TryGetValue(shortname, out modifier) &&
                    !_outputModifiers.TryGetValue("global", out modifier))
                    modifier = 1.0f;

                PrintDebug($"{shortname} modifier: {modifier}");
                return modifier;
            }

            private List<string> _blacklist;
            private List<string> _whitelist;

            private bool? IsAllowed(string shortname)
            {
                if (_blacklist != null && _blacklist.Contains(shortname))
                    return false;

                if (_whitelist != null && _whitelist.Contains(shortname))
                    return true;

                return null;
            }

            private static bool CanBeCookedByAtTemperature(ItemModCookable cookable, float temperature)
            {
                return temperature >= cookable.lowTemp && temperature <= cookable.highTemp;
            }

            private void Awake()
            {
                // Well, sorry for my complicated code. But that should work faster! :)

                float modifierF; // float modifier
                int modifierI; // int modifier

                if (!_config.SpeedMultipliers.TryGetValue(Furnace.ShortPrefabName, out modifierF) &&
                    !_config.SpeedMultipliers.TryGetValue("global", out modifierF))
                    modifierF = 1.0f;

                _speedMultiplier = 0.5f / modifierF;

                if (!_config.FuelSpeedMultipliers.TryGetValue(Furnace.ShortPrefabName, out modifierF) &&
                    !_config.FuelSpeedMultipliers.TryGetValue("global", out modifierF))
                    modifierF = 1.0f;

                _fuelSpeedMultiplier = modifierF;

                if (!_config.FuelUsageMultipliers.TryGetValue(Furnace.ShortPrefabName, out modifierI) &&
                    !_config.FuelUsageMultipliers.TryGetValue("global", out modifierI))
                    modifierI = 1;

                _fuelUsageMultiplier = modifierI;

                if (!_config.SmeltingFrequencies.TryGetValue(Furnace.ShortPrefabName, out modifierI) &&
                    !_config.SmeltingFrequencies.TryGetValue("global", out modifierI))
                    modifierI = 1;

                _smeltingFrequency = modifierI;

                if (!_config.OutputMultipliers.TryGetValue(Furnace.ShortPrefabName, out _outputModifiers) &&
                    !_config.OutputMultipliers.TryGetValue("global", out _outputModifiers))
                {
                    // ignored
                }

                if ((!_config.Blacklist.TryGetValue(Furnace.ShortPrefabName, out _blacklist) &&
                     !_config.Blacklist.TryGetValue("global", out _blacklist)) &
                    (!_config.Whitelist.TryGetValue(Furnace.ShortPrefabName, out _whitelist) &&
                     !_config.Whitelist.TryGetValue("global", out _whitelist)))
                {
                    // ignored
                }
            }

            private Item FindBurnable()
            {
                if (Furnace.inventory == null)
                    return null;

                var burnable = Interface.Call<Item>("OnFindBurnable", _oven);
                if (burnable != null)
                {
                    return burnable;
                }

                foreach (var item in Furnace.inventory.itemList)
                {
                    if (!_oven.IsBurnableItem(item))
                        continue;

                    return item;
                }

                return null;
            }

            public void Cook()
            {
                var itemBurnable = FindBurnable();
                if (Interface.CallHook("OnOvenCook", this, itemBurnable) != null)
                {
                    return;
                }

                if (itemBurnable == null)
                {
                    StopCooking();
                    return;
                }

                SmeltItems();

                foreach (var itemCooking in _oven.inventory.itemList)
                {
                    if (itemCooking.position >= _oven._inputSlotIndex &&
                        itemCooking.position < _oven._inputSlotIndex + _oven.inputSlots &&
                        !itemCooking.HasFlag(global::Item.Flag.Cooking))
                    {
                        itemCooking.SetFlag(global::Item.Flag.Cooking, true);
                        itemCooking.MarkDirty();
                    }
                }

                var slot = Furnace.GetSlot(BaseEntity.Slot.FireMod);
                if (slot)
                {
                    slot.SendMessage("Cook", 0.5f, SendMessageOptions.DontRequireReceiver);
                }

                var burnable = itemBurnable.info.GetComponent<ItemModBurnable>();
                itemBurnable.fuel -= 0.5f * (Furnace.cookingTemperature / 200f) * _fuelSpeedMultiplier;

                if (!itemBurnable.HasFlag(global::Item.Flag.OnFire))
                {
                    itemBurnable.SetFlag(global::Item.Flag.OnFire, true);
                    itemBurnable.MarkDirty();
                }

                if (itemBurnable.fuel <= 0f)
                {
                    ConsumeFuel(itemBurnable, burnable);
                }

                _ticks++;

                Interface.CallHook("OnOvenCooked", this, itemBurnable, slot);
            }

            private void ConsumeFuel(Item fuel, ItemModBurnable burnable)
            {
                if (Interface.CallHook("OnFuelConsume", _oven, fuel, burnable) != null)
                {
                    return;
                }

                if (Furnace.allowByproductCreation && burnable.byproductItem != null &&
                    Random.Range(0f, 1f) > burnable.byproductChance)
                {
                    var def = burnable.byproductItem;
                    var item = ItemManager.Create(def,
                        (int)(burnable.byproductAmount * OutputMultiplier(def.shortname))); // It's fuel multiplier

                    if (!item.MoveToContainer(Furnace.inventory))
                    {
                        StopCooking();
                        item.Drop(Furnace.inventory.dropPosition, Furnace.inventory.dropVelocity);
                    }
                }

                if (fuel.amount <= _fuelUsageMultiplier)
                {
                    fuel.Remove();
                    return;
                }

                fuel.UseItem(_fuelUsageMultiplier);
                fuel.fuel = burnable.fuelAmount;
                fuel.MarkDirty();

                Interface.CallHook("OnFuelConsumed", _oven, fuel, burnable);
            }

            private void SmeltItems()
            {
                if (_ticks % _smeltingFrequency != 0)
                    return;

                for (var i = 0; i < Furnace.inventory.itemList.Count; i++)
                {
                    var item = Furnace.inventory.itemList[i];
                    if (item == null || !item.IsValid())
                        continue;

                    var cookable = item.info.GetComponent<ItemModCookable>();
                    if (cookable == null)
                        continue;

                    var isAllowed = IsAllowed(item.info.shortname);
                    if (isAllowed != null &&
                        !isAllowed.Value) // Allowed is false? Okay, no problem. Don't cook this item
                        continue;

                    var temperature = item.temperature;
                    if (!CanBeCookedByAtTemperature(cookable, temperature) && isAllowed == null)
                    {
                        if (!cookable.setCookingFlag || !item.HasFlag(global::Item.Flag.Cooking))
                            continue;

                        item.SetFlag(global::Item.Flag.Cooking, false);
                        item.MarkDirty();
                        continue;
                    }

                    if (cookable.cookTime > 0 && _ticks * 1f / _smeltingFrequency % cookable.cookTime > 0)
                        continue;

                    if (cookable.setCookingFlag && !item.HasFlag(global::Item.Flag.Cooking))
                    {
                        item.SetFlag(global::Item.Flag.Cooking, true);
                        item.MarkDirty();
                    }

                    // var targetPosition = item.position + 1;
                    var amountConsumed = (int)_oven.GetSmeltingSpeed();
                    amountConsumed = Math.Min(amountConsumed, item.amount);
                    if (item.amount > amountConsumed)
                    {
                        item.amount -= amountConsumed;
                        item.MarkDirty();
                    }
                    else
                    {
                        item.Remove();
                    }

                    if (cookable.becomeOnCooked == null)
                        continue;

                    var itemProduced = ItemManager.Create(cookable.becomeOnCooked,
                        (int)(cookable.amountOfBecome * amountConsumed *
                              OutputMultiplier(cookable.becomeOnCooked.shortname)));

                    if (itemProduced == null || itemProduced.MoveToContainer(item.parent))
                        continue;

                    itemProduced.Drop(item.parent.dropPosition, item.parent.dropVelocity);

                    StopCooking();
                }
            }

            public void StartCooking()
            {
                if (FindBurnable() == null)
                {
                    PrintDebug("No burnable.");
                    return;
                }

                StopCooking();

                PrintDebug("Starting cooking..");
                Furnace.inventory.temperature = Furnace.cookingTemperature;
                Furnace.UpdateAttachmentTemperature();

                PrintDebug($"Speed Multiplier: {_speedMultiplier}");
                Furnace.InvokeRepeating(Cook, _speedMultiplier, _speedMultiplier);
                Furnace.SetFlagLocal(BaseEntity.Flags.On, true);
                Furnace.SendNetworkUpdate_Flags();
            }

            public void StopCooking()
            {
                PrintDebug("Stopping cooking..");
                Furnace.CancelInvoke(Cook);
                Furnace.StopCooking();
            }
        }

        #endregion
    }
}


Merged post

Above code fixed with AI, had yet to seen any issues, use at own risk, hope it helps
X8XN2uPAAxpLWKJ.jpg madstayen

I used to use Umod QuickSmelt, but because of this type of issue I started to use Quick Smelt by Scalbox from DigitalMarketPlay. Unfortunately it's also broken since the update, but unlike this developer Scalbox keeps his up to date, but it's weekend now, so this will only happen next week I assume. However, it's also a free plugin, and I fixed it temporarily by editing line 604:

if ((temperature < cookable.lowTemp || temperature > cookable.highTemp) && isAllowed == null)

Open the CS file. Hit Ctrl+F. Enter the following in the search tab and hit ENTER: CanBeCookedByAtTemperature

You'll see the following: if (!cookable.CanBeCookedByAtTemperature(temperature) && isAllowed == null)

Change this to: if ((temperature < cookable.lowTemp || temperature > cookable.highTemp) && isAllowed == null)

These plugins are both exactly the same (fork) so it should work on this one too.

Hi, unfortunately it doesn't work, another error appears:

Error while compiling QuickSmelt: 'BaseOven' does not contain a definition for 'SetFlag' and no accessible extension method 'SetFlag' accepting a first argument of type 'BaseOven' could be found (are you missing a using directive or an assembly reference?) | Line: 542, Pos: 25
VincentVega
Hi, unfortunately it doesn't work, another error appears:

Error while compiling QuickSmelt: 'BaseOven' does not contain a definition for 'SetFlag' and no accessible extension method 'SetFlag' accepting a first argument of type 'BaseOven' could be found (are you missing a using directive or an assembly reference?) | Line: 542, Pos: 25

Hi, try using this one: https://digitalmarketplay.com/product/quick-smelt/ but with my fix. It's working

This one works and doesn't reset the Composter process every time you open it (one of the links posted above did):

using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
using Random = UnityEngine.Random;

namespace Oxide.Plugins
{
[Info("Quick Smelt", "misticos + WhiteThunder", "5.1.15")]
[Description("Increases the speed of the furnace smelting")]
class QuickSmelt : RustPlugin
{
#region Variables

private static QuickSmelt _instance;

private const string PermissionUse = "quicksmelt.use";

private readonly object False = false;

#endregion

#region Configuration

private static Configuration _config;

private class Configuration
{
[JsonProperty(PropertyName = "Use Permission")]
public bool UsePermission = true;

[JsonProperty(PropertyName = "Speed Multipliers", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, float> SpeedMultipliers = new Dictionary<string, float>
{
{ "global", 1.0f },
{ "furnace.shortname", 1.0f }
};

[JsonProperty(PropertyName = "Fuel Usage Speed Multipliers",
ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, float> FuelSpeedMultipliers = new Dictionary<string, float>
{
{ "global", 1.0f },
{ "furnace.shortname", 1.0f }
};

[JsonProperty(PropertyName = "Fuel Usage Multipliers",
ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, int> FuelUsageMultipliers = new Dictionary<string, int>
{
{ "global", 1 },
{ "furnace.shortname", 1 }
};

[JsonProperty(PropertyName = "Output Multipliers", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, Dictionary<string, float>> OutputMultipliers =
new Dictionary<string, Dictionary<string, float>>
{
{
"global", new Dictionary<string, float>
{
{ "global", 1.0f }
}
},
{
"furnace.shortname", new Dictionary<string, float>
{
{ "item.shortname", 1.0f }
}
}
};

[JsonProperty(PropertyName = "Whitelist", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, List<string>> Whitelist = new Dictionary<string, List<string>>
{
{
"global", new List<string>
{
"item.shortname"
}
},
{
"furnace.shortname", new List<string>
{
"item.shortname"
}
}
};

[JsonProperty(PropertyName = "Blacklist", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, List<string>> Blacklist = new Dictionary<string, List<string>>
{
{
"global", new List<string>
{
"item.shortname"
}
},
{
"furnace.shortname", new List<string>
{
"item.shortname"
}
}
};

[JsonProperty(PropertyName = "Smelting Frequencies (Smelt items every N smelting ticks)",
ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, int> SmeltingFrequencies = new Dictionary<string, int>
{
{ "global", 1 },
{ "furnace.shortname", 1 }
};

[JsonProperty(PropertyName = "Debug")]
public bool Debug = false;

public void OnServerInitialized(QuickSmelt plugin)
{
foreach (var entry in OutputMultipliers.Values)
{
ValidateItemNames(plugin, entry.Keys);
}

foreach (var entry in Whitelist.Values)
{
ValidateItemNames(plugin, entry);
}

foreach (var entry in Blacklist.Values)
{
ValidateItemNames(plugin, entry);
}

var validFurnaceShortNames = GetValidFurnaceShortNames();
var validDeployables = GetItemShortNameToDeployableShortName<BaseOven>();
ValidateFurnaceShortNames(plugin, validFurnaceShortNames, validDeployables, SpeedMultipliers.Keys);
ValidateFurnaceShortNames(plugin, validFurnaceShortNames, validDeployables, FuelSpeedMultipliers.Keys);
ValidateFurnaceShortNames(plugin, validFurnaceShortNames, validDeployables, FuelUsageMultipliers.Keys);
ValidateFurnaceShortNames(plugin, validFurnaceShortNames, validDeployables, OutputMultipliers.Keys);
ValidateFurnaceShortNames(plugin, validFurnaceShortNames, validDeployables, Whitelist.Keys);
ValidateFurnaceShortNames(plugin, validFurnaceShortNames, validDeployables, Blacklist.Keys);
}

private void ValidateItemNames(QuickSmelt plugin, IEnumerable<string> itemShortNameList)
{
foreach (var itemShortName in itemShortNameList)
{
if (itemShortName != "global"
&& itemShortName != "item.shortname"
&& ItemManager.FindItemDefinition(itemShortName) == null)
{
plugin.PrintWarning($"[Configuration] {itemShortName} is not a valid item.");
}
}
}

private void ValidateFurnaceShortNames(QuickSmelt plugin, HashSet<string> validFurnaceShortNames, Dictionary<string, string> validFurnaces, IEnumerable<string> shortNameList)
{
foreach (var shortName in shortNameList)
{
if (shortName == "global" || shortName == "furnace.shortname" || validFurnaceShortNames.Contains(shortName))
continue;

var message = $"[Configuration] {shortName} is not a valid furnace short name.";

// People often put item short names into the config where an entity short name is expected.
// This will suggest the correct name to the user: electric.furnace -> electricfurnace.deployed
string furnaceShortName;
if (validFurnaces.TryGetValue(shortName, out furnaceShortName))
{
message += $" Did you mean {furnaceShortName}?";
}

plugin.PrintWarning(message);
}
}

private static HashSet<string> GetValidFurnaceShortNames()
{
var validShortNames = new HashSet<string>();

foreach (var prefabPath in GameManifest.Current.entities)
{
var furnace = GameManager.server.FindPrefab(prefabPath)?.GetComponent<BaseOven>();
if (furnace == null)
continue;

validShortNames.Add(furnace.ShortPrefabName);
}

return validShortNames;
}

private static Dictionary<string, string> GetItemShortNameToDeployableShortName<T>() where T : BaseEntity
{
var itemsToDeployables = new Dictionary<string, string>();

foreach (var itemDefinition in ItemManager.itemList)
{
var itemModDeployable = itemDefinition.GetComponent<ItemModDeployable>();
if (itemModDeployable == null)
continue;

var entity = itemModDeployable.entityPrefab.GetEntity() as T;
if (entity == null)
continue;

itemsToDeployables[itemDefinition.shortname] = entity.ShortPrefabName;
}

return itemsToDeployables;
}
}

protected override void LoadConfig()
{
base.LoadConfig();
try
{
_config = Config.ReadObject<Configuration>();
if (_config == null) throw new Exception();
}
catch
{
PrintError("Your configuration file contains an error. Using default configuration values.");
LoadDefaultConfig();
}
}

protected override void LoadDefaultConfig() => _config = new Configuration();

protected override void SaveConfig() => Config.WriteObject(_config);

#endregion

#region Hooks

private void Unload()
{
var ovens = BaseNetworkable.serverEntities.OfType<BaseOven>().Where(o => !(o is Composter)).ToArray();
PrintDebug($"Processing BaseOven(s).. Amount: {ovens.Length}.");

for (var i = 0; i < ovens.Length; i++)
{
var oven = ovens[i];
var component = oven.GetComponent<FurnaceController>();

if (oven.IsOn())
{
PrintDebug("Oven is on. Restarted cooking");
component.StopCooking();
oven.StartCooking();
}

UnityEngine.Object.Destroy(component);
}

PrintDebug("Done.");
}

private void OnServerInitialized()
{
_instance = this;
_config.OnServerInitialized(this);
permission.RegisterPermission(PermissionUse, this);

var ovens = BaseNetworkable.serverEntities.OfType<BaseOven>().Where(o => !(o is Composter)).ToArray();
PrintDebug($"Processing BaseOven(s).. Amount: {ovens.Length}.");

for (var i = 0; i < ovens.Length; i++)
{
var oven = ovens[i];

OnEntitySpawned(oven);
}

timer.Once(1f, () =>
{
for (var i = 0; i < ovens.Length; i++)
{
var oven = ovens[i];
if (oven == null)
{
continue;
}

var component = oven.gameObject.GetComponent<FurnaceController>();

if (oven.IsDestroyed || !oven.IsOn() || !CanUse(oven.OwnerID))
continue;

component.StartCooking();
}
});
}

private void OnEntitySpawned(BaseNetworkable entity)
{
var oven = entity as BaseOven;
if (oven == null || oven is Composter)
return;

oven.gameObject.AddComponent<FurnaceController>();
}

// Electric furnaces can be started via electricity.
// Normal furnaces can be started via igniter.
private object OnOvenStart(StorageContainer oven)
{
if (oven is BaseFuelLightSource || oven is Composter)
return null;

if (!CanUse(oven.OwnerID))
return null;

oven.gameObject.GetComponent<FurnaceController>().StartCooking();
return False;
}

private object OnOvenToggle(StorageContainer oven, BasePlayer player)
{
if (oven is BaseFuelLightSource || oven is Composter || oven.needsBuildingPrivilegeToUse && !player.CanBuild())
return null;

PrintDebug("OnOvenToggle called");
var component = oven.gameObject.GetComponent<FurnaceController>();
var canUse = CanUse(oven.OwnerID) || CanUse(player.userID);
if (oven.IsOn())
{
component.StopCooking();
}
else
{
if (canUse)
{
component.StartCooking();
}
else
{
PrintDebug($"No permission ({player.userID})");
return null;
}
}

return False;
}

#endregion

#region Helpers

private bool CanUse(ulong id) =>
!_config.UsePermission || permission.UserHasPermission(id.ToString(), PermissionUse);

private static void PrintDebug(string message)
{
if (_config.Debug)
Debug.Log($"DEBUG ({_instance.Name}) > " + message);
}

#endregion

#region Controller

public class FurnaceController : FacepunchBehaviour
{
private BaseOven _oven;

private BaseOven Furnace
{
get
{
if (_oven == null)
_oven = GetComponent<BaseOven>();

return _oven;
}
}

private float _speedMultiplier;

private float _fuelSpeedMultiplier;

private int _fuelUsageMultiplier;

private int _smeltingFrequency;

private Dictionary<string, float> _outputModifiers;

private List<Item> _itemsToCook = new List<Item>();

private float OutputMultiplier(string shortname)
{
float modifier;
if (_outputModifiers == null || !_outputModifiers.TryGetValue(shortname, out modifier) &&
!_outputModifiers.TryGetValue("global", out modifier))
modifier = 1.0f;

PrintDebug($"{shortname} modifier: {modifier}");
return modifier;
}

private List<string> _blacklist;
private List<string> _whitelist;

private bool? IsAllowed(string shortname)
{
if (_blacklist != null && _blacklist.Contains(shortname))
return false;

if (_whitelist != null && _whitelist.Contains(shortname))
return true;

return null;
}

private void Awake()
{
// Well, sorry for my complicated code. But that should work faster! :)

float modifierF; // float modifier
int modifierI; // int modifier

if (!_config.SpeedMultipliers.TryGetValue(Furnace.ShortPrefabName, out modifierF) &&
!_config.SpeedMultipliers.TryGetValue("global", out modifierF))
modifierF = 1.0f;

_speedMultiplier = modifierF;

if (!_config.FuelSpeedMultipliers.TryGetValue(Furnace.ShortPrefabName, out modifierF) &&
!_config.FuelSpeedMultipliers.TryGetValue("global", out modifierF))
modifierF = 1.0f;

_fuelSpeedMultiplier = modifierF;

if (!_config.FuelUsageMultipliers.TryGetValue(Furnace.ShortPrefabName, out modifierI) &&
!_config.FuelUsageMultipliers.TryGetValue("global", out modifierI))
modifierI = 1;

_fuelUsageMultiplier = modifierI;

if (!_config.SmeltingFrequencies.TryGetValue(Furnace.ShortPrefabName, out modifierI) &&
!_config.SmeltingFrequencies.TryGetValue("global", out modifierI))
modifierI = 1;

_smeltingFrequency = modifierI;

if (!_config.OutputMultipliers.TryGetValue(Furnace.ShortPrefabName, out _outputModifiers) &&
!_config.OutputMultipliers.TryGetValue("global", out _outputModifiers))
{
// ignored
}

if ((!_config.Blacklist.TryGetValue(Furnace.ShortPrefabName, out _blacklist) &&
!_config.Blacklist.TryGetValue("global", out _blacklist)) &
(!_config.Whitelist.TryGetValue(Furnace.ShortPrefabName, out _whitelist) &&
!_config.Whitelist.TryGetValue("global", out _whitelist)))
{
// ignored
}
}

private Item FindBurnable()
{
if (Furnace.inventory == null)
return null;

var burnable = Interface.Call<Item>("OnFindBurnable", _oven);
if (burnable != null)
{
return burnable;
}

foreach (var item in Furnace.inventory.itemList)
{
if (!_oven.IsBurnableItem(item))
continue;

return item;
}

return null;
}

public void Cook()
{
var itemBurnable = FindBurnable();
if (Interface.CallHook("OnOvenCook", _oven, itemBurnable) != null)
{
return;
}

if (itemBurnable == null && !Furnace.CanRunWithNoFuel)
{
StopCooking();
return;
}

foreach (var itemCooking in _oven.inventory.itemList)
{
if (itemCooking.position >= _oven._inputSlotIndex &&
itemCooking.position < _oven._inputSlotIndex + _oven.inputSlots &&
!itemCooking.HasFlag(global::Item.Flag.Cooking))
{
itemCooking.SetFlag(global::Item.Flag.Cooking, true);
itemCooking.MarkDirty();
}
}

SmeltItems();

var slot = Furnace.GetSlot(BaseEntity.Slot.FireMod);
if (slot)
{
slot.SendMessage("Cook", 0.5f, SendMessageOptions.DontRequireReceiver);
}

if (itemBurnable != null)
{
var burnable = itemBurnable.info.GetComponent<ItemModBurnable>();
itemBurnable.fuel -= 0.5f * (Furnace.cookingTemperature / 200f) * _fuelSpeedMultiplier;

if (!itemBurnable.HasFlag(global::Item.Flag.OnFire))
{
itemBurnable.SetFlag(global::Item.Flag.OnFire, true);
itemBurnable.MarkDirty();
}

if (itemBurnable.fuel <= 0f)
{
ConsumeFuel(itemBurnable, burnable);
}
}

Interface.CallHook("OnOvenCooked", _oven, itemBurnable, slot);
}

private void ConsumeFuel(Item fuel, ItemModBurnable burnable)
{
if (Interface.CallHook("OnFuelConsume", _oven, fuel, burnable) != null)
{
return;
}

if (Furnace.allowByproductCreation && burnable.byproductItem != null &&
Random.Range(0f, 1f) > burnable.byproductChance)
{
var def = burnable.byproductItem;
var item = ItemManager.Create(def,
(int)(burnable.byproductAmount * OutputMultiplier(def.shortname) * Mathf.Min(_speedMultiplier, fuel.amount))); // It's fuel multiplier

if (item != null && !item.MoveToContainer(Furnace.inventory))
{
StopCooking();
item.Drop(Furnace.inventory.dropPosition, Furnace.inventory.dropVelocity);
}
}

var fuelToConsume = (int)(_fuelUsageMultiplier * _speedMultiplier);

if (fuel.amount <= fuelToConsume)
{
fuel.Remove();
return;
}

fuel.UseItem(fuelToConsume);
fuel.fuel = burnable.fuelAmount;
fuel.MarkDirty();

Interface.CallHook("OnFuelConsumed", _oven, fuel, burnable);
}

private void SmeltItems()
{
_itemsToCook.Clear();

foreach (var item in Furnace.inventory.itemList)
{
if (item.HasFlag(global::Item.Flag.Cooking))
{
_itemsToCook.Add(item);
}
}

foreach (var item in _itemsToCook)
{
if (item == null || !item.IsValid())
continue;

var cookable = item.info.ItemModCookable;
if (cookable == null)
continue;

var isAllowed = IsAllowed(item.info.shortname);
if (isAllowed != null &&
!isAllowed.Value) // Allowed is false? Okay, no problem. Don't cook this item
continue;

var temperature = item.temperature;
if (!cookable.CanBeCookedByAtTemperature(temperature) && isAllowed == null || item.cookTimeLeft < 0)
{
if (!cookable.setCookingFlag || !item.HasFlag(global::Item.Flag.Cooking))
continue;

item.SetFlag(global::Item.Flag.Cooking, false);
item.MarkDirty();

continue;
}

if (cookable.setCookingFlag && !item.HasFlag(global::Item.Flag.Cooking))
{
item.SetFlag(global::Item.Flag.Cooking, true);
item.MarkDirty();
}

item.cookTimeLeft -= 0.5f * _oven.GetSmeltingSpeed() / _itemsToCook.Count;
if (item.cookTimeLeft > 0)
{
item.MarkDirty();
continue;
}

var cookTimeInverted = item.cookTimeLeft * -1;
var amountConsumed = (int)((1 + Mathf.FloorToInt(cookTimeInverted / cookable.cookTime)) * _speedMultiplier);

item.cookTimeLeft = cookable.cookTime - cookTimeInverted % cookable.cookTime;
amountConsumed = Math.Min(amountConsumed, item.amount);

if (item.amount > amountConsumed)
{
item.amount -= amountConsumed;
item.MarkDirty();
}
else
{
item.Remove();
}

if (cookable.becomeOnCooked == null)
continue;

var itemProduced = ItemManager.Create(cookable.becomeOnCooked,
(int)(cookable.amountOfBecome * amountConsumed *
OutputMultiplier(cookable.becomeOnCooked.shortname)));

if (itemProduced == null || itemProduced.MoveToContainer(item.parent))
continue;

itemProduced.Drop(item.parent.dropPosition, item.parent.dropVelocity);

StopCooking();
}

_itemsToCook.Clear();
}

public void StartCooking()
{
if (!Furnace.CanRunWithNoFuel && FindBurnable() == null)
{
PrintDebug("No burnable.");
return;
}

StopCooking();

PrintDebug("Starting cooking..");
Furnace.inventory.temperature = Furnace.cookingTemperature;
Furnace.UpdateAttachmentTemperature();

PrintDebug($"Speed Multiplier: {_speedMultiplier}");
Furnace.InvokeRepeating(Cook, 0.5f, 0.5f);
Furnace.SetFlagLocal(BaseEntity.Flags.On, true);
Furnace.SendNetworkUpdate_Flags();
}

public void StopCooking()
{
PrintDebug("Stopping cooking..");
Furnace.CancelInvoke(Cook);
Furnace.StopCooking();
}
}

#endregion
}
}