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

FREE RatesController : 3.3.2 3.3.2

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Network;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using UnityEngine;
using Formatter = Oxide.Core.Libraries.Covalence.Formatter;

namespace Oxide.Plugins
{
    [Info("RatesController", "Vlad-00003", "3.3.2")]
    [Description("All-in-one customizable rate system for the server")]
    /* 
     * Author info:
     *   E-mail: Vlad-00003@mail.ru
     *   Vk: vk.com/vlad_00003
     * TODO: Вывести частоту срабатывания переплавки в печах
     */
    class RatesController : RustPlugin
    {
        #region Vars

        private static PluginConfig _config;
        private static RatesController _ratesController;
        private PluginData _data;
        private bool _isDay = true;
        private Dictionary<ItemModCookable, float> _smeltRatesBackup = new Dictionary<ItemModCookable, float>();
        private Dictionary<ulong,string> _quarryOwners = new Dictionary<ulong, string>();
        private CoalConfig _defaultCoal;

        private static class Constants
        {
            public const string ExcavatorArmPrefab = "assets/content/structures/excavator/prefabs/excavator_yaw.prefab";
        }

        #endregion

        #region Configuration

        #region Rates

        private sealed class RateType
        {
            private readonly string _name;

            private RateType(string name)
            {
                _name = name;
            }
            public override string ToString()
            {
                return _name;
            }

            public static implicit operator string(RateType type) => type._name;

            public static readonly RateType Quarry = new RateType("Добываемые ресурсы в карьере");
            public static readonly RateType Excavator = new RateType("Добываемые ресурсы в экскаваторе");
            public static readonly RateType Gather = new RateType("Добываемые ресурсы");
            public static readonly RateType Loot = new RateType("Получаемый лут");
            public static readonly RateType Pickup = new RateType("Подбираемые ресурсы");
            public static readonly RateType OvenSpeed = new RateType("Скорость печей");
            public static readonly RateType[] Available = {Quarry, Excavator, Gather, Loot, Pickup, OvenSpeed};
        }

        private class Rates
        {
            [JsonProperty("Днём")]
            private Dictionary<string, float> _day = new Dictionary<string, float>();
            [JsonProperty("Ночью")]
            private Dictionary<string, float> _night = new Dictionary<string, float>();

            public float GetRate(RateType type, bool day = true)
            {
                var dict = day ? _day : _night;
                float val;
                return dict.TryGetValue(type, out val) ? val : 1f;
            }
            
            #region Default Сonfig

            public static Rates Default => DefaultWith(1f);

            public static Rates DefaultWith(float rate) => new Rates
            {
                _day = RateType.Available.ToDictionary(x => (string) x, x => rate),
                _night = RateType.Available.ToDictionary(x => (string) x, x => rate)
            };

            #endregion
        }

        #endregion

        #region Server Time Config

        private class SavedDateConfig
        {
            [JsonProperty("Устанавливать дату при запуске плагина")]
            public bool Use;
            [JsonProperty("День")]
            private int _day;
            [JsonProperty("Месяц")]
            private int _month;
            [JsonProperty("Год")]
            private int _year;
            [JsonProperty("Час")]
            private int _hour;
            [JsonProperty("Минута")]
            private int _minute;
            [JsonProperty("Секунда")]
            private int _second;

            [JsonIgnore]
            public DateTime Date;

            #region Default Config

            public static SavedDateConfig DefaultConfig
            {
                get
                {
                    var now = DateTime.Now;
                    return new SavedDateConfig
                    {
                        Use = false,
                        _day = now.Day,
                        _month = now.Month,
                        _year = now.Year,
                        _hour = 12,
                        _minute = 0,
                        _second = 0
                    };
                }
            }

            #endregion
            
            [OnDeserialized]
            internal void OnDeserializedMethod(StreamingContext context)
            {
                Date = new DateTime(_year,_month,_day,_hour,_minute,_second);
            }
        }

        private class DayNightSwitchConfig
        {
            [JsonProperty("Рассчитывать время по закату/восходу (false - по часам)")]
            public bool UseSun;
            
            [JsonProperty("Час начала дня (игровое время)")]
            public int DayStartHour;
            
            [JsonProperty("Час начала ночи (игровое время)")]
            public int NightStartHour;

            #region Default Config

            public static DayNightSwitchConfig DefaultConfig => new DayNightSwitchConfig
            {
                UseSun = true,
                DayStartHour = 6,
                NightStartHour = 18
            };

            #endregion

            [JsonIgnore]
            public float DayMultiplier;
            [JsonIgnore]
            public float NightMultiplier;
            
            [OnDeserialized]
            internal void OnDeserializedMethod(StreamingContext context)
            {
                DayMultiplier = 24.0f / (NightStartHour - DayStartHour);
                NightMultiplier = 24.0f / (24.0f - (NightStartHour - DayStartHour));
            }
        }
        
        private class TimeConfig
        {
            [JsonProperty("Длина дня (в минутах)")]
            public int DayLength;

            [JsonProperty("Длина ночи (в минутах)")]
            public int NightLength;

            [JsonProperty("Настройки смены дня/ночи")]
            public DayNightSwitchConfig DayNightSwitchConfig;
            
