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

FREE RecycleManager : 2.0.3 2.0.3

Нет прав для скачивания
C#:
// #define ENABLE_TESTS
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core.Libraries.Covalence;
using Oxide.Game.Rust.Cui;
using System;
using System.Collections.Generic;
using System.Linq;
using Oxide.Core;
using Oxide.Core.Libraries;
using UnityEngine;
#if ENABLE_TESTS
using System.Collections;
using System.Reflection;
using Oxide.Core.Plugins;
#endif
namespace Oxide.Plugins {
    [Info("Recycle Manager", "WhiteThunder", "2.0.3")]
    [Description("Allows customizing recycler speed, input, and output")]
    internal class RecycleManager : CovalencePlugin {
#region Fields
        private Configuration _config;
        private const string PermissionAdmin = "recyclemanager.admin";
        private const int ScrapItemId = -932201673;
        private const float RecycleEfficiency = 0.5f;
        private readonly object True = true;
        private readonly object False = false;
        private const int NumInputSlots = 6;
        private const int NumOutputSlots = 6;
        private readonly RecycleComponentManager _recycleComponentManager = new RecycleComponentManager();
        private readonly RecycleEditManager _recycleEditManager;
        private readonly float[] _recycleTime = new float[1];
        private bool IsEditUIEnabled => !_config.UsingDefaults && _config.EditUISettings.Enabled;
#if ENABLE_TESTS
        private readonly RecycleManagerTests _testRunner;
#endif
        public RecycleManager() {
#if ENABLE_TESTS
            _testRunner = new RecycleManagerTests(this);
#endif
            _recycleEditManager = new RecycleEditManager(this);
        }
#endregion
#region Hooks
        private void Init() {
            _config.Init(this);
            _recycleComponentManager.Init(this);
            permission.RegisterPermission(PermissionAdmin, this);
            if (!_config.RecycleSpeed.Enabled) {
                Unsubscribe(nameof(OnRecyclerToggle));
            }
            if (!IsEditUIEnabled) {
                Unsubscribe(nameof(OnLootEntity));
            }
        }
        private void OnServerInitialized() {
#if ENABLE_TESTS
            _testRunner.Run();
#endif
            if (IsEditUIEnabled) {
                foreach (var player in BasePlayer.activePlayerList) {
                    var container = player.inventory.loot.containers.FirstOrDefault();
                    if (container == null) continue;
                    var recycler = container.entityOwner as Recycler;
                    if ((object)recycler == null) continue;
                    OnLootEntity(player, recycler);
                }
            }
        }
        private void Unload() {
#if ENABLE_TESTS
            _testRunner.Interrupt();
#endif
            _recycleComponentManager.Unload();
            _recycleEditManager.Unload();
        }
        // This hook is primarily used to determine whether an item can be placed into the recycler input,
        // but it's also called when processing each item.private object CanBeRecycled(Item item, Recycler recycler)
        {
            if (item == null) return null;
            if (_config.RestrictedInputItems.IsDisallowed(item)) {
                // Defensively return null if vanilla would *disallow* recycling, to avoid hook conflicts.return IsVanillaRecyclable(item) && !RecyclableWasBlocked(item, recycler)
                ? False : null;
            }
            if (_config.OverrideOutput.GetBestOverride(item) != null) {
                // Defensively return null if vanilla would *allow* recycling, to avoid hook conflicts.return IsVanillaRecyclable(item) || RecyclableWasBlocked(item, recycler)
                ? null : True;
            }
            return null;
        }
        private object CanRecycle(Recycler recycler, Item item) {
            return CanBeRecycled(item, recycler);
        }
        private void OnRecyclerToggle(Recycler recycler, BasePlayer player) {
            _recycleComponentManager.HandleRecyclerToggle(recycler, player);
        }
        private object OnItemRecycle(Item item, Recycler recycler) {
            if (RecycleItemWasBlocked(item, recycler)) return null;
            var recycleAmount = DetermineConsumptionAmount(recycler, item);
            if (recycleAmount <= 0) return False;
            var customIngredientList = _config.OverrideOutput.GetBestOverride(item);
            if (customIngredientList != null) {
                item.UseItem(recycleAmount);
                // Overrides already account for standard recycle efficiency, so only calculate based on item condition.if (PopulateOutputWithOverride(recycler, customIngredientList, recycleAmount, DetermineRecycleEfficiency(item)))
                {
                    recycler.StopRecycling();
                }
                return False;
            }
            // If the item is not vanilla recyclable, and this plugin doesn't have an override,
            // that probably means another plugin is going to handle recycling it.if (!IsVanillaRecyclable(item))
            return null;
            item.UseItem(recycleAmount);
            var outputIsFull = PopulateOutputVanilla(_config, recycler, item, recycleAmount, DetermineRecycleEfficiency(item, recycler.recycleEfficiency));
            if (outputIsFull || !recycler.HasRecyclable()) {
                recycler.StopRecycling();
            }
            return False;
        }
        private void OnLootEntity(BasePlayer player, Recycler recycler) {
            if (!recycler.onlyOneUser) return;
            if (permission.UserHasPermission(player.UserIDString, PermissionAdmin)) {
                var player2 = player;
                var recycler2 = recycler;
                NextTick(() => {
                    var lootingContainer = player2.inventory.loot.containers.FirstOrDefault();
                    if (lootingContainer == null || lootingContainer != recycler2.inventory) return;
                    _recycleEditManager.HandlePlayerStartedLooting(player2, recycler2);
                }
                );
            }
        }
#endregion
#region Exposed Hooks
        private static class ExposedHooks {
            public static object OnRecycleManagerItemRecyclable(Item item, Recycler recycler) {
                return Interface.CallHook("OnRecycleManagerItemRecyclable", item, recycler);
            }
            public static object OnRecycleManagerSpeed(Recycler recycler, BasePlayer player, float[] recycleTime) {
                return Interface.CallHook("OnRecycleManagerSpeed", recycler, player, recycleTime);
            }
            public static object OnRecycleManagerRecycle(Item item, Recycler recycler) {
                return Interface.CallHook("OnRecycleManagerRecycle", item, recycler);
            }
        }
#endregion
#region Commands
        [Command("recyclemanager.add", "recman.add")]
        private void CommandAddItem(IPlayer player, string cmd, string[] args) {
            if (!VerifyHasPermission(player, PermissionAdmin) || !VerifyConfigLoaded(player)) return;
            ItemDefinition itemDefinition;
            if (!VerifyValidItemIdOrShortName(player, args.ElementAtOrDefault(0), out itemDefinition, cmd)) return;
            if (!_config.OverrideOutput.AddOverride(this, itemDefinition)) {
                ReplyToPlayer(player, LangEntry.AddExists, itemDefinition.shortname);
                return;
            }
            SaveConfig();
            ReplyToPlayer(player, LangEntry.AddSuccess, itemDefinition.shortname);
        }
        [Command("recyclemanager.reset", "recman.reset")]
        private void CommandResetItem(IPlayer player, string cmd, string[] args) {
            if (!VerifyHasPermission(player, PermissionAdmin) || !VerifyConfigLoaded(player)) return;
            ItemDefinition itemDefinition;
            if (!VerifyValidItemIdOrShortName(player, args.ElementAtOrDefault(0), out itemDefinition, cmd)) return;
            _config.OverrideOutput.ResetOverride(this, itemDefinition);
            SaveConfig();
            ReplyToPlayer(player, LangEntry.ResetSuccess, itemDefinition.shortname);
        }
        [Command("recyclemanager.ui")]
        private void CommandEdit(IPlayer player, string cmd, string[] args) {
            if (player.IsServer || !player.HasPermission(PermissionAdmin)) return;
            var basePlayer = player.Object as BasePlayer;
            _recycleEditManager.GetController(basePlayer)?.HandleUICommand(basePlayer, args);
        }
#endregion
#region Helper Methods - Instance
        private bool VerifyHasPermission(IPlayer player, string perm) {
            if (player.HasPermission(perm)) return true;
            ReplyToPlayer(player, LangEntry.ErrorNoPermission);
            return false;
        }
        private bool VerifyConfigLoaded(IPlayer player) {
            if (!_config.UsingDefaults) return true;
            ReplyToPlayer(player, LangEntry.ErrorConfig);
            return false;
        }
        private bool VerifyValidItemIdOrShortName(IPlayer player, string itemArg, out ItemDefinition itemDefinition, string command) {
            if (itemArg == null) {
                itemDefinition = (player.Object as BasePlayer)?.GetActiveItem()?.info;
                if (itemDefinition != null) return true;
                ReplyToPlayer(player, LangEntry.ItemSyntax, command);
                return false;
            }
            int itemId;
            if (int.TryParse(itemArg, out itemId)) {
                itemDefinition = ItemManager.FindItemDefinition(itemId);
                if (itemDefinition != null) return true;
            }
            itemDefinition = ItemManager.FindItemDefinition(itemArg);
            if (itemDefinition != null) return true;
            ReplyToPlayer(player, LangEntry.ErrorInvalidItem, itemArg);
            return false;
        }
        private bool TryDetermineRecycleTime(Recycler recycler, BasePlayer player, out float recycleTime) {
            _recycleTime[0] = _config.RecycleSpeed.DefaultRecycleTime * _config.RecycleSpeed.GetTimeMultiplierForPlayer(player);
            if (_config.RecycleSpeed.SafeZoneTimeMultiplier != 1 && player.InSafeZone()) {
                _recycleTime[0] *= _config.RecycleSpeed.SafeZoneTimeMultiplier;
            }
            var hookResult = ExposedHooks.OnRecycleManagerSpeed(recycler, player, _recycleTime);
            if (hookResult is bool && !(bool)hookResult) {
                recycleTime = 0;
                return false;
            }
            recycleTime = Math.Max(0, _recycleTime[0]);
            return true;
        }
        private object CallCanBeRecycled(Item item, Recycler recycler) {
            Unsubscribe(nameof(CanBeRecycled));
            var hookResult = Interface.CallHook(nameof(CanBeRecycled), item, recycler);
            Subscribe(nameof(CanBeRecycled));
            return hookResult;
        }
        private IngredientInfo[] GetVanillaOutput(ItemDefinition itemDefinition) {
            if (itemDefinition.Blueprint?.ingredients == null) return new IngredientInfo[0];
            var ingredientList = new List<IngredientInfo>();
            if (itemDefinition.Blueprint.scrapFromRecycle > 0) {
                var ingredientInfo = new IngredientInfo {
                    ShortName = "scrap", Amount = itemDefinition.Blueprint.scrapFromRecycle,
                }
                ;
                ingredientInfo.Init();
                ingredientList.Add(ingredientInfo);
            }
            foreach (var blueprintIngredient in itemDefinition.Blueprint.ingredients) {
                if (blueprintIngredient.itemid == ScrapItemId) continue;
                var amount = blueprintIngredient.amount / itemDefinition.Blueprint.amountToCreate * RecycleEfficiency;
                if (amount > 1) {
                    amount = Mathf.CeilToInt(amount);
                }
                var ingredientInfo = new IngredientInfo {
                    ShortName = blueprintIngredient.itemDef.shortname, Amount = amount,
                }
                ;
                ingredientInfo.Init();
                ingredientList.Add(ingredientInfo);
            }
            return ingredientList.ToArray();
        }
        private float DetermineRecycleEfficiency(Item item, float recycleEfficiency = 1) {
            return item.hasCondition ? Mathf.Clamp01(recycleEfficiency * Mathf.Clamp(item.conditionNormalized * item.maxConditionNormalized, 0.1f, 1f)) : recycleEfficiency;
        }
        private int DetermineConsumptionAmount(Recycler recycler, Item item) {
            var recycleAmount = 1;
            if (item.amount > 1) {
                var consumeMultiplier = _config.MaxItemsPerRecycle.GetPercent(item) / 100f;
                recycleAmount = Mathf.CeilToInt(Mathf.Min(item.amount, (float)item.info.stackable * consumeMultiplier));
                // In case the configured multiplier is 0, ensure at least 1 item is recycled.recycleAmount = Math.Max(recycleAmount, 1);
            }
            // Call standard Oxide hook for compatibility.var amountOverride = Interface.CallHook("OnItemRecycleAmount", item, recycleAmount, recycler);
            if (amountOverride is int) {
                return (int)amountOverride;
            }
            return recycleAmount;
        }
        private bool PopulateOutputWithOverride(Recycler recycler, IngredientInfo[] customIngredientList, int recycleAmount, float recycleEfficiency = 1, bool forEditor = false) {
            var outputIsFull = false;
            foreach (var ingredientInfo in customIngredientList) {
                if (ingredientInfo.ItemDefinition == null) continue;
                var ingredientAmount = ingredientInfo.Amount * recycleEfficiency;
                if (ingredientAmount <= 0) continue;
                var outputAmount = CalculateOutputAmount(recycleAmount, ingredientAmount, forEditor : forEditor);
                if (outputAmount <= 0) continue;
                if (AddItemToRecyclerOutput(recycler, ingredientInfo.ItemDefinition, outputAmount, ingredientInfo.SkinId, ingredientInfo.DisplayName)) {
                    outputIsFull = true;
                }
            }
            return outputIsFull;
        }
        private static bool PopulateOutputVanilla(Configuration config, Recycler recycler, Item item, int recycleAmount, float recycleEfficiency = RecycleEfficiency, bool forEditor = false) {
            var outputIsFull = false;
            if (item.info.Blueprint.scrapFromRecycle > 0) {
                var scrapOutputMultiplier = config.OutputMultipliers.GetOutputMultiplier(ScrapItemId);
                var scrapAmount = Mathf.CeilToInt(item.info.Blueprint.scrapFromRecycle * recycleAmount);
                scrapAmount = Mathf.CeilToInt(scrapAmount * scrapOutputMultiplier);
                if (!forEditor && item.info.stackable == 1 && item.hasCondition) {
                    scrapAmount = Mathf.CeilToInt(scrapAmount * item.conditionNormalized);
                }
                if (scrapAmount >= 1) {
                    var scrapItem = ItemManager.CreateByItemID(ScrapItemId, scrapAmount);
                    recycler.MoveItemToOutput(scrapItem);
                }
            }
            foreach (var ingredient in item.info.Blueprint.ingredients) {
                // Skip scrap since it's handled separately.if (ingredient.itemDef.itemid == ScrapItemId)
                continue;
                var ingredientAmount = ingredient.amount * recycleEfficiency / item.info.Blueprint.amountToCreate;
                if (ingredientAmount <= 0) continue;
                var outputAmount = CalculateOutputAmount(recycleAmount, ingredientAmount, config.OutputMultipliers.GetOutputMultiplier(ingredient.itemid), forEditor );
                if (outputAmount <= 0) continue;
                if (AddItemToRecyclerOutput(recycler, ingredient.itemDef, outputAmount)) {
                    outputIsFull = true;
                }
            }
            return outputIsFull;
        }
#endregion
#region Helper Methods - Static
        public static void LogInfo(string message) => Interface.Oxide.LogInfo($"[Recycle Manager] {message}");
        public static void LogError(string message) => Interface.Oxide.LogError($"[Recycle Manager] {message}");
        public static void LogWarning(string message) => Interface.Oxide.LogWarning($"[Recycle Manager] {message}");
        private static void Swap<T>(ref T a, ref T b) {
            T temp = a;
            a = b;
            b = temp;
        }
        private static bool IsVanillaRecyclable(Item item) {
            return item.info.Blueprint != null;
        }
        private static bool RecyclableWasBlocked(Item item, Recycler recycler) {
            var hookResult = ExposedHooks.OnRecycleManagerItemRecyclable(item, recycler);
            return hookResult is bool && (bool)hookResult == false;
        }
        private static bool RecycleItemWasBlocked(Item item, Recycler recycler) {
            var hookResult = ExposedHooks.OnRecycleManagerRecycle(item, recycler);
            return hookResult is bool && (bool)hookResult == false;
        }
        private static Item CreateItem(ItemDefinition itemDefinition, int amount, ulong skinId, string displayName = null) {
            var item = ItemManager.Create(itemDefinition, amount, skinId);
            if (!string.IsNullOrWhiteSpace(displayName)) {
                item.name = displayName;
            }
            return item;
        }
        private static int CalculateOutputAmountVanillaRandom(int recycleAmount, float ingredientChance) {
            var outputAmount = 0;
            // Roll a random number for every item to consume.for (var i = 0; i < recycleAmount; i++)
            {
                if (UnityEngine.Random.Range(0f, 1f) <= ingredientChance) {
                    outputAmount++;
                }
            }
            return outputAmount;
        }
        private static int CalculateOutputAmountFast(int recycleAmount, float ingredientAmount) {
            // To save on performance, don't generate hundreds/thousands/millions of random numbers.var fractionalOutputAmount = ingredientAmount * recycleAmount;
            var integerOutputAmount = (int)fractionalOutputAmount;
            // Roll a random number to see if the the remainder should be given.var remainderFractionalOutputAmount = fractionalOutputAmount - integerOutputAmount;
            if (remainderFractionalOutputAmount > 0 && UnityEngine.Random.Range(0f, 1f) <= remainderFractionalOutputAmount) {
                integerOutputAmount++;
            }
            return integerOutputAmount;
        }
        private static int CalculateOutputAmount(int recycleAmount, float ingredientAmount, float outputMultiplier = 1, bool forEditor = false) {
            // Adjust using vanilla rounding behavior before applying multipliers, to match user expectations.var adjustedIngredientAmount = ingredientAmount > 1
            ? Mathf.Ceil(ingredientAmount) : ingredientAmount;
            adjustedIngredientAmount *= outputMultiplier;
            // Use more optimized RNG for stacks larger than 100, because players probably don't care at that point.var outputAmount = adjustedIngredientAmount < 1 && recycleAmount <= 100
            ? CalculateOutputAmountVanillaRandom(recycleAmount, adjustedIngredientAmount) : CalculateOutputAmountFast(recycleAmount, adjustedIngredientAmount);
            return forEditor ? Math.Max(1, outputAmount) : outputAmount;
        }
        private static bool AddItemToRecyclerOutput(Recycler recycler, ItemDefinition itemDefinition, int ingredientAmount, ulong skinId = 0, string displayName = null) {
            var outputIsFull = false;
            var numStacks = Mathf.CeilToInt(ingredientAmount / (float)itemDefinition.stackable);
            for (var i = 0; i < numStacks; i++) {
                var amountForStack = Math.Min(ingredientAmount, itemDefinition.stackable);
                var outputItem = CreateItem(itemDefinition, amountForStack, skinId, displayName);
                if (!recycler.MoveItemToOutput(outputItem)) {
                    outputIsFull = true;
                }
                ingredientAmount -= amountForStack;
                if (ingredientAmount <= 0) break;
            }
            return outputIsFull;
        }
#endregion
#region UI
        private enum IdentificationType {
            Item, Skin, DisplayName,
        }
        private enum OutputType {
            NotRecyclable, Default, Custom,
        }
        private enum UICommand {
            Edit, Reset, Save, Cancel, InputPercentage, ChangeIdentificationType, ChangeOutputType,
        }
        [Flags]
        private enum LayoutOptions {
            AnchorBottom = 1 << 0, AnchorRight = 1 << 1, Vertical = 1 << 2,
        }
        private class LayoutProvider {
            public const string AnchorBottomLeft = "0 0";
            public const string AnchorBottomRight = "1 0";
            public const string AnchorTopLeft = "0 1";
            public const string AnchorTopRight = "1 1";
            public static LayoutProvider Once(float width = 0, float height = 0) => _reusable.WithOffset().WithDimensions(width, height).WithOptions(0).WithSpacing(0);
            private static LayoutProvider _reusable = new LayoutProvider(0, 0);
            private LayoutOptions _options;
            private string _anchor;
            private float _x, _y;
            private float _xSpacing, _ySpacing;
            private float _width, _height;
            private bool _isVertical => (_options & LayoutOptions.Vertical) != 0;
            private bool _isLeftToRight => (_options & LayoutOptions.AnchorRight) == 0;
            private bool _isTopToBottom => (_options & LayoutOptions.AnchorBottom) == 0;
            private int _xSign => _isLeftToRight ? 1 : -1;
            private int _ySign => _isTopToBottom ? -1 : 1;
            private float XMin, XMax, YMin, YMax;
            public string AnchorMin => _anchor;
            public string AnchorMax => _anchor;
            public string OffsetMin => $"{XMin.ToString()} {YMin.ToString()}";
            public string OffsetMax => $"{XMax.ToString()} {YMax.ToString()}";
            public LayoutProvider(float width, float height) {
                WithDimensions(width, height);
                WithOptions(0);
            }
            public LayoutProvider WithDimensions(float width, float height) {
                _width = width;
                _height = height;
                return this;
            }
            public LayoutProvider WithOptions(LayoutOptions options) {
                _options = options;
                _anchor = DetermineAnchor();
                return this;
            }
            public LayoutProvider WithSpacing(float x, float y = float.MaxValue) {
                _xSpacing = x;
                _ySpacing = y != float.MaxValue ? y : x;
                return this;
            }
            public LayoutProvider WithOffset(float x = 0, float y = 0) {
                _x = x * _xSign;
                _y = y * _ySign;
                return this;
            }
            public LayoutProvider Next() {
                XMin = _x + _xSpacing * _xSign;
                YMin = _y + _ySpacing * _ySign;
                XMax = XMin + _width * _xSign;
                YMax = YMin + _height * _ySign;
                if (_isVertical) {
                    _y = YMax;
                }
                else {
                    _x = XMax;
                }
                if (YMin > YMax) {
                    Swap(ref YMin, ref YMax);
                }
                if (XMin > XMax) {
                    Swap(ref XMin, ref XMax);
                }
                return this;
            }
            public CuiRectTransformComponent GetRectTransform() {
                return new CuiRectTransformComponent {
                    AnchorMin = _anchor, AnchorMax = _anchor, OffsetMin = OffsetMin, OffsetMax = OffsetMax,
                }
                ;
            }
            private string DetermineAnchor() {
                return _isTopToBottom ? _isLeftToRight ? AnchorTopLeft : AnchorTopRight : _isLeftToRight ? AnchorBottomLeft : AnchorBottomRight;
            }
        }
        private class ButtonColor {
            public readonly string Color;
            public readonly string TextColor;
            public ButtonColor(string color, string textColor) {
                Color = color;
                TextColor = textColor;
            }
        }
        private class ButtonColorScheme {
            public ButtonColor Active;
            public ButtonColor Enabled;
            public ButtonColor Disabled;
            public ButtonColor Get(bool active = false, bool enabled = false) {
                return active ? Active : enabled ? Enabled : Disabled;
            }
        }
        private class CuiInputFieldComponentHud : CuiInputFieldComponent {
            [JsonProperty("hudMenuInput", DefaultValueHandling = DefaultValueHandling.Ignore)]
            public bool HudMenuInput {
                get;
                set;
            }
        }
        private class CuiElementRecreate : CuiElement {
            [JsonProperty("destroyUi", DefaultValueHandling = DefaultValueHandling.Ignore)]
            public string DestroyUi {
                get;
                set;
            }
        }
        private static class EditUI {
            private const string UIName = "RecycleManager.UI";
            private const string EditPanelUIName = "RecycleManager.UI.EditPanel";
            private const string PercentagePanelUIName = "RecycleManager.UI.EditPanel.Percentages";
            private const string AnchorMin = "0.5 0";
            private const string AnchorMax = "0.5 0";
            private const float PanelWidth = 380.5f;
            private const float PanelHeight = 93f;
            private const float HeaderHeight = 21;
            private const int ItemPaddingLeft = 6;
            private const int ItemSize = 58;
            private const int ItemSpacing = 4;
            private const string BaseUICommand = "recyclemanager.ui";
            private const string TextColor = "0.8 0.8 0.8 1";
            private const string BackgroundColor = "0.25 0.25 0.25 1";
            private static ButtonColorScheme DefaultButtonColorScheme = new ButtonColorScheme {
                Active = new ButtonColor("0.25 0.5 0.75 1", "0.75 0.85 1 1"), Enabled = new ButtonColor("0.4 0.4 0.4 1", "0.71 0.71 0.71 1"), Disabled = new ButtonColor("0.4 0.4 0.4 0.5", "0.71 0.71 0.71 0.5"),
            }
            ;
            private static ButtonColorScheme SaveButtonColorScheme = new ButtonColorScheme {
                Enabled = new ButtonColor("0.451 0.553 0.271 1", "0.659 0.918 0.2 1"), Disabled = new ButtonColor("0.451 0.553 0.271 0.5", "0.659 0.918 0.2 0.5"),
            }
            ;
            private static ButtonColorScheme ResetButtonColorScheme = new ButtonColorScheme {
                Enabled = new ButtonColor("0.9 0.5 0.2 1", "1 0.9 0.7 1"), Disabled = new ButtonColor("0.9 0.5 0.2 0.25", "1 0.9 0.7 0.25"),
            }
            ;
            public static void DestroyUI(BasePlayer player) {
                CuiHelper.DestroyUi(player, UIName);
            }
            public static void DrawUI(RecycleManager plugin, BasePlayer player, EditState state) {
                if (state == null) {
                    DrawDefaultUI(plugin, player);
                }
                else {
                    DrawEditUI(plugin, player, state);
                }
            }
            private static void DrawDefaultUI(RecycleManager plugin, BasePlayer player) {
                var elements = CreateContainer();
                AddEditButton(elements, plugin, player);
                CuiHelper.AddUi(player, elements);
            }
            private static void DrawEditUI(RecycleManager plugin, BasePlayer player, EditState state) {
                var elements = CreateContainer();
                AddEditPanel(elements, plugin, player, state);
                CuiHelper.AddUi(player, elements);
            }
            private static CuiElementContainer CreateContainer() {
                var offsetY = 108f;
                var offsetX = 192f;
                return new CuiElementContainer {
                    {
                        new CuiElementRecreate {
                            Parent = "Hud.Menu", Name = UIName, DestroyUi = UIName, Components = {
                                new CuiRectTransformComponent {
                                    AnchorMin = AnchorMin, AnchorMax = AnchorMax, OffsetMin = $"{offsetX} {offsetY}", OffsetMax = $"{offsetX} {offsetY}",
                                }
                            }
                        }
                    }
                }
                ;
            }
            private static void AddEditButton(CuiElementContainer elements, RecycleManager plugin, BasePlayer player) {
                var buttonWidth = 80f;
                var offsetX = PanelWidth - buttonWidth;
                var offsetY = 266f;
                elements.Add(new CuiButton {
                    Text = {
                        Text = plugin.GetMessage(player.UserIDString, LangEntry.UIButtonAdmin), Color = SaveButtonColorScheme.Enabled.TextColor, Align = TextAnchor.MiddleCenter, FontSize = 15,
                    }
                    , Button = {
                        Color = SaveButtonColorScheme.Enabled.Color, Command = $"{BaseUICommand} {UICommand.Edit}", FadeIn = 0.1f,
                    }
                    , RectTransform = {
                        AnchorMin = "0 0", AnchorMax = "0 0", OffsetMin = $"{offsetX} {offsetY}", OffsetMax = $"{offsetX + buttonWidth} {offsetY + HeaderHeight}",
                    }
                    ,
                }
                , UIName);
            }
            private static void AddEditHeader(CuiElementContainer elements, RecycleManager plugin, BasePlayer player) {
                var offsetY = 266f;
                elements.Add(new CuiElement {
                    Parent = EditPanelUIName, Components = {
                        new CuiRawImageComponent {
                            Color = BackgroundColor, Sprite = "assets/content/ui/ui.background.tiletex.psd",
                        }
                        , new CuiRectTransformComponent {
                            AnchorMin = "0 0", AnchorMax = "0 0", OffsetMin = $"0 {offsetY}", OffsetMax = $"{PanelWidth} {offsetY + HeaderHeight}",
                        }
                        ,
                    }
                    ,
                }
                );
                elements.Add(new CuiElement {
                    Parent = EditPanelUIName, Components = {
                        new CuiTextComponent {
                            Text = plugin.GetMessage(player.UserIDString, LangEntry.UIHeader), Align = TextAnchor.MiddleLeft, FontSize = 14, Color = TextColor,
                        }
                        , new CuiRectTransformComponent {
                            AnchorMin = "0 0", AnchorMax = "0 0", OffsetMin = $"5 {offsetY}", OffsetMax = $"{5 + PanelWidth} {offsetY + HeaderHeight}",
                        }
                        ,
                    }
                }
                );
                var buttonWidth = 80f;
                var offsetX = PanelWidth - buttonWidth;
                elements.Add(new CuiButton {
                    Text = {
                        Text = plugin.GetMessage(player.UserIDString, LangEntry.UIButtonClose), Color = DefaultButtonColorScheme.Enabled.TextColor, Align = TextAnchor.MiddleCenter, FontSize = 15,
                    }
                    , Button = {
                        Color = DefaultButtonColorScheme.Enabled.Color, Command = $"{BaseUICommand} {UICommand.Cancel}",
                    }
                    , RectTransform = {
                        AnchorMin = "0 0", AnchorMax = "0 0", OffsetMin = $"{offsetX} {offsetY}", OffsetMax = $"{offsetX + buttonWidth} {offsetY + HeaderHeight}",
                    }
                    ,
                }
                , UIName);
            }
            private static void AddEditPanel(CuiElementContainer elements, RecycleManager plugin, BasePlayer player, EditState state) {
                elements.Add(new CuiElement {
                    Parent = UIName, Name = EditPanelUIName, Components = {
                        new CuiRawImageComponent {
                            Color = BackgroundColor, Sprite = "assets/content/ui/ui.background.tiletex.psd",
                        }
                        , new CuiRectTransformComponent {
                            AnchorMin = AnchorMin, AnchorMax = AnchorMax, OffsetMin = "0 0", OffsetMax = $"{PanelWidth} {PanelHeight}",
                        }
                        ,
                    }
                    ,
                }
                );
                AddEditHeader(elements, plugin, player);
                if (state.BlockedByAnotherPlugin) {
                    elements.Add(new CuiElement {
                        Parent = EditPanelUIName, Components = {
                            new CuiTextComponent {
                                Text = plugin.GetMessage(player.UserIDString, LangEntry.UIItemBlocked), Align = TextAnchor.MiddleCenter, FontSize = 12, Color = TextColor,
                            }
                            , new CuiRectTransformComponent {
                                AnchorMin = "0 0", AnchorMax = "1 1",
                            }
                            ,
                        }
                    }
                    );
                    return;
                }
                AddPercentageControllers(elements, state);
                if (state.InputItem == null) {
                    elements.Add(new CuiElement {
                        Parent = EditPanelUIName, Components = {
                            new CuiTextComponent {
                                Text = plugin.GetMessage(player.UserIDString, LangEntry.UIEmptyState), Align = TextAnchor.MiddleCenter, FontSize = 12, Color = TextColor,
                            }
                            , new CuiRectTransformComponent {
                                AnchorMin = "0 0", AnchorMax = "1 1",
                            }
                            ,
                        }
                    }
                    );
                    return;
                }
                AddItemIdentificationControls(elements, plugin, player, state);
                AddItemAllowedControls(elements, plugin, player, state);
                AddPrimaryControls(elements, plugin, player, state);
            }
            private static void AddPercentageControllers(CuiElementContainer elements, EditState state) {
                var offsetY = 169;
                elements.Add(new CuiElement {
                    Name = PercentagePanelUIName, Parent = EditPanelUIName, Components = {
                        new CuiRawImageComponent {
                            Color = BackgroundColor, Sprite = "assets/content/ui/ui.background.tiletex.psd",
                        }
                        , new CuiRectTransformComponent {
                            AnchorMin = "0 0", AnchorMax = "0 0", OffsetMin = $"0 {offsetY}", OffsetMax = $"{PanelWidth} {offsetY + HeaderHeight}",
                        }
                        ,
                    }
                    ,
                }
                );
                if (state.InputItem == null) return;
                for (var i = 0; i < 6; i++) {
                    if (state.Chances[i] <= 0) continue;
                    var offsetX = ItemPaddingLeft + i * (ItemSize + ItemSpacing);
                    elements.Add(new CuiElement {
                        Parent = PercentagePanelUIName, Components = {
                            new CuiInputFieldComponentHud {
                                Align = TextAnchor.MiddleCenter, HudMenuInput = true, Text = $"{state.Chances[i]:0.##}%", Color = TextColor, CharsLimit = 6, Command = $"{BaseUICommand} {UICommand.InputPercentage} {i}",
                            }
                            , new CuiRectTransformComponent {
                                AnchorMin = "0 0", AnchorMax = "0 0", OffsetMin = $"{offsetX} 0", OffsetMax = $"{offsetX + ItemSize} {HeaderHeight}",
                            }
                            ,
                        }
                        ,
                    }
                    );
                }
            }
            private static void AddButton(CuiElementContainer elements, LayoutProvider layoutProvider, ButtonColorScheme buttonColorScheme, string parent, string text, string command, bool active = false, bool enabled = true) {
                var buttonColor = buttonColorScheme.Get(active, enabled);
                elements.Add(new CuiButton {
                    Text = {
                        Text = text, Color = buttonColor.TextColor, Align = TextAnchor.MiddleCenter, FontSize = 12,
                    }
                    , Button = {
                        Color = buttonColor.Color, Command = enabled && !active ? command : null,
                    }
                    , RectTransform = {
                        AnchorMin = layoutProvider.AnchorMin, AnchorMax = layoutProvider.AnchorMax, OffsetMin = layoutProvider.OffsetMin, OffsetMax = layoutProvider.OffsetMax,
                    }
                }
                , parent);
            }
            private static void AddItemIdentificationControls(CuiElementContainer elements, RecycleManager plugin, BasePlayer player, EditState state) {
                var spacingX = 5;
                var spacingY = 2;
                var paddingY = 5;
                var numElements = 4;
                var columnWidth = PanelWidth / 3f;
                var elementHeight = (PanelHeight - 2 * paddingY - (numElements - 1) * spacingY) / numElements;
                var layoutProvider = LayoutProvider.Once(columnWidth - 2 * spacingX, elementHeight).WithOffset(0, paddingY - spacingY).WithSpacing(spacingX, spacingY).WithOptions(LayoutOptions.Vertical);
                elements.Add(new CuiElement {
                    Parent = EditPanelUIName, Components = {
                        new CuiTextComponent {
                            Text = plugin.GetMessage(player.UserIDString, LangEntry.UILabelConfigureBy), Align = TextAnchor.MiddleCenter, FontSize = 12, Color = TextColor,
                        }
                        , layoutProvider.Next().GetRectTransform(),
                    }
                }
                );
                AddButton(elements, layoutProvider.Next(), DefaultButtonColorScheme, EditPanelUIName, plugin.GetMessage(player.UserIDString, LangEntry.UIButtonItem), $"{BaseUICommand} {UICommand.ChangeIdentificationType} {IdentificationType.Item}", state.IdentificationType == IdentificationType.Item, state.InputItem.skin != 0);
                AddButton(elements, layoutProvider.Next(), DefaultButtonColorScheme, EditPanelUIName, plugin.GetMessage(player.UserIDString, LangEntry.UIButtonSkin), $"{BaseUICommand} {UICommand.ChangeIdentificationType} {IdentificationType.Skin}", state.IdentificationType == IdentificationType.Skin, state.InputItem.skin != 0);
                AddButton(elements, layoutProvider.Next(), DefaultButtonColorScheme, EditPanelUIName, plugin.GetMessage(player.UserIDString, LangEntry.UIButtonDisplayName), $"{BaseUICommand} {UICommand.ChangeIdentificationType} {IdentificationType.DisplayName}", state.IdentificationType == IdentificationType.DisplayName, !string.IsNullOrWhiteSpace(state.InputItem.name));
            }
            private static void AddItemAllowedControls(CuiElementContainer elements, RecycleManager plugin, BasePlayer player, EditState state) {
                var spacingX = 5;
                var spacingY = 2;
                var paddingY = 5;
                var numElements = 4;
                var columnWidth = PanelWidth / 3f;
                var elementHeight = (PanelHeight - 2 * paddingY - (numElements - 1) * spacingY) / numElements;
                var layoutProvider = LayoutProvider.Once(columnWidth - 2 * spacingX, elementHeight).WithOffset(columnWidth, paddingY - spacingY).WithSpacing(spacingX, spacingY).WithOptions(LayoutOptions.Vertical);
                elements.Add(new CuiElement {
                    Parent = EditPanelUIName, Components = {
                        new CuiTextComponent {
                            Text = plugin.GetMessage(player.UserIDString, LangEntry.UILabelOutput), Align = TextAnchor.MiddleCenter, FontSize = 12, Color = TextColor,
                        }
                        , layoutProvider.Next().GetRectTransform(),
                    }
                }
                );
                AddButton(elements, layoutProvider.Next(), DefaultButtonColorScheme, EditPanelUIName, plugin.GetMessage(player.UserIDString, LangEntry.UIButtonNotRecyclable), $"{BaseUICommand} {UICommand.ChangeOutputType} {OutputType.NotRecyclable}", state.OutputType == OutputType.NotRecyclable);
                AddButton(elements, layoutProvider.Next(), DefaultButtonColorScheme, EditPanelUIName, plugin.GetMessage(player.UserIDString, LangEntry.UIButtonDefaultOutput), $"{BaseUICommand} {UICommand.ChangeOutputType} {OutputType.Default}", state.OutputType == OutputType.Default, state.IdentificationType != IdentificationType.Item || IsVanillaRecyclable(state.InputItem));
                AddButton(elements, layoutProvider.Next(), DefaultButtonColorScheme, EditPanelUIName, plugin.GetMessage(player.UserIDString, LangEntry.UIButtonCustomOutput), $"{BaseUICommand} {UICommand.ChangeOutputType} {OutputType.Custom}", state.OutputType == OutputType.Custom);
            }
            private static void AddPrimaryControls(CuiElementContainer elements, RecycleManager plugin, BasePlayer player, EditState state) {
                var spacingX = 5;
                var spacingY = 2;
                var paddingY = 5;
                var numElements = 4;
                var columnWidth = PanelWidth / 3f;
                var elementHeight = (PanelHeight - 2 * paddingY - (numElements - 1) * spacingY) / numElements;
                var layoutProvider = LayoutProvider.Once(columnWidth - 2 * spacingX, elementHeight).WithOffset(2 * columnWidth, paddingY - spacingY).WithSpacing(spacingX, spacingY).WithOptions(LayoutOptions.Vertical);
                elements.Add(new CuiElement {
                    Parent = EditPanelUIName, Components = {
                        new CuiTextComponent {
                            Text = plugin.GetMessage(player.UserIDString, LangEntry.UILabelActions), Align = TextAnchor.MiddleCenter, FontSize = 12, Color = TextColor,
                        }
                        , layoutProvider.Next().GetRectTransform(),
                    }
                }
                );
                AddButton(elements, layoutProvider.Next(), SaveButtonColorScheme, EditPanelUIName, plugin.GetMessage(player.UserIDString, LangEntry.UIButtonSave), $"{BaseUICommand} {UICommand.Save}", enabled : state.CanSave);
                AddButton(elements, layoutProvider.Next(), ResetButtonColorScheme, EditPanelUIName, plugin.GetMessage(player.UserIDString, LangEntry.UIButtonReset), $"{BaseUICommand} {UICommand.Reset}", enabled : state.CanReset);
                AddButton(elements, layoutProvider.Next(), DefaultButtonColorScheme, EditPanelUIName, plugin.GetMessage(player.UserIDString, LangEntry.UIButtonCancel), $"{BaseUICommand} {UICommand.Cancel}");
            }
        }
#endregion
#region Edit Controller
        private class EditState {
            public Item InputItem;
            public IdentificationType IdentificationType;
            public OutputType OutputType;
            public float[] Chances = new float[NumOutputSlots];
            public bool BlockedByAnotherPlugin;
            public bool CanSave;
            public bool CanReset;
        }
        private class EditController : FacepunchBehaviour {
            public static EditController AddToRecycler(RecycleManager plugin, RecycleEditManager recycleEditManager, Recycler recycler) {
                var component = recycler.gameObject.AddComponent<EditController>();
                component._plugin = plugin;
                component._recycleEditManager = recycleEditManager;
                component._recycler = recycler;
                return component;
            }
            private RecycleManager _plugin;
            private RecycleEditManager _recycleEditManager;
            private Recycler _recycler;
            private BasePlayer _player;
            private EditState _editState;
            private Func<Item, int, bool> _originalCanAcceptItem;
            private Action _onDirtyDelayed;
            private bool _pauseAutoChangeOutput;
            private Configuration _config => _plugin._config;
            private EditController() {
                _onDirtyDelayed = OnDirtyDelayed;
            }
            public void StartViewing(BasePlayer player) {
                _player = player;
                DrawUI();
            }
            public void DestroyImmediate() {
                DestroyImmediate(this);
            }
            private IngredientInfo[] GetSavedIngredients() {
                return GetOutput(_editState.IdentificationType, _editState.OutputType);
            }
            private bool CanSave() {
                if (_editState.InputItem == null) return false;
                switch (_editState.OutputType) {
                    case OutputType.NotRecyclable : {
                        if (IsDisallowed()) return false;
                        if (GetOverride() != null) return true;
                        return _editState.IdentificationType == IdentificationType.Item && IsVanillaRecyclable(_editState.InputItem);
                    }
                    case OutputType.Default : {
                        if (IsDisallowed()) return true;
                        if (GetOverride() != null) return true;
                        return false;
                    }
                    case OutputType.Custom : return GetOverride() == null || !GetOutputIngredients().SequenceEqual(GetSavedIngredients());
                    default : return true;
                }
            }
            private bool CanReset() {
                if (_editState.InputItem == null) return false;
                return IsDisallowed() || GetOverride() != null;
            }
            private void DrawUI() {
                if (_editState != null) {
                    _editState.CanSave = CanSave();
                    _editState.CanReset = CanReset();
                }
                EditUI.DrawUI(_plugin, _player, _editState);
            }
            private List<IngredientInfo> GetOutputIngredients() {
                var customIngredientList = new List<IngredientInfo>();
                for (var i = NumInputSlots; i < Num
// ... [Code preview truncated due to length. Full source in attached file] ...

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

Другие ресурсы пользователя 15FPS

Сверху