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

FREE FurnaceNoOreStop : 1.4.8 1.4.8

Нет прав для скачивания
C#:
using Oxide.Core;
using Oxide.Core.Plugins;
using UnityEngine;
using System.Linq;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
//Bunch of optimizations and some minor changes for version 1.1.1
//Bunch more optimzation for 1.2.1
//1.2.2 Checks for ores and furnaces now use HashSet for faster lookups
//Might add more configurable settings in the future. Potentially the list of BaseOvens affected and the cookable types.
//Made more optimizations from where i threw together a quick compatibility fix for quick smelt.
//1.3.5 Moved the hashset for lookup into config so users can now add their own filter system. Wood should not be added or it defeats this plugins purpose. Debug mode is helpful for finding the IDs by looting an already deployed oven, includes barbecues, campfires and stone fireplaces.
//1.3.6 Fixed a typo in a name, nothing worth pushing as it didnt break anything.
//1.4.0 Added a command to output all cookables by their shortname, this is particularly helpful for getting the cookable names for config use.
//1.4.2 Added another hook, for more quicksmelt compatibility. Should now toggle off properly when you remove the fuel mid cycle.
//1.4.3 Added a config setting that lets you control if you want furances going on when ending looting. Also better handling of QuickSmelt(hopefully lol).
//1.4.5 Added container empty check in OnItemRemovedFromContainer() to prevent the furnaces turning off when you remove 1 stack of items from a furnace thathas multiple stacks of ore.
//1.4.6 Separated logic for wood removal vs ore removal in OnItemRemovedFromContainer(), this should be the final fix for quicksmelt compatibility.
//1.4.7 Added a check OnItemRemovedFromContainer to ensure ovens that are not whitelisted are not turned off.
namespace Oxide.Plugins {
    [Info("Furnace No Ore Stop", "Tacman", "1.4.8")]
    [Description("Stops furnaces when there are no more ores")]
    public class FurnaceNoOreStop : RustPlugin {
        [PluginReference]
        private Plugin QuickSmelt;
        private string usePerm = "furnacenoorestop.use";
        private Dictionary<ulong, List<BaseOven>> cookers = new();
        //This is to keep track of player ovens, if config setting for on and off are enabled. It also keeps track for turning off when no more ores or crude.
        /*private static readonly HashSet<string> checkOvens = new() //to keep track of all valid furnace and refinery prefab names
        {
            "furnace",
            "furnace.small",
            "furnace.large",
            "legacy_furnace",
            "electricfurnace.deployed",
            "refinery_small_deployed",
            "refinery"
        };*/
        //Moved this to config, config also includes tools to find the prefab id on your own using debug mode.
        /*private static readonly HashSet<string> checkCookables = new()
        {
            "metal.ore",
            "hq.metal.ore",
            "sulfur.ore",
            "crude.oil"
        };
        private static readonly HashSet<uint> prefabID = new()
        {
            3808299817, //electric furnace deployed
            2931042549, //regular furnace deployed
            2013224025, //legacy furnace deployed
            1374462671, //large furnace deployed
            1057236622 //oil refinery deployed
        };*/
#region Config
        static Configuration config;
        public class Configuration {
            [JsonProperty("Turn off furnaces when players disconnect?")]
            public bool disconnectOff;
            [JsonProperty("Turn on players furnaces when they connect?")]
            public bool connectOn;
            [JsonProperty("Debugging (for development and repairs)")]
            public bool debug;
            [JsonProperty("List of prefab ids allowed to be affected by this plugin. You can find prefab IDs by enabling debug and looking at the console when you loot the oven. (will repopulate with defaults if emptied)")]
            public HashSet<uint> PrefabIDs {
                get;
                set;
            }
            = new();
            [JsonProperty("Items that are allowed to trigger the ovens to turn on and off. Do not add wood, the whole point of the plugin is to turn off when wood is the only contents. (will repopulate with defaults if emptied)")]
            public HashSet<string> checkCookables {
                get;
                set;
            }
            = new();
            [JsonProperty("Turn furnace on when closing furnace UI?")]
            public bool closeUIOn;
            public static Configuration DefaultConfig() {
                return new Configuration {
                    disconnectOff = false, connectOn = false, debug = false, PrefabIDs = new HashSet<uint>() {
                        3808299817, 2931042549, 2013224025, 1374462671, 1057236622
                    }
                    , checkCookables = new HashSet<string>() {
                        "metal.ore", "hq.metal.ore", "sulfur.ore", "crude.oil"
                    }
                }
                ;
            }
        }
        protected override void LoadConfig() {
            base.LoadConfig();
            try {
                config = Config.ReadObject<Configuration>();
                if (config == null) LoadDefaultConfig();
                if (config.PrefabIDs == null || config.PrefabIDs.Count == 0) {
                    Puts("Prefab IDs list invalid. Restoring defaults");
                    config.PrefabIDs = Configuration.DefaultConfig().PrefabIDs;
                }
                if (config.checkCookables == null || config.checkCookables.Count == 0) {
                    Puts("Cookable list invalid. Restoring defaults");
                    config.checkCookables = Configuration.DefaultConfig().checkCookables;
                }
                SaveConfig();
            }
            catch (Exception ex) {
                Debug.LogException(ex);
                PrintWarning("Creating new configuration file.");
                LoadDefaultConfig();
            }
        }
        protected override void LoadDefaultConfig() => config = Configuration.DefaultConfig();
        protected override void SaveConfig() => Config.WriteObject(config);
#endregion
#region Setup
        void Init() {
            permission.RegisterPermission(usePerm, this);
            if (QuickSmelt != null && QuickSmelt.Author == "misticos") Puts("QuickSmelt detected, will use quick smelt safe methods instead.");
        }
#endregion
#region Hooks
        void OnPluginUnloaded(Plugin plugin) {
            if (plugin == null) return;
            if (plugin.Name == "QuickSmelt" && plugin.Author == "misticos") Puts("QuickSmelt has been unloaded, reverting to default hooks.");
        }
        void OnPluginLoaded(Plugin plugin) {
            if (plugin == null) return;
            if (plugin.Name == "QuickSmelt" && plugin.Author == "misticos") Puts("QuickSmelt has been loaded, using hooks compatible with it.");
        }
        void OnServerInitialized() {
            if (config.debug) if (QuickSmelt != null && QuickSmelt.Author == "misticos") Puts("QuickSmelt detected, using hooks compatible with it.");
            else QuickSmelt = null;
            cookers.Clear();
            foreach (BaseOven oven in BaseNetworkable.serverEntities.OfType<BaseOven>())  //Only doing this once at server start to populate the dictionary, i prefer this over saving data, it is much more accurate this way.
            {
                if (oven.OwnerID == 0) continue;
                if (!config.PrefabIDs.Contains(oven.prefabID)) continue;
                //this is now a config setting, find your own ids by enabling debug and looting the placed entity you want to be affected. Works for barbecue, campfire and stone fireplaces.
                if (!cookers.TryGetValue(oven.OwnerID, out var list)) cookers[oven.OwnerID] = list = new List<BaseOven>();
                if (!list.Contains(oven)) list.Add(oven);
            }
        }
        void OnEntitySpawned(BaseOven oven)  //decided to use BaseOven here instead of BaseNetworkable for optimization
        {
            if (oven == null) return;
            if (oven.OwnerID == 0) return;
            if (!config.PrefabIDs.Contains(oven.prefabID)) return;
            if (!cookers.TryGetValue(oven.OwnerID, out var list)) cookers[oven.OwnerID] = list = new List<BaseOven>();
            if (!list.Contains(oven)) list.Add(oven);
            if (config.debug) Puts($"Added {oven.ShortPrefabName}:{oven.prefabID} for owner {BasePlayer.FindByID(oven.OwnerID)?.displayName}");
        }
        void OnEntityKill(BaseOven oven)  //same again with BaseOven instead of BaseNetworkable
        {
            if (oven == null) return;
            if (!cookers.TryGetValue(oven.OwnerID, out var list)) return;
            list.Remove(oven);
            if (list.Count == 0) cookers.Remove(oven.OwnerID);
        }
        //hashset lookups should be more performant
        private void OnOvenCooked(BaseOven oven) {
            if (oven == null || oven.inventory == null) return;
            if (!config.PrefabIDs.Contains(oven.prefabID)) return;
            if (!permission.UserHasPermission(oven.OwnerID.ToString(), usePerm)) return;
            bool hasOres = false;
            foreach (var i in oven.inventory.itemList) {
                if (config.checkCookables.Contains(i.info.shortname)) {
                    hasOres = true;
                    break;
                }
            }
            if (!hasOres) {
                if (QuickSmelt != null) {
                    BasePlayer player = BasePlayer.FindByID(oven.OwnerID);
                    //moved this check from outside this scope. since it is only required to throw the hook properly for quicksmelt.
                    if (player == null) return;
                    Interface.CallHook("OnOvenToggle", oven, player);
                }
                else oven.StopCooking();
                if (config.debug) Puts($"Furnace has been turned off as it has no more ores/crude inside.");
            }
        }
        void OnItemRemovedFromContainer(ItemContainer container, Item item) {
            if (container == null || item == null) return;
            BaseOven oven = container.entityOwner as BaseOven;
            if (oven == null) return;
            if (!config.PrefabIDs.Contains(oven.prefabID)) return;
            BasePlayer findPlayer = BasePlayer.FindByID(oven.OwnerID);
            if (findPlayer == null) return;
            if (config.checkCookables.Contains(item.info.shortname)) {
                if (QuickSmelt && QuickSmelt.Author != "ifte") {
                    if (oven.IsOn()) {
                        if (!container.itemList.Any(i => config.checkCookables.Contains(i.info.shortname))) {
                            Interface.CallHook("OnOvenToggle", oven, findPlayer);
                            if (config.debug) Puts($"Furnace owned by {findPlayer.displayName} has been turned off as the container was emptied of ore.");
                        }
                    }
                }
                else {
                    if (oven.IsOn()) {
                        if (!container.itemList.Any(i => config.checkCookables.Contains(i.info.shortname))) {
                            oven.StopCooking();
                            if (config.debug) Puts($"Furnace owned by {findPlayer.displayName} has been turned off as the container was emptied of ore.");
                        }
                    }
                }
            }
            else if (item.info.shortname == "wood" && oven.IsOn()) {
                if (QuickSmelt) {
                    Interface.CallHook("OnOvenToggle", oven, findPlayer);
                    if (config.debug) Puts($"Furnace owned by {findPlayer.displayName} has been turned off as the container was emptied of fuel.");
                }
                else {
                    oven.StopCooking();
                    if (config.debug) Puts($"Furnace owned by {findPlayer.displayName} has been turned off as the container was emptied of fuel.");
                }
            }
        }
        /*in here, it does not actually automatically turn on when the furnace already has existing items, so I use OnLootEntityEnd() to accomplish this.
         I have enabled this again so that industrial automation works properly as long as there are no ores or crude inside already.*/
        private void OnItemAddedToContainer(ItemContainer container, Item item) {
            if (container == null || item == null) return;
            //Puts($"{item.info.shortname} was added to {container}");
            BaseOven oven = container.entityOwner as BaseOven;
            if (oven == null) return;
            if (!config.PrefabIDs.Contains(oven.prefabID)) return;
            if (!config.checkCookables.Contains(item.info.shortname) && item.info.shortname != "wood") return;
            if (!permission.UserHasPermission(oven.OwnerID.ToString(), usePerm)) return;
            if (!oven.IsOn()) {
                BasePlayer player = BasePlayer.FindByID(oven.OwnerID);
                if (QuickSmelt != null && QuickSmelt.Author != "ifte") {
                    if (player == null) return;
                    Interface.CallHook("OnOvenToggle", oven, player);
                }
                else oven.StartCooking();
                if (config.debug) Puts($"Furnace owned by {player?.displayName ?? "Offline or dead Player"} has been turned on as ore/crude was added.");
            }
        }
        private void OnLootEntityEnd(BasePlayer player, BaseOven oven) {
            if (!config.closeUIOn) return;
            if (oven == null) return;
            //moved this earlier, to help getting the entity ids. Previously it was placed at the end, and would have no way to find the prefab ids unless already configured.
            if (config.debug) Puts($"{player.displayName} looted furnace with prefab id {oven.prefabID}");
            if (!config.PrefabIDs.Contains(oven.prefabID)) return;
            if (!permission.UserHasPermission(oven.OwnerID.ToString(), usePerm)) return;
            if (!oven.IsOn()) {
                oven.StartCooking();
                if (config.debug) Puts($"Furnace owned by {player.displayName} has been turned on as it has ores/crude inside.");
            }
        }
        private void OnPlayerConnected(BasePlayer player) {
            if (config.connectOn) ToggleOvens(player, true);
        }
        private void OnPlayerDisconnected(BasePlayer player) {
            if (config.disconnectOff) ToggleOvens(player, false);
        }
#endregion
#region Helper
        //removed the LINQ check here to increase performance when players log in and out. Now uses a direct dictionary lookup.
        private void ToggleOvens(BasePlayer player, bool online) {
            if (player == null) return;
            if (!cookers.TryGetValue(player.userID, out var ovens)) return;
            foreach (BaseOven oven in ovens) {
                if (oven == null) continue;
                if (online && !oven.IsOn()) {
                    if (QuickSmelt != null && QuickSmelt.Author != "ifte") Interface.CallHook("OnOvenToggle", oven, player);
                    else oven.StartCooking();
                    if (config.debug) Puts($"{oven.ShortPrefabName} owned by {player.displayName} turned on.");
                }
                else if (!online && oven.IsOn()) {
                    if (QuickSmelt != null && QuickSmelt.Author != "ifte") Interface.CallHook("OnOvenToggle", oven, player);
                    else oven.StopCooking();
                    if (config.debug) Puts($"{oven.ShortPrefabName} owned by {player.displayName} turned off.");
                }
            }
        }
#endregion
#region Commands
        //Added this here to make it easier to configure the cookable list in config. Even the less technical server owners should be able to handle this 1.
        [ConsoleCommand("cookables")]
        private void Cookables(ConsoleSystem.Arg arg) {
            var results = new List<string>();
            var items = ItemManager.itemList;
            for (int i = 0; i < items.Count; i++) {
                var item = items[i];
                var mods = item.itemMods;
                if (mods == null) continue;
                bool isCookable = false;
                for (int j = 0; j < mods.Length; j++) {
                    if (mods[j] is ItemModCookable) {
                        isCookable = true;
                        break;
                    }
                }
                // Skip non cookables here to save performance, no need to check the shortname if it is not cookable.
                if (!isCookable) continue;
                // filter cooked or burnt variants
                if (item.shortname.EndsWith(".cooked") || item.shortname.EndsWith(".burned")) continue;
                results.Add(item.shortname);
            }
            arg.ReplyWith(string.Join("\n", results));
        }
#endregion
    }
}

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