            [JsonProperty("Восстанавливать состояние времени при запуске плагина")]
            public bool RestoreState;

            [JsonProperty("Устанавливаемая при запуске плагина дата")]
            public SavedDateConfig SavedDateConfig;
            
            #region Default Config

            public static TimeConfig DefaultConfig => new TimeConfig
            {
                DayLength = 30,
                NightLength = 30,
                DayNightSwitchConfig = DayNightSwitchConfig.DefaultConfig,
                RestoreState = true,
                SavedDateConfig = SavedDateConfig.DefaultConfig
            };

            #endregion
        }

        #endregion

        #region General Options

        private class ChatConfig
        {
            [JsonProperty("Выводить сообщения в чат о начале дня или ночи")]
            public bool NotifyTod;

            [JsonProperty("Формат сообщений в чате")]
            private string _chatFormat;

            [JsonIgnore]
            public string ChatFormat;

            #region Default Config

            public static ChatConfig DefaultConfig => new ChatConfig
            {
                NotifyTod = true,
                _chatFormat = "<color=#ff0000>[RatesController]</color>: {0}"
            };

            #endregion
            
            [OnDeserialized]
            internal void OnDeserializedMethod(StreamingContext context)
            {
                ChatFormat =  Formatter.ToUnity(_chatFormat);
            }
        }

        [JsonObject(MemberSerialization.OptIn)]
        private class DefaultModifiers
        {
            [JsonProperty("Время переработки ресурсов (в секундах)")]
            public Dictionary<string, float> SmeltRates;
            [JsonProperty("Множители добываемых ресурсов")]
            private Dictionary<string, float> _gatherRates;
            [JsonProperty("Множители добываемых ресурсов в карьере")]
            private Dictionary<string, float> _quarryRates;
            [JsonProperty("Множители добываемых ресурсов в экскаваторе")]
            private Dictionary<string, float> _excavatorRates;
            [JsonProperty("Множители подбираемых ресурсов")]
            private Dictionary<string, float> _pickupRates;
            
            #region Default Config

            public static DefaultModifiers DefaultConfig
            {
                get
                {
                    var modifiers = new DefaultModifiers
                    {
                        SmeltRates = new Dictionary<string, float>(),
                        _gatherRates = new Dictionary<string, float>
                        {
                            ["Animal Fat"] = 1.0f,
                            ["Raw Bear Meat"] = 1.0f,
                            ["Bone Fragments"] = 1.0f,
                            ["Cloth"] = 1.0f,
                            ["High Quality Metal Ore"] = 1.0f,
                            ["Human Skull"] = 1.0f,
                            ["Leather"] = 1.0f,
                            ["Metal Ore"] = 1.0f,
                            ["Pork"] = 1.0f,
                            ["Raw Chicken Breast"] = 1.0f,
                            ["Raw Human Meat"] = 1.0f,
                            ["Raw Wolf Meat"] = 1.0f,
                            ["Stones"] = 1.0f,
                            ["Sulfur Ore"] = 1.0f,
                            ["Wolf Skull"] = 1.0f,
                            ["Wood"] = 1.0f,
                            ["Raw Deer Meat"] = 1.0f,
                            ["Cactus Flesh"] = 1.0f
                        },
                        _quarryRates = new Dictionary<string, float>
                        {
                            ["High Quality Metal Ore"] = 1.0f,
                            ["Sulfur Ore"] = 1.0f,
                            ["Stones"] = 1.0f,
                            ["Metal Fragments"] = 1.0f,
                            ["Crude Oil"] = 1.0f
                        },
                        _excavatorRates = GameManager.server.FindPrefab(Constants.ExcavatorArmPrefab).GetComponent<ExcavatorArm>()?.resourcesToMine.ToDictionary(x => x.itemDef.displayName.english, x => 1f),
                        _pickupRates = new Dictionary<string, float>
                        {
                            ["Metal Ore"] = 1.0f,
                            ["Stones"] = 1.0f,
                            ["Sulfur Ore"] = 1.0f,
                            ["Wood"] = 1.0f,
                            ["Hemp Seed"] = 1.0f,
                            ["Corn Seed"] = 1.0f,
                            ["Pumpkin Seed"] = 1.0f,
                            ["Cloth"] = 1.0f,
                            ["Pumpkin"] = 1.0f,
                            ["Corn"] = 1.0f,
                            ["Wolf Skull"] = 1.0f
                        }
                    };

                    ItemManager.GetItemDefinitions().ForEach(def =>
                    {
                        var cookable = def.GetComponent<ItemModCookable>();
                        if (!cookable)
                            return;
                        modifiers.SmeltRates[def.displayName.english] = cookable.cookTime;
                    });

                    return modifiers;
                }
            }


            #endregion

            public float GetModifier(RateType type, ItemDefinition def)
            {
                if (type == RateType.Gather)
                    return GetModifier(def, _gatherRates);
                if (type == RateType.Quarry)
                    return GetModifier(def, _quarryRates);
                if (type == RateType.Excavator)
                    return GetModifier(def, _excavatorRates);
                if (type == RateType.Pickup)
                    return GetModifier(def, _pickupRates);
                return 1f;
            }

