Иконка ресурса

FREE QuickSmelt : 5.1.16 5.1.16

Нет прав для скачивания
C#:
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.16")]
[Description("Increases the speed of the furnace smelting")]
internal 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()
        {
            { "global", 1.0f },
            { "furnace.shortname", 1.0f },
        };

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

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

        [JsonProperty(PropertyName = "Output Multipliers", ObjectCreationHandling = ObjectCreationHandling.Replace)]
        public Dictionary<string, Dictionary<string, float>> OutputMultipliers =
            new()
            {
                {
                    "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()
        {
            {
                "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()
        {
            {
                "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()
        {
            { "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
                if (validFurnaces.TryGetValue(shortName, out var 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>().ToArray();
        PrintDebug($"Processing BaseOven(s).. Amount: {ovens.Length}.");

        foreach (var oven in ovens)
        {
            var component = oven.GetComponent<FurnaceController>();
            if (component == null)
                continue;

            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>().ToArray();
        PrintDebug($"Processing BaseOven(s).. Amount: {ovens.Length}.");

        foreach (var oven in ovens)
        {
            OnEntitySpawned(oven);
        }

        timer.Once(1f, () =>
        {
            foreach (var oven in ovens)
            {
                if (oven == null)
                    continue;

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

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

                component.StartCooking();
            }
        });
    }

    private void OnEntitySpawned(BaseOven oven)
    {
        if (oven == null || !IsSupportedFurnace(oven))
            return;

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

    // Electric furnaces can be started via electricity.
    // Normal furnaces can be started via igniter.
    private object OnOvenStart(BaseOven oven)
    {
        if (!IsSupportedFurnace(oven))
            return null;

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

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

    private object OnOvenToggle(BaseOven oven, BasePlayer player)
    {
        if (!IsSupportedFurnace(oven) || 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);
    }

    private bool IsSupportedFurnace(BaseOven oven)
    {
        if (oven is BaseFuelLightSource or Composter)
            return false;

        return true;
    }

    #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();

        private float OutputMultiplier(string shortname)
        {
            if (_outputModifiers == null || !_outputModifiers.TryGetValue(shortname, out var 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! :)

            if (!_config.SpeedMultipliers.TryGetValue(Furnace.ShortPrefabName, out var 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 var 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 && fuel.amount > 0 &&
                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.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
}

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху