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

FREE FurnaceSplitterEx : 2.2.0 2.2.0

Нет прав для скачивания
C#:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("Furnace Splitter Ex", "Menevt", "2.2.0")]
    [Description("Splits up resources in furnaces automatically")]
    public class FurnaceSplitterEx : RustPlugin
    {
        private class OvenSlot
        {
            /// <summary>The item in this slot.May be null.</summary>
            public Item Item;

            /// <summary>The slot position</summary>
            public int? Position;

            /// <summary>The slot's index in the itemList list.</summary>
            public int Index;

            /// <summary>How much should be added/removed from stack</summary>
            public int DeltaAmount;
        }

        public class OvenInfo
        {
            public float ETA;
            public float FuelNeeded;
        }

        public enum MoveResult
        {
            Ok,
            SlotsFilled,
            NotEnoughSlots
        }

        private const string permUse = "furnacesplitterex.use";
        private readonly string[] compatibleOvens =
        {
            "bbq.deployed",
            "campfire",
            "fireplace.deployed",
            "furnace",
            "furnace.large",
            "hobobarrel_static",
            "refinery_small_deployed",
            "skull_fire_pit"
        };

        private Dictionary<string, int> initialStackOptions = new Dictionary<string, int>()
            {
                {"furnace", 3},
                {"bbq.deployed", 9},
                {"campfire", 2},
                {"fireplace.deployed", 2},
                {"furnace.large", 15},
                {"hobobarrel_static", 2},
                {"refinery_small_deployed", 3},
                {"skull_fire_pit", 2}
            };

        private void Loaded()
        {
            permission.RegisterPermission(permUse, this);
        }

        private bool IsSlotCompatible(Item item, BaseOven oven, ItemDefinition itemDefinition)
        {
            ItemModCookable cookable = item.info.GetComponent<ItemModCookable>();

            if (item.amount < item.info.stackable && item.info == itemDefinition)
                return true;

            if (oven.allowByproductCreation && oven.fuelType.GetComponent<ItemModBurnable>().byproductItem == item.info)
                return true;

            if (cookable == null || cookable.becomeOnCooked == itemDefinition)
                return true;

            if (CanCook(cookable, oven))
                return true;

            return false;
        }

        private object CanMoveItem(Item item, PlayerInventory inventory, uint targetContainer, int targetSlot)
        {
            BasePlayer player = inventory.GetComponent<BasePlayer>();
            if (player == null)
                return null;

            ItemContainer container = inventory.FindContainer(targetContainer);
            ItemContainer originalContainer = item.GetRootContainer();

            Func<object> splitFunc = () =>
            {
                if (player == null || !HasPermission(player))
                    return null;


                if (container == null || container == item.GetRootContainer())
                    return null;

                BaseOven oven = container.entityOwner as BaseOven;
                ItemModCookable cookable = item.info.GetComponent<ItemModCookable>();

                if (oven == null || cookable == null)
                    return null;

                int totalSlots = 2 + (oven.allowByproductCreation ? 1 : 0);

                if (initialStackOptions.ContainsKey(oven.ShortPrefabName))
                {
                    totalSlots = initialStackOptions[oven.ShortPrefabName];
                }

                if (cookable.lowTemp > oven.cookingTemperature || cookable.highTemp < oven.cookingTemperature)
                    return null;

                MoveSplitItem(item, oven, totalSlots);
                return true;
            };

            object returnValue = splitFunc();

            if (HasPermission(player))
            {
                BaseOven oven = container?.entityOwner as BaseOven ?? item.GetRootContainer().entityOwner as BaseOven;

                if (oven != null && compatibleOvens.Contains(oven.ShortPrefabName))
                {
                    if (returnValue is bool && (bool)returnValue)
                        AutoAddFuel(inventory, oven);
                }
            }

            return returnValue;
        }

        private MoveResult MoveSplitItem(Item item, BaseOven oven, int totalSlots)
        {
            ItemContainer container = oven.inventory;
            int invalidItemsCount = container.itemList.Count(slotItem => !IsSlotCompatible(slotItem, oven, item.info));
            int numOreSlots = Math.Min(container.capacity - invalidItemsCount, totalSlots);
            int totalMoved = 0;
            int totalAmount = Math.Min(item.amount + container.itemList.Where(slotItem => slotItem.info == item.info).Take(numOreSlots).Sum(slotItem => slotItem.amount), item.info.stackable * numOreSlots);

            if (numOreSlots <= 0)
            {
                return MoveResult.NotEnoughSlots;
            }

            //Puts("---------------------------");

            int totalStackSize = Math.Min(totalAmount / numOreSlots, item.info.stackable);
            int remaining = totalAmount - totalAmount / numOreSlots * numOreSlots;

            List<int> addedSlots = new List<int>();

            //Puts("total: {0}, remaining: {1}, totalStackSize: {2}", totalAmount, remaining, totalStackSize);

            List<OvenSlot> ovenSlots = new List<OvenSlot>();

            for (int i = 0; i < numOreSlots; ++i)
            {
                Item existingItem;
                int slot = FindMatchingSlotIndex(container, out existingItem, item.info, addedSlots);

                if (slot == -1) // full
                {
                    return MoveResult.NotEnoughSlots;
                }

                addedSlots.Add(slot);

                OvenSlot ovenSlot = new OvenSlot
                {
                    Position = existingItem?.position,
                    Index = slot,
                    Item = existingItem
                };

                int currentAmount = existingItem?.amount ?? 0;
                int missingAmount = totalStackSize - currentAmount + (i < remaining ? 1 : 0);
                ovenSlot.DeltaAmount = missingAmount;

                //Puts("[{0}] current: {1}, delta: {2}, total: {3}", slot, currentAmount, ovenSlot.DeltaAmount, currentAmount + missingAmount);

                if (currentAmount + missingAmount <= 0)
                    continue;

                ovenSlots.Add(ovenSlot);
            }

            foreach (OvenSlot slot in ovenSlots)
            {
                if (slot.Item == null)
                {
                    Item newItem = ItemManager.Create(item.info, slot.DeltaAmount, item.skin);
                    slot.Item = newItem;
                    newItem.MoveToContainer(container, slot.Position ?? slot.Index);
                }
                else
                {
                    slot.Item.amount += slot.DeltaAmount;
                }

                totalMoved += slot.DeltaAmount;
            }

            container.MarkDirty();

            if (totalMoved >= item.amount)
            {
                item.Remove();
                item.GetRootContainer()?.MarkDirty();
                return MoveResult.Ok;
            }
            else
            {
                item.amount -= totalMoved;
                item.GetRootContainer()?.MarkDirty();
                return MoveResult.SlotsFilled;
            }
        }

        private void AutoAddFuel(PlayerInventory playerInventory, BaseOven oven)
        {
            int neededFuel = (int)Math.Ceiling(GetOvenInfo(oven).FuelNeeded);
            neededFuel -= oven.inventory.GetAmount(oven.fuelType.itemid, false);
            var playerFuel = playerInventory.FindItemIDs(oven.fuelType.itemid);

            if (neededFuel <= 0 || playerFuel.Count <= 0)
                return;

            foreach (Item fuelItem in playerFuel)
            {
                if (oven.inventory.CanAcceptItem(fuelItem, -1) != ItemContainer.CanAcceptResult.CanAccept)
                    break;

                Item largestFuelStack = oven.inventory.itemList.Where(item => item.info == oven.fuelType).OrderByDescending(item => item.amount).FirstOrDefault();
                int toTake = Math.Min(neededFuel, oven.fuelType.stackable - (largestFuelStack?.amount ?? 0));

                if (toTake > fuelItem.amount)
                    toTake = fuelItem.amount;

                if (toTake <= 0)
                    break;

                neededFuel -= toTake;

                if (toTake >= fuelItem.amount)
                {
                    fuelItem.MoveToContainer(oven.inventory);
                }
                else
                {
                    Item splitItem = fuelItem.SplitItem(toTake);
                    if (!splitItem.MoveToContainer(oven.inventory)) // Break if oven is full
                        break;
                }

                if (neededFuel <= 0)
                    break;
            }
        }

        private int FindMatchingSlotIndex(ItemContainer container, out Item existingItem, ItemDefinition itemType, List<int> indexBlacklist)
        {
            existingItem = null;
            int firstIndex = -1;
            Dictionary<int, Item> existingItems = new Dictionary<int, Item>();

            for (int i = 0; i < container.capacity; ++i)
            {
                if (indexBlacklist.Contains(i))
                    continue;

                Item itemSlot = container.GetSlot(i);
                if (itemSlot == null || itemType != null && itemSlot.info == itemType)
                {
                    if (itemSlot != null)
                        existingItems.Add(i, itemSlot);

                    if (firstIndex == -1)
                    {
                        existingItem = itemSlot;
                        firstIndex = i;
                    }
                }
            }

            if (existingItems.Count <= 0 && firstIndex != -1)
            {
                return firstIndex;
            }
            else if (existingItems.Count > 0)
            {
                var largestStackItem = existingItems.OrderByDescending(kv => kv.Value.amount).First();
                existingItem = largestStackItem.Value;
                return largestStackItem.Key;
            }

            existingItem = null;
            return -1;
        }

        public OvenInfo GetOvenInfo(BaseOven oven)
        {
            OvenInfo result = new OvenInfo();
            var smeltTimes = GetSmeltTimes(oven);

            if (smeltTimes.Count > 0)
            {
                var longestStack = smeltTimes.OrderByDescending(kv => kv.Value).First();
                float fuelUnits = oven.fuelType.GetComponent<ItemModBurnable>().fuelAmount;
                float neededFuel = (float)Math.Ceiling(longestStack.Value * (oven.cookingTemperature / 200.0f) / fuelUnits);

                result.FuelNeeded = neededFuel;
                result.ETA = longestStack.Value;
            }

            return result;
        }

        private Dictionary<ItemDefinition, float> GetSmeltTimes(BaseOven oven)
        {
            ItemContainer container = oven.inventory;
            var cookables = container.itemList.Where(item =>
            {
                ItemModCookable cookable = item.info.GetComponent<ItemModCookable>();
                return cookable != null && CanCook(cookable, oven);
            }).ToList();

            if (cookables.Count == 0)
                return new Dictionary<ItemDefinition, float>();

            var distinctCookables = cookables.GroupBy(item => item.info, item => item).ToList();
            Dictionary<ItemDefinition, int> amounts = new Dictionary<ItemDefinition, int>();

            foreach (var group in distinctCookables)
            {
                int biggestAmount = group.Max(item => item.amount);
                amounts.Add(group.Key, biggestAmount);
            }

            var smeltTimes = amounts.ToDictionary(kv => kv.Key, kv => GetSmeltTime(kv.Key.GetComponent<ItemModCookable>(), kv.Value));
            return smeltTimes;
        }

        private float GetSmeltTime(ItemModCookable cookable, int amount)
        {
            float smeltTime = cookable.cookTime * amount;
            return smeltTime;
        }

        private bool CanCook(ItemModCookable cookable, BaseOven oven)
        {
            return oven.cookingTemperature >= cookable.lowTemp && oven.cookingTemperature <= cookable.highTemp;
        }

        private bool HasPermission(BasePlayer player)
        {
            return permission.UserHasPermission(player.UserIDString, permUse);
        }

        #region Exposed plugin methods

        [HookMethod("MoveSplitItem")]
        public string Hook_MoveSplitItem(Item item, BaseOven oven, int totalSlots)
        {
            MoveResult result = MoveSplitItem(item, oven, totalSlots);
            return result.ToString();
        }

        [HookMethod("GetOvenInfo")]
        public JObject Hook_GetOvenInfo(BaseOven oven)
        {
            OvenInfo ovenInfo = GetOvenInfo(oven);
            return JObject.FromObject(ovenInfo);
        }

        #endregion Exposed plugin methods
    }
}

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

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

Сверху