            private float GetModifier(ItemDefinition def, Dictionary<string, float> data)
            {
                float mod;
                if (data.TryGetValue(def.displayName.english, out mod) || data.TryGetValue(def.shortname, out mod))
                    return mod;
                return 1f;
            }
        }

        #endregion

        #region Coal and HQM

         private class HqmConfig
        {
            [JsonProperty("Добавить МВК в список бонусов всех рудных жил")]
            public bool AddHqm;

            [JsonProperty("Количество МВК в жиле")]
            private int _amount;

            [JsonIgnore]
            public ItemDefinition HqmDefinition;
            
            [JsonIgnore]
            public ItemAmount ItemAmount => new ItemAmount(HqmDefinition, _amount);

            #region Default Config

            public static HqmConfig DefaultConfig => new HqmConfig
            {
                AddHqm = false,
                _amount = 2
            };

            #endregion

            [OnDeserialized]
            internal void OnDeserializedMethod(StreamingContext context)
            {
                HqmDefinition = ItemManager.FindItemDefinition("hq.metal.ore");
            }
        }

        private class CoalConfig
        {
            [JsonProperty("Шанс производства")]
            private int _chance;
            [JsonProperty("Количество")]
            public int Amount;

            //UnityEngine.Random.Range(0f, 1f) > burnable.byproductChance
            [JsonIgnore]
            public float Chance;

            #region Default Config

            public static CoalConfig DefaultConfig
            {
                get
                {
                    var coal = ItemManager.FindItemDefinition("wood").GetComponent<ItemModBurnable>();
                    return new CoalConfig
                    {
                        _chance = Mathf.RoundToInt(100 - coal.byproductChance*100),
                        Amount = coal.byproductAmount
                    };
                }
            }

            #endregion

            public static CoalConfig Save()
            {
                var coal = ItemManager.FindItemDefinition("wood").GetComponent<ItemModBurnable>();
                return new CoalConfig
                {
                    Amount = coal.byproductAmount,
                    Chance = coal.byproductChance
                };
            }
            
            [OnDeserialized]
            internal void OnDeserializedMethod(StreamingContext context)
            {
                if (Amount < 0)
                    Amount = 0;
                if (_chance <= 0 || Amount <= 0)
                    Chance = 2;
                else
                    Chance = (100 - _chance) / 100f;
            }
        }

        private class CoalConfigs
        {
            [JsonProperty("Днём")]
            public CoalConfig Day;
            [JsonProperty("Ночью")]
            public CoalConfig Night;

            #region Default Config

            public static CoalConfigs DefaultConfig => new CoalConfigs
            {
                Day = CoalConfig.DefaultConfig,
                Night = CoalConfig.DefaultConfig
            };

            #endregion

            public CoalConfig Get(bool isDay) => isDay ? Day : Night;
        }

        #endregion

        #region Loot
        
        private class AllowedItemsConfig
        {
            [JsonProperty("Тип списка (0 - никак не управлять предметами, 1 - чёрный список, 2 - белый список).")]
            private int _type;

            [JsonProperty("Список предметов")]
            public List<string> Items;
            
            #region Default Config

            public static AllowedItemsConfig DefaultConfig => new AllowedItemsConfig
            {
                _type = 1,
                Items = new List<string> { "Blueprint","Rotten Apple", "Spoiled Wolf Meat", "Spoiled Chicken", "Spoiled Human Meat"}
            };

            #endregion

            public bool ShouldChange(Item item)
            {
                switch (_type)
                {
                    case 1:
                        return !Items.Any(x => x == item.info.displayName.english || x == item.info.shortname);
                    case 2:
                        return Items.Any(x => x == item.info.displayName.english || x == item.info.shortname);
                    default:
                        return true;
                }
            }
        }

        private class LootConfig
        {
            [JsonProperty("Предметы, на которые действуют множители")]
            public AllowedItemsConfig AllowedItems;
            [JsonProperty("Предметы, которые не будут выпадать вообще")]
            public List<string> BlackList;
            [JsonProperty("Множитель для предметов, не указанных в списке ниже")]
            public float DefaultModifier;
            [JsonProperty("Список множителей отдельных предметов (SkinID:Множитель)")]
            public Dictionary<string, Dictionary<ulong, float>> CustomModifiers;

            #region Default Config

            public static LootConfig DefaultConfig => new LootConfig
            {
                AllowedItems = AllowedItemsConfig.DefaultConfig,
                BlackList = new List<string>{"Rotten Apple"},
                DefaultModifier = 1f,
                CustomModifiers = new Dictionary<string, Dictionary<ulong, float>>
                {
                    ["battery.small"] = new Dictionary<ulong, float>
                    {
                        [0] = 1f,
                        [12331] = 2f
                    },
                    ["scrap"] = new Dictionary<ulong, float>
                    {
                        [0] = 1f
                    }
                }
            };

            #endregion

            public bool ShouldDrop(Item item) =>
                !BlackList.Any(x => x == item.info.displayName.english || x == item.info.shortname);

