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

FREE CompostSplitter : 1.7.3 1.7.3

Нет прав для скачивания
C#:
using System;
using System.Collections.Generic;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("CompostSplitter", "xADROCx", "1.7.3")]
    [Description("Safely splits inserted compostables across free slots without deleting existing inventory.")]
    public class CompostSplitter : RustPlugin
    {
        private const string PermUse = "compostsplitter.use";
        private readonly HashSet<ItemContainer> busy = new HashSet<ItemContainer>();
        private readonly Dictionary<ItemContainer, Dictionary<int, long>> observed = new Dictionary<ItemContainer, Dictionary<int, long>>();
        private bool unloading;

        private void Init()
        {
            permission.RegisterPermission(PermUse, this);
            timer.Every(0.25f, CheckDeposits);
        }
        private void Unload() { unloading = true; observed.Clear(); busy.Clear(); }

        private static bool IsComposter(StorageContainer comp)
        {
            return comp != null && !comp.IsDestroyed && comp.ShortPrefabName != null &&
                comp.ShortPrefabName.Contains("composter");
        }
        private static bool IsCompostable(Item item)
        {
            if (item == null || item.info == null) return false;
            string name = item.info.shortname;
            return name == "horsedung" || name == "plantfiber" || name == "food.scraps" ||
                name == "horsepoo" || item.info.GetComponent<ItemModCompostable>() != null;
        }
        private bool HasAuthorizedLooter(StorageContainer comp)
        {
            // Read actual loot state so closing one of several viewers cannot disable another.
            foreach (BasePlayer player in BasePlayer.activePlayerList)
                if (player != null && player.IsConnected && player.inventory != null &&
                    player.inventory.loot != null && player.inventory.loot.entitySource == comp &&
                    permission.UserHasPermission(player.UserIDString, PermUse)) return true;
            return false;
        }
        private object CanAcceptItem(ItemContainer container, Item item, int targetPos)
        {
            StorageContainer comp = container == null ? null : container.entityOwner as StorageContainer;
            if (!IsComposter(comp) || !IsCompostable(item) || busy.Contains(container) ||
                item.parent == container || !HasAuthorizedLooter(comp)) return null;
            for (int i = 0; i < container.capacity; i++)
                if (container.GetSlot(i) == null) return null;
            // Current Oxide expects this enum, not a bool.
            return ItemContainer.CanAcceptResult.CannotAccept;
        }
        private static Dictionary<int, long> Totals(ItemContainer container)
        {
            var result = new Dictionary<int, long>();
            foreach (Item item in container.itemList)
            {
                if (!IsCompostable(item)) continue;
                long amount;
                result.TryGetValue(item.info.itemid, out amount);
                result[item.info.itemid] = amount + item.amount;
            }
            return result;
        }
        private void OnLootEntity(BasePlayer player, BaseEntity entity)
        {
            var comp = entity as StorageContainer;
            if (!IsComposter(comp) || comp.inventory == null || player == null ||
                !permission.UserHasPermission(player.UserIDString, PermUse)) return;
            if (!observed.ContainsKey(comp.inventory)) observed[comp.inventory] = Totals(comp.inventory);
        }
        private void CheckDeposits()
        {
            if (unloading) return;
            var active = new HashSet<ItemContainer>();
            foreach (BasePlayer player in BasePlayer.activePlayerList)
            {
                var comp = player?.inventory?.loot?.entitySource as StorageContainer;
                if (!IsComposter(comp) || comp.inventory == null ||
                    !permission.UserHasPermission(player.UserIDString, PermUse) || !active.Add(comp.inventory)) continue;
                ItemContainer container = comp.inventory;
                Dictionary<int, long> current = Totals(container);
                Dictionary<int, long> previous;
                if (!observed.TryGetValue(container, out previous))
                {
                    // Opening/reloading is not a deposit. Establish a baseline without rearranging.
                    observed[container] = current;
                    continue;
                }
                if (!busy.Add(container)) continue;
                try
                {
                    foreach (var entry in current)
                    {
                        long oldAmount;
                        previous.TryGetValue(entry.Key, out oldAmount);
                        if (entry.Value <= oldAmount) continue;
                        var handled = new List<Item>();
                        foreach (Item item in new List<Item>(container.itemList))
                        {
                            if (item.info.itemid != entry.Key) continue;
                            bool duplicate = false;
                            foreach (Item other in handled)
                                if (other == item || other.CanStack(item)) { duplicate = true; break; }
                            if (duplicate) continue;
                            SplitInsertedStack(container, item, comp);
                            handled.Add(item);
                        }
                    }
                }
                catch (Exception ex) { PrintError("Compost split stopped: " + ex.Message); }
                finally
                {
                    busy.Remove(container);
                    if (!comp.IsDestroyed) observed[container] = Totals(container);
                }
            }
            foreach (ItemContainer container in new List<ItemContainer>(observed.Keys))
                if (!active.Contains(container)) observed.Remove(container);
        }
        private void SplitInsertedStack(ItemContainer container, Item source, StorageContainer comp)
        {
            if (source.info.stackable <= 1) return;
            var stacks = new List<Item>();
            var slots = new List<int>();
            long total = 0;
            // Occupied compatible slots come first, so each original stack keeps at least one.
            for (int i = 0; i < container.capacity; i++)
            {
                Item current = container.GetSlot(i);
                if (current != null && (current == source || source.CanStack(current)))
                {
                    stacks.Add(current);
                    slots.Add(i);
                    total += current.amount;
                }
            }
            for (int i = 0; i < container.capacity; i++)
            {
                // Respect the composter's input/output slot rules.
                if (container.GetSlot(i) == null &&
                    container.CanAcceptItem(null, source, i) == ItemContainer.CanAcceptResult.CanAccept)
                {
                    stacks.Add(null);
                    slots.Add(i);
                }
            }
            int count = (int)Math.Min(total, slots.Count);
            if (count <= 1) return;
            int each = (int)(total / count);
            int extra = (int)(total % count);
            var targets = new int[count];
            for (int i = 0; i < count; i++) targets[i] = each + (i < extra ? 1 : 0);
            for (int receiver = 0; receiver < count; receiver++)
            {
                for (int donor = 0; donor < count; donor++)
                {
                    Item to = stacks[receiver];
                    int need = targets[receiver] - (to == null ? 0 : to.amount);
                    if (need <= 0) break;
                    Item from = stacks[donor];
                    if (from == null || from.parent != container) continue;
                    int surplus = from.amount - targets[donor];
                    int amount = Math.Min(need, surplus);
                    if (amount <= 0) continue;
                    if (to != null)
                    {
                        if (to.parent != container || !from.CanStack(to)) return;
                        // No item destruction or recreation: transfer quantities between compatible stacks.
                        from.amount -= amount;
                        to.amount += amount;
                        from.MarkDirty();
                        to.MarkDirty();
                        continue;
                    }
                    if (container.GetSlot(slots[receiver]) != null) return;
                    Item part = from.SplitItem(amount);
                    if (part == null) return;
                    bool moved = false;
                    try { moved = part.MoveToContainer(container, slots[receiver], false); }
                    finally
                    {
                        if (!moved && part.parent == null && part.amount > 0)
                        {
                            if (from.parent == container && !comp.IsDestroyed)
                            {
                                from.amount += part.amount;
                                from.MarkDirty();
                                part.Remove();
                            }
                            else part.Drop(comp.transform.position + Vector3.up, Vector3.zero);
                        }
                    }
                    if (!moved) return;
                    stacks[receiver] = part;
                }
            }
            container.MarkDirty();
        }
        // Rust saves the real inventory. Legacy snapshots are deliberately never replayed:
        // recreating inventory from them can lose items, erase metadata, or resurrect consumed resources.
    }
}

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