            public float GetModifier(Item item)
            {
                Dictionary<ulong, float> skins;
                if (!CustomModifiers.TryGetValue(item.info.shortname, out skins) &&
                    !CustomModifiers.TryGetValue(item.info.displayName.english, out skins))
                    return DefaultModifier;
                float mod;
                return !skins.TryGetValue(item.skin, out mod) ? DefaultModifier : mod;
            }
        }

        #endregion

        private class PluginConfig
        {
            [JsonProperty("Настройки сообщений в чате")]
            public ChatConfig ChatConfig;

            [JsonProperty("Настройки даты и времени")]
            public TimeConfig TimeConfig;

            [JsonProperty("Металл высокого качества")]
            public HqmConfig HqmConfig;

            [JsonProperty("Производство угля при сжигании дерева")]
            public CoalConfigs CoalConfigs;

            [JsonProperty("Настройки лута")]
            public LootConfig LootConfig;

            [JsonProperty("Общие множители")]
            public Rates DefaultRates;

            [JsonProperty("Множители по привилегиям")]
            public Dictionary<string, Rates> CustomRates = new Dictionary<string, Rates>(StringComparer.InvariantCultureIgnoreCase);

            [JsonProperty("Множители ресурсов")]
            public DefaultModifiers DefaultModifiers;

            [JsonProperty("Дополнительные привилегии (прибавляются к основным, любые источники)")]
            public Dictionary<string, float> AdditionalPermissions = new Dictionary<string, float>(StringComparer.InvariantCultureIgnoreCase);

            [JsonProperty("Переключатели множителей в печах")]
            public Dictionary<string, bool> OvenSwitches;

            #region Default Config

            public static PluginConfig DefaultConfig => new PluginConfig
            {
                ChatConfig = ChatConfig.DefaultConfig,
                TimeConfig = TimeConfig.DefaultConfig,
                HqmConfig = HqmConfig.DefaultConfig,
                CoalConfigs = CoalConfigs.DefaultConfig,
                LootConfig = LootConfig.DefaultConfig,
                DefaultRates = Rates.Default,
                CustomRates = 
                {
                    [nameof(RatesController)+".vip"] = Rates.DefaultWith(2f),
                    [nameof(RatesController)+".premium"] = Rates.DefaultWith(3f)
                },
                DefaultModifiers = DefaultModifiers.DefaultConfig,
                AdditionalPermissions =
                {
                    ["RatesController.NameReward"] = 0.3f
                },
                OvenSwitches = null
            };
            #endregion
            
        }

        #endregion
        
        #region Data

        private class PluginData
        {
            public bool IsFrozen;
        }

        #endregion

        #region Config and Data initialization

        #region Data

        private void LoadData()
        {
            try
            {
                _data = Interface.Oxide.DataFileSystem.ReadObject<PluginData>(Title);
            }
            catch (Exception ex)
            {
                PrintError($"Failed to load data (is the file corrupt?) - no previously created recycles would work ({ex.Message})");
                _data = new PluginData();
            }
        }
        private void SaveData()
        {
            if(TimeController.Initialized)
                _data.IsFrozen = TimeController.Instance.IsFrozen;
            Interface.Oxide.DataFileSystem.WriteObject(Title, _data);
        }

        #endregion

        #region Config

        protected override void LoadConfig()
        {
            base.LoadConfig();
            _config = Config.ReadObject<PluginConfig>();

            if (ShouldUpdateConfig())
                SaveConfig();

            foreach (var customRate in _config.CustomRates)
            {
                permission.RegisterPermission(customRate.Key, this);
            }
            foreach (var addPerm in _config.AdditionalPermissions)
            {
                permission.RegisterPermission(addPerm.Key, this);
            }


            LoadData();
        }

        private bool ShouldUpdateConfig()
        {
            bool res = false;
            if (_config.TimeConfig.DayLength < 0)
            {
                PrintWarning("Day length can't be less then 0, setting to 0");
                _config.TimeConfig.DayLength = 0;
                res = true;
            }

            if (_config.TimeConfig.NightLength < 0)
            {
                PrintWarning("Night length can't be less then 0, setting to 0");
                _config.TimeConfig.NightLength = 0;
                res = true;
            }

            if (_config.TimeConfig.DayLength == 0 && _config.TimeConfig.NightLength == 0)
            {
                PrintWarning("Both night and day length can't be 0 at the same time, setting day length to 30");
                _config.TimeConfig.DayLength = 30;
                res = true;
            }

            if (!ConfigExists<Dictionary<string,object>>("Дополнительные привилегии (прибавляются к основным, любые источники)"))
            {
                PrintWarning("New option added to the config file - additional rates");
                _config.AdditionalPermissions = new Dictionary<string, float>() {["RatesController.NameReward"] = 0.3f};
                res = true;
            }

            if (!ConfigExists<double>("Настройки лута", "Множитель для предметов, не указанных в списке ниже"))
            {
                PrintWarning("New options added to the config file - custom loot items modifiers, furnace selector");
                _config.LootConfig.DefaultModifier = 1f;
                _config.LootConfig.CustomModifiers = LootConfig.DefaultConfig.CustomModifiers;
                res = true;
            }
            return res;
        }

        protected override void LoadDefaultConfig()
        {
            _config = PluginConfig.DefaultConfig;
        }

        protected override void SaveConfig()
        {
            Config.WriteObject(_config);
        }
        private bool ConfigExists<T>(params string[] path)
        {
            var value = Config.Get(path);
            return value is T;
        }

        #endregion

        #endregion

        #region Localization
        private static string GetMessage(string langKey, string playerId = null)
        {
            return _ratesController.lang.GetMessage(langKey, _ratesController, playerId);
        }

        private static string GetMessage(string langKey, string playerId = null, params object[] args)
        {
            return args.Length == 0 ? GetMessage(langKey, playerId) : string.Format(GetMessage(langKey, playerId), args);
        }

        private static void SendResponse(BasePlayer player, string langKey, params object[] args)
        {
            if (!player || !player.IsConnected)
                return;
            player.ChatMessage(string.Format(_config.ChatConfig.ChatFormat, GetMessage(langKey, player.UserIDString, args)));
        }

        private static void SendResponse(IPlayer player, string langKey, params object[] args)
        {
            player.Reply(string.Format(_config.ChatConfig.ChatFormat, GetMessage(langKey, player.Id, args)));
        }
        
        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                [RateType.Quarry] = "Quarry gather rates: {0}",
                [RateType.Excavator] = "Excavator gather rates: {0}",
                [RateType.Gather] = "Gather rates: {0}",
                [RateType.Loot] = "Loot rates: {0}",
                [RateType.Pickup] = "Pickup rates: {0}",
                [RateType.OvenSpeed] = "Oven speed: {0}",
                ["RatesPersonal"] = "Your personal rates:\n{0}",
                ["DayStarted"] = "The day has come!\n{0}",
                ["NightStarted"] ="The night has come!\n{0}",
                ["PositiveRate"] = "<color=green>{0:P0}</color>",
                ["NegativeRate"] = "<color=red>{0:P0}</color>",
                ["NeutralRate"] = "{0:P0}"
            }, this);
            lang.RegisterMessages(new Dictionary<string, string>
            {
                [RateType.Quarry] = "Добываемые ресурсы в карьере: {0}",
                [RateType.Excavator] = "Добываемые ресурсы в экскаваторе: {0}",
                [RateType.Gather] = "Добываемые ресурсы: {0}",
                [RateType.Loot] = "Получаемый лут: {0}",
                [RateType.Pickup] = "Подбираемые ресурсы: {0}",
                [RateType.OvenSpeed] = "Скорость печей: {0}",
                ["RatesPersonal"] = "Ваши личные рейты:\n{0}",
                ["DayStarted"] = "Наступает день!\n{0}",
                ["NightStarted"] ="Наступает ночь!\n{0}",
                ["PositiveRate"] = "<color=green>{0:P0}</color>",
                ["NegativeRate"] = "<color=red>{0:P0}</color>",
                ["NeutralRate"] = "{0:P0}"
            }, this, "ru");

        }

        #endregion
        
        #region Time controller
        
        private class TimeController: FacepunchBehaviour
        {
            private int _attempt;
            private TOD_Sky _sky;
            private TOD_Time _time;
            private bool _isDaySet;
            private float _lastKnownTime; //env.time set workaround
            private bool _initialized;

            public static TimeController Instance { get; private set; }
            public static bool Initialized => Instance && Instance._initialized;

            #region Instance public properties

            public bool IsFrozen
            {
                get { return !_time.ProgressTime; }
                set { _time.ProgressTime = !value; }
            }

            #endregion

            #region Private properties

            private bool IsDay => DayStart <= _sky.Cycle.Hour && _sky.Cycle.Hour < NightStart;

            private float DayStart
            {
                get
                {
                    if (!_config.TimeConfig.DayNightSwitchConfig.UseSun)
                        return _config.TimeConfig.DayNightSwitchConfig.DayStartHour;
                    return _sky.SunriseTime;
                }
            }

            private float NightStart
            {
                get
                {
                    if (!_config.TimeConfig.DayNightSwitchConfig.UseSun)
                        return _config.TimeConfig.DayNightSwitchConfig.NightStartHour;
                    return _sky.SunsetTime;
                }
            }

            private float DayLength
            {
                get
                {
                    if (!_config.TimeConfig.DayNightSwitchConfig.UseSun)
                        return _config.TimeConfig.DayLength * _config.TimeConfig.DayNightSwitchConfig.DayMultiplier;
                    return _config.TimeConfig.DayLength * (24.0f / (_sky.SunsetTime - _sky.SunriseTime));
                }
            }

            private float NightLength
            {
                get
                {
                    if (!_config.TimeConfig.DayNightSwitchConfig.UseSun)
                        return _config.TimeConfig.NightLength * _config.TimeConfig.DayNightSwitchConfig.NightMultiplier;
                    return _config.TimeConfig.NightLength * (24.0f / (24.0f - (_sky.SunsetTime - _sky.SunriseTime)));
                }
            }

            #endregion

            #region Initialization

            public void Initialize()
            {
                _sky = TOD_Sky.Instance;
                if (_sky == null)
                {
                    if (_attempt++ < 10)
                    {
                        Invoke(Initialize,1f);
                        return;
                    }
                    _ratesController.PrintError("Failed to get TOD_Sky instance in {0} attempts.", _attempt);
                    return;
                }
                _ratesController.Puts("TOD_Sky found after {0} attempts", _attempt);
                _time = _sky.Components.Time;
                if (_time == null)
                {
                    _ratesController.PrintError("Can't find time component!");
                    return;
                }
                
                _initialized = true;

                SetData();
                
                if(IsDay)
                    OnDayStarted();
                else
                    OnNightStarted();
                _time.OnHour += OnHour;
            }
            
            private void SetData()
            {
                _time.UseTimeCurve = false;
                if (_config.TimeConfig.SavedDateConfig.Use)
                    _sky.Cycle.DateTime = _config.TimeConfig.SavedDateConfig.Date;
                if (_config.TimeConfig.RestoreState)
                    _time.ProgressTime = !_ratesController._data.IsFrozen;
                

                _lastKnownTime = _sky.Cycle.Hour;
            }

            #endregion
            
            #region Day/Night Switch
            
            private void OnDayStarted()
            {
                if (!Initialized)
                    return;
                var dayLength = DayLength;
                if (dayLength <= 0)
                {
                    print("Day skipped");
                    _sky.Cycle.Hour = NightStart;
                    _lastKnownTime = _sky.Cycle.Hour;
                    OnNightStarted();
                    return;
                }

                _time.DayLengthInMinutes = dayLength;
                Interface.CallHook("OnDayStarted");
                _isDaySet = true;
            }

            private void OnNightStarted()
            {
                if (!Initialized)
                    return;
                var nightLength = NightLength;
                if (nightLength <= 0)
                {
                    print("Night skipped");
                    _sky.Cycle.Hour += 24 - _sky.Cycle.Hour + DayStart;
                    _lastKnownTime = _sky.Cycle.Hour;
                    OnDayStarted();
                    return;
                }

                _time.DayLengthInMinutes = nightLength;
                Interface.CallHook("OnNightStarted");
                _isDaySet = false;
            }

            #endregion
            
            #region Actions
            private void OnHour()
            {
                if(IsDay && !_isDaySet)
                    OnDayStarted();
                if(!IsDay && _isDaySet)
                    OnNightStarted();
            }

            //env.time set workaround
            private void Update()
            {
                if (!Initialized)
                    return;
                if (Math.Abs(_sky.Cycle.Hour - _lastKnownTime) > Time.deltaTime)
                    OnHour();
                _lastKnownTime = _sky.Cycle.Hour;
            }

            #endregion
          
            public void Kill()
            {
                if (!Initialized)
                    return;
                _time.OnHour -= OnHour;
                Destroy(gameObject);
                Instance = null;
            }

            public static TimeController Create()
            {
                if (Instance)
                {
                    _ratesController.PrintWarning("TimeController wasn't destroyed");
                    Instance.Kill();
                }
                var go = new GameObject(nameof(RatesController) + "." + nameof(TimeController));
                DontDestroyOnLoad(go);
                Instance = go.AddComponent<TimeController>();
                return Instance;
            }
        }

        #endregion

        #region Initialization and quitting

        private void Init()
        {
            _ratesController = this;
            Unsubscribe("OnPluginLoaded");
            Unsubscribe("OnPlayerDisconnected");
            Unsubscribe("OnPluginUnloaded");
            Unsubscribe("OnPlayerConnected");
        }
        private void Unload()
        {
            LootController.KillAll();
            TimeController.Instance?.Kill();
            UpdateCoalRates(true);
            OnServerSave();
            foreach (var pair in _smeltRatesBackup)
                pair.Key.cookTime = pair.Value;
            
            _config = null;
            _ratesController = null;
            _data = null;
            _defaultCoal = null;
            _smeltRatesBackup.Clear();
            _smeltRatesBackup = null;
            _quarryOwners.Clear();
            _quarryOwners = null;
            _ratesCache.Clear();
        }

        private void OnServerSave() =>  SaveData();
        private void OnServerInitialized()
        {
            var ovens = GameManager.server.preProcessed.prefabList.Values.Select(x => x.GetComponent<BaseOven>()).Where(x => x != null && (int)x.temperature >= 2);
            if (_config.OvenSwitches == null)
            {
                _config.OvenSwitches = ovens.ToDictionary(x => x.ShortPrefabName, x => true);
                SaveConfig();
                PrintWarning("Oven switches list was null, filling with default values.Config was overwritten");
            }
            else
            {
                var changed = false;
                foreach (var oven in ovens)
                {
                    if (_config.OvenSwitches.ContainsKey(oven.ShortPrefabName))
                        continue;
                    _config.OvenSwitches[oven.ShortPrefabName] = true;
                    changed = true;
                }

                if (changed)
                {
                    SaveConfig();
                    PrintWarning("New type(s) of oven added to the Oven Switch List");
                }
            }
            _defaultCoal = CoalConfig.Save();
            TimeController.Create().Initialize();
            ItemManager.GetItemDefinitions().ForEach(SetCookableDefinition);
            UpdateCoalRates();
        }

        
        #endregion

        #region Time Hooks
        
        private void OnDayStarted()
        {
            _isDay = true;
            UpdateCoalRates();
            _ratesCache.Clear();
            if (!_config.ChatConfig.NotifyTod)
                return;
            foreach (var player in BasePlayer.activePlayerList)
                SendRates(player, "DayStarted");
            
        }

        private void OnNightStarted()
        {
            _isDay = false;
            UpdateCoalRates();
            _ratesCache.Clear();
            if (!_config.ChatConfig.NotifyTod)
                return;
            foreach (var player in BasePlayer.activePlayerList)
                SendRates(player, "NightStarted");
        }

        #endregion

        #region Oxide Hooks (Rates Cache)

        private void OnUserGroupAdded(string playerId, string groupName)
        {
            if (permission.GetGroupPermissions(groupName).Any(groupPermission =>
                    _config.CustomRates.ContainsKey(groupPermission) || _config.AdditionalPermissions.ContainsKey(groupPermission)))
            {
                _ratesCache.Remove(playerId);
            }
        }

        private void OnUserGroupRemoved(string playerId, string groupName)
        {
            if (permission.GetGroupPermissions(groupName).Any(groupPermission
                    => _config.CustomRates.ContainsKey(groupPermission) || _config.AdditionalPermissions.ContainsKey(groupPermission)))
            {
                _ratesCache.Remove(playerId);
            }
        }

        private void OnUserPermissionGranted(string playerId, string perm)
        {
            if (!_config.CustomRates.ContainsKey(perm) && !_config.AdditionalPermissions.ContainsKey(perm))
                return;
            _ratesCache.Remove(playerId);
        }

        private void OnUserPermissionRevoked(string playerId, string perm)
        {
            if (!_config.CustomRates.ContainsKey(perm) && !_config.AdditionalPermissions.ContainsKey(perm))
                return;
            _ratesCache.Remove(playerId);
        }

        private void OnGroupPermissionGranted(string group, string perm)
        {
            if (!_config.CustomRates.ContainsKey(perm) && !_config.AdditionalPermissions.ContainsKey(perm))
                return;
            foreach (var user in permission.GetUsersInGroup(group))
                _ratesCache.Remove(user.Split(' ')[0]);
        }

        private void OnGroupPermissionRevoked(string group, string perm)
        {
            if (!_config.CustomRates.ContainsKey(perm) && !_config.AdditionalPermissions.ContainsKey(perm))
                return;
            foreach (var user in permission.GetUsersInGroup(group))
                _ratesCache.Remove(user.Split(' ')[0]);
        }

        #endregion

        #region Oxide Hooks (Sub)
        
        private void OnQuarryToggled(MiningQuarry quarry, BasePlayer player)
        {
            if (!player || !quarry || !quarry.IsOn() || quarry.OwnerID != 0)
                return;
            _quarryOwners[quarry.net.ID.Value] = player.UserIDString;
        }
        private void OnExcavatorResourceSet(ExcavatorArm arm, string resource, BasePlayer player)
        {
            if (!player || !arm || arm.OwnerID != 0)
                return;
            _quarryOwners[arm.net.ID.Value] = player.UserIDString;
        }
        
        private void CanMoveItem(Item item, PlayerInventory playerLoot, ItemContainerId targetContainer, int targetSlot, int amount)
        {
            var container = item.GetRootContainer()?.entityOwner as LootContainer;
            if (!container)
                return; 
            LootController.GetOrAdd(container).OnMove(item, playerLoot, amount);
        }

        private void OnItemAction(Item item, string action, BasePlayer player)
        {
            if (action != "drop")
                return;
            var container = item.GetRootContainer()?.entityOwner as LootContainer;
            if (!container)
                return;
            LootController.GetOrAdd(container).OnDrop(item, player);
        }


        private void OnItemAddedToContainer(ItemContainer inventory, Item item)
        {
            var container = item.GetRootContainer()?.entityOwner as LootContainer;
            if (!container)
                return;
            LootController.GetOrAdd(container).OnRefill(inventory);
        }
        #endregion

        #region Oxide Hooks (Rates)
        
        private void OnQuarryGather(MiningQuarry quarry, Item item)
        {
            UpdateAmount(item, RateType.Quarry, GetQuarryOwner(quarry));
        } 
       
        private void OnExcavatorGather(ExcavatorArm arm, Item item)
        {
            UpdateAmount(item, RateType.Excavator, GetQuarryOwner(arm));
        }

        private void OnDispenserGather(ResourceDispenser dispenser, BasePlayer player, Item item)
        {
            UpdateAmount(item, RateType.Gather, player.UserIDString);
            if (!_config.HqmConfig.AddHqm || dispenser.gatherType != ResourceDispenser.GatherType.Ore)
                return;
            if (dispenser.finishBonus.Any(x => x.itemDef == _config.HqmConfig.HqmDefinition))
                return;
            dispenser.finishBonus.Add(_config.HqmConfig.ItemAmount);
        }

        private void OnDispenserBonus(ResourceDispenser dispenser, BasePlayer player, Item item)
        {
            UpdateAmount(item, RateType.Gather, player.UserIDString);
        }

        private object OnCollectiblePickup(CollectibleEntity entity, BasePlayer player)
        {
            if (!player || !entity)
                return null;
            entity.itemList = UpdateAmounts(entity.itemList, RateType.Pickup, player.UserIDString).ToArray();
            return entity.itemList == null ? (object) false : null;
        }
        
        void OnGrowableGathered(GrowableEntity plant, Item item, BasePlayer player)
        {
            string owner = player.UserIDString;
            if (plant.OwnerID != 0)
                owner = plant.OwnerID.ToString();
            UpdateAmount(item, RateType.Pickup, owner);
        }
        private void OnLootEntity(BasePlayer player, LootContainer container)
        {
            LootController.GetOrAdd(container).OnOpen(player);
        }
        private void OnLootEntityEnd(BasePlayer player, LootContainer container)
        {
            LootController.GetOrAdd(container).OnClose(player);
        }

        private void OnContainerDropItems(ItemContainer container)
        {
            var lootContainer = container?.entityOwner as LootContainer;
            if (lootContainer == null)
                return;
            LootController.GetOrAdd(lootContainer).OnDropItems();
        }

        #region Cooking

        private object OnOvenCook(BaseOven oven, Item fuelItem)
        {
            bool isOn;
            if (_config.OvenSwitches.TryGetValue(oven.ShortPrefabName, out isOn) && !isOn)
                return null;
            
            if ((fuelItem == null && !oven.CanRunWithNoFuel) || oven.OwnerID == 0 || (int)oven.temperature < 2)
                return null;
            var userRate = GetUserRate(RateType.OvenSpeed, oven.OwnerID.ToString());

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

            IncreaseCookTime(oven, 0.5f * oven.GetSmeltingSpeed() * userRate);
            var slot = oven.GetSlot(BaseEntity.Slot.FireMod);
            if (slot)
                slot.SendMessage("Cook", 0.5f, SendMessageOptions.DontRequireReceiver);

            if (fuelItem != null)
            {
                var burnable = fuelItem.info.GetComponent<ItemModBurnable>();
                var requiredFuel = 0.5f * userRate * (oven.cookingTemperature / 200f);
                if (!fuelItem.HasFlag(global::Item.Flag.OnFire))
                {
                    fuelItem.SetFlag(global::Item.Flag.OnFire, true);
                    fuelItem.MarkDirty();
                }
                if (fuelItem.fuel >= requiredFuel)
                {
                    fuelItem.fuel -= requiredFuel;
                    if (fuelItem.fuel <= 0f)
                    {
                        oven.ConsumeFuel(fuelItem, burnable);
                    }
                }
                else
                {
                    while (requiredFuel > 0)
                    {
                        var dif = fuelItem.fuel - requiredFuel;
                        if (dif >= 0)
                        {
                            fuelItem.fuel -= requiredFuel;
                            if (fuelItem.fuel <= 0f)
                            {
                                oven.ConsumeFuel(fuelItem, burnable);
                            }
                            break;
                        }
                        requiredFuel -= fuelItem.fuel;
                        oven.ConsumeFuel(fuelItem, burnable);
                        if (!fuelItem.IsValid())
                            break;
                    
                    }
                
                }
            }
            //oven.OnCooked();
            if (oven is ModularCarOven)
            {
                if (WaterLevel.Test(oven.transform.position, true, false))
                {
                    oven.StopCooking();
                }
            }
            Interface.CallHook("OnOvenCooked", oven, fuelItem, slot);
            return false;

        }
        private void IncreaseCookTime(BaseOven oven,  float amount)
        {
            List<global::Item> list = Facepunch.Pool.GetList<global::Item>();
            foreach (global::Item item in oven.inventory.itemList)
            {
                if (item.HasFlag(global::Item.Flag.Cooking))
                {
                    list.Add(item);
                }
            }
            float num = amount / (float)list.Count;
            foreach (global::Item item2 in list)
            {
                item2.OnCycle(num);
            }
            Facepunch.Pool.FreeList<global::Item>(ref list);
        }

        #endregion


        #endregion

        #region Console Commands

        [ConsoleCommand("env.freeze")]
        private void FreezeCmd(ConsoleSystem.Arg arg)
        {
            if (arg.Connection != null && arg.Connection.authLevel < 2) 
                return;
            if (!TimeController.Initialized)
                return;
            TimeController.Instance.IsFrozen = !TimeController.Instance.IsFrozen;
            arg.ReplyWith(TimeController.Instance.IsFrozen ? "Frozen" : "Unfrozen");
        }

        #endregion

        #region Chat Commands

        [ChatCommand("Rates")]
        private void RatesCmd(BasePlayer player, string command, string[] args)
        {
            SendRates(player, "RatesPersonal");
        }

        #endregion
        
        #region Loot Controller

        private class LootController : FacepunchBehaviour
        {
            private static readonly Dictionary<LootContainer, LootController> LootControllers = new Dictionary<LootContainer, LootController>();
            private LootContainer _lootContainer;
            private
// ... [Code preview truncated due to length. Full source in attached file] ...

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