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

FREE CompostHelper : 1.0.207 1.0.207

Нет прав для скачивания
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using Oxide.Plugins;
using Newtonsoft.Json;
using UnityEngine;
using Oxide.Game.Rust.Cui;
using Oxide.Core;
using Oxide.Core.Libraries;
namespace Oxide.Plugins
{
    // --- Main.cs ---
    [Info("CompostHelper", "HiroOfCanton", "1.0.207")]
    [Description("Smart fertilizer distribution system for Rust composters")]
    public class CompostHelper : RustPlugin
    {
        private ComposterManager _composterManager;
        private UIManager _uiManager;
        #region Localization
        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                [Consts.LANG_NO_PERMISSION] = "You don't have permission to use this command.",
                [Consts.LANG_INVALID_COMMAND] = "Invalid spread command",
                [Consts.LANG_INVALID_COMPOSTER] = "Invalid composter ID",
                [Consts.LANG_COMPOSTER_NOT_FOUND] = "Composter not found or has been destroyed",
                [Consts.LANG_TOO_FAR_AWAY] = "You must be closer to the composter to use the Spread button",
                [Consts.LANG_DISTRIBUTE_SUCCESS] = "Distributed {0}/{1} fertilizer to {2} planters",
                [Consts.LANG_DISTRIBUTE_FAILED] = "Found {0} fertilizer but couldn't distribute - {1}",
                [Consts.LANG_FERTILIZER_REMAINING] = "{0} fertilizer stored back in composter",
                [Consts.LANG_NO_FERTILIZER] = "{0}",
                [Consts.LANG_PROCESS_FAILED] = "Failed to process composter"
            }, this);
        }
        public string GetMessage(string key, BasePlayer player, params object[] args)
        {
            var message = lang.GetMessage(key, this, player?.UserIDString);
            return args.Length > 0 ? string.Format(message, args) : message;
        }
        #endregion
        #region Configuration
        protected override void LoadDefaultConfig()
        {
            PluginConfig.Instance = new PluginConfig();
            Puts("Created default configuration");
        }
        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                PluginConfig.Instance = Config.ReadObject<PluginConfig>();
                if (PluginConfig.Instance == null)
                {
                    LoadDefaultConfig();
                }
                else if (PluginConfig.Instance.ValidateAndCorrect())
                {
                    SaveConfig();
                }
            }
            catch
            {
                LoadDefaultConfig();
            }
        }
        protected override void SaveConfig()
        {
            Config.WriteObject(PluginConfig.Instance);
        }
        #endregion
        #region Plugin Lifecycle
        private void Init()
        {
            permission.RegisterPermission(Consts.PERMISSION_USE, this);
            _composterManager = new ComposterManager(new FertilizerDistributor());
            _uiManager = new UIManager(this, _composterManager);
            StartupDiagnostics.Run(permission);
        }
        private void Unload()
        {
            _uiManager.Cleanup();
        }
        #endregion
        #region Oxide Hooks
        private void OnLootEntity(BasePlayer player, BaseEntity entity)
        {
            if (player == null || entity == null) return;
            _uiManager.OnLootEntityOpened(player, entity);
        }
        private void OnLootEntityEnd(BasePlayer player, BaseCombatEntity entity)
        {
            if (player == null || entity == null) return;
            _uiManager.OnLootEntityClosed(player, entity);
        }
        private void OnPlayerDisconnected(BasePlayer player, string reason)
        {
            if (player == null) return;
            _uiManager.OnPlayerDisconnected(player);
        }
        #endregion
        #region Console Commands
        [ConsoleCommand(Consts.CMD_SPREAD)]
        private void SpreadCommand(ConsoleSystem.Arg arg)
        {
            var player = arg.Player();
            if (player == null) return;
            if (!permission.UserHasPermission(player.UserIDString, Consts.PERMISSION_USE))
            {
                SendReply(player, GetMessage(Consts.LANG_NO_PERMISSION, player));
                return;
            }
            _uiManager.HandleSpreadCommand(player, arg.Args != null ? arg.Args.Select(a => a.ToString()).ToArray() : Array.Empty<string>());
        }
        #endregion
        public bool HasPermission(BasePlayer player, string perm)
        {
            return player != null && permission.UserHasPermission(player.UserIDString, perm);
        }
    }
    // --- Configuration/PluginConfig.cs ---
    public class PluginConfig
    {
        public static PluginConfig Instance { get; set; } = new PluginConfig();
        [JsonProperty("Maximum Distribution Range")]
        public float MaxDistributionRange { get; set; } = 50.0f;
        [JsonProperty("Supported Planter Types")]
        public string[] SupportedPlanterTypes { get; set; } = new string[]
        {
            "planter.large.deployed",
            "planter.small.deployed",
            "planter.triangle.deployed",
            "plantpot.single.deployed",
            "bathtub.planter.deployed",
            "minecart.planter.deployed"
        };
        [JsonProperty("Fertilizer Item Shortname")]
        public string FertilizerItem { get; set; } = "fertilizer";
        [JsonProperty("Debug Mode")]
        public bool Debug { get; set; } = false;
        [JsonIgnore]
        private HashSet<string> _planterTypes;
        public bool ValidateAndCorrect()
        {
            bool changed = false;
            if (MaxDistributionRange <= 0)
            {
                MaxDistributionRange = 50.0f;
                changed = true;
            }
            if (SupportedPlanterTypes == null || SupportedPlanterTypes.Length == 0)
            {
                SupportedPlanterTypes = new[]
                {
                    "planter.large.deployed", "planter.small.deployed", "planter.triangle.deployed",
                    "plantpot.single.deployed", "bathtub.planter.deployed", "minecart.planter.deployed"
                };
                changed = true;
            }
            if (string.IsNullOrEmpty(FertilizerItem))
            {
                FertilizerItem = "fertilizer";
                changed = true;
            }
            return changed;
        }
        public bool IsSupportedPlanterType(string shortname)
        {
            if (string.IsNullOrEmpty(shortname) || SupportedPlanterTypes == null) return false;
            if (_planterTypes == null)
                _planterTypes = new HashSet<string>(SupportedPlanterTypes, StringComparer.OrdinalIgnoreCase);
            return _planterTypes.Contains(shortname);
        }
    }
    // --- Data/PlanterInfo.cs ---
    public class PlanterInfo
    {
        public BaseEntity Entity { get; set; }
        public ItemContainer Container { get; set; }
        public int FertilizerCount { get; set; }
        public PlanterInfo(BaseEntity entity)
        {
            Entity = entity;
            Container = entity.GetComponent<StorageContainer>()?.inventory;
            UpdateInfo();
        }
        public void UpdateInfo()
        {
            if (Entity == null || Entity.IsDestroyed || Container == null) return;
            FertilizerCount = 0;
            foreach (var item in Container.itemList)
            {
                if (item.info.shortname == PluginConfig.Instance.FertilizerItem)
                    FertilizerCount += item.amount;
            }
        }
        public int RemoveAllFertilizer()
        {
            if (Container == null || Entity == null || Entity.IsDestroyed) return 0;
            int total = 0;
            var items = new List<Item>();
            foreach (var item in Container.itemList)
            {
                if (item.info.shortname != PluginConfig.Instance.FertilizerItem) continue;
                items.Add(item);
                total += item.amount;
            }
            foreach (var item in items)
            {
                item.RemoveFromContainer();
                item.Remove();
            }
            if (total > 0) UpdateInfo();
            return total;
        }
        public bool AddFertilizer(int amount = 1)
        {
            if (Container == null || Entity == null || Entity.IsDestroyed) return false;
            var itemDefinition = ItemManager.FindItemDefinition(PluginConfig.Instance.FertilizerItem);
            if (itemDefinition == null) return false;
            foreach (var existingItem in Container.itemList)
            {
                if (existingItem.info.shortname != PluginConfig.Instance.FertilizerItem) continue;
                if (existingItem.amount >= existingItem.MaxStackable()) continue;
                int canAdd = Math.Min(amount, existingItem.MaxStackable() - existingItem.amount);
                existingItem.amount += canAdd;
                existingItem.MarkDirty();
                amount -= canAdd;
                if (amount <= 0)
                {
                    UpdateInfo();
                    return true;
                }
            }
            while (amount > 0)
            {
                var item = ItemManager.Create(itemDefinition, Math.Min(amount, itemDefinition.stackable));
                if (item == null) return false;
                bool placed = false;
                for (int slot = 0; slot < Container.capacity; slot++)
                {
                    if (Container.GetSlot(slot) != null) continue;
                    if (item.MoveToContainer(Container, slot))
                    {
                        amount -= item.amount;
                        placed = true;
                        break;
                    }
                }
                if (!placed)
                {
                    item.Remove();
                    return false;
                }
            }
            UpdateInfo();
            return true;
        }
    }
    // --- Managers/ComposterManager.cs ---
    public class ComposterManager
    {
        private readonly FertilizerDistributor _fertilizerDistributor;
        public ComposterManager(FertilizerDistributor fertilizerDistributor)
        {
            _fertilizerDistributor = fertilizerDistributor;
        }
        public ProcessResult ProcessComposterManually(Composter composter)
        {
            if (composter == null || composter.IsDestroyed) return null;
            var result = new ProcessResult();
            var container = composter.inventory;
            if (container == null)
            {
                result.StopReason = "No inventory container";
                return result;
            }
            int total = 0;
            var items = new List<Item>(container.itemList);
            foreach (var item in items)
            {
                total += item.amount;
                item.Remove();
            }
            var planters = _fertilizerDistributor.GetPlantersNear(composter.transform.position);
            foreach (var planter in planters)
            {
                total += planter.RemoveAllFertilizer();
            }
            if (total == 0)
            {
                result.StopReason = "No fertilizer to distribute";
                return result;
            }
            int remaining = _fertilizerDistributor.DistributeFertilizerAndReturnRemainder(
                composter.transform.position, total);
            result.FertilizerFound = total;
            result.FertilizerDistributed = total - remaining;
            if (remaining > 0)
            {
                AddFertilizerToComposter(composter, remaining);
                result.FertilizerRemaining = remaining;
            }
            foreach (var planter in planters)
            {
                planter.UpdateInfo();
                if (planter.FertilizerCount > 0) result.PlantersReceived++;
            }
            return result;
        }
        private void AddFertilizerToComposter(Composter composter, int amount)
        {
            if (composter == null || composter.inventory == null || amount <= 0) return;
            var item = ItemUtils.CreateFertilizerItem(amount);
            if (item == null) return;
            if (!composter.inventory.Insert(item))
            {
                item.Remove();
            }
        }
        public class ProcessResult
        {
            public int FertilizerFound { get; set; }
            public int FertilizerDistributed { get; set; }
            public int FertilizerRemaining { get; set; }
            public int PlantersReceived { get; set; }
            public string StopReason { get; set; } = string.Empty;
        }
    }
    // --- Managers/FertilizerDistributor.cs ---
    public class FertilizerDistributor
    {
        public int DistributeFertilizerAndReturnRemainder(Vector3 composterPosition, int totalFertilizer)
        {
            if (totalFertilizer <= 0) return 0;
            var planters = PlanterFinder.FindNearbyPlanters(composterPosition);
            if (planters.Count == 0) return totalFertilizer;
            int remaining = totalFertilizer;
            while (remaining > 0 && planters.Count > 0)
            {
                bool placed = false;
                for (int i = 0; i < planters.Count && remaining > 0; i++)
                {
                    if (planters[i].AddFertilizer(1))
                    {
                        remaining--;
                        placed = true;
                    }
                }
                if (!placed) break;
                planters.Sort((a, b) => a.FertilizerCount.CompareTo(b.FertilizerCount));
            }
            return remaining;
        }
        public List<PlanterInfo> GetPlantersNear(Vector3 position)
        {
            return PlanterFinder.FindNearbyPlanters(position);
        }
    }
    // --- Managers/PlanterFinder.cs ---
    public static class PlanterFinder
    {
        private static readonly int PlanterLayerMask = LayerMask.GetMask("Deployed", "Default");
        public static List<PlanterInfo> FindNearbyPlanters(Vector3 position)
        {
            var planters = new List<PlanterInfo>();
            var seen = new HashSet<ulong>();
            foreach (var collider in Physics.OverlapSphere(position, PluginConfig.Instance.MaxDistributionRange, PlanterLayerMask))
            {
                var entity = collider.GetComponentInParent<BaseEntity>();
                if (entity == null || entity.IsDestroyed) continue;
                if (!PluginConfig.Instance.IsSupportedPlanterType(entity.ShortPrefabName)) continue;
                if (!seen.Add(entity.net.ID.Value)) continue;
                planters.Add(new PlanterInfo(entity));
            }
            return planters;
        }
    }
    // --- Managers/UIManager.cs ---
    public class UIManager
    {
        private readonly CompostHelper _plugin;
        private readonly ComposterManager _composterManager;
        private readonly Dictionary<ulong, string> _activeUIs = new Dictionary<ulong, string>();
        public UIManager(CompostHelper plugin, ComposterManager composterManager)
        {
            _plugin = plugin;
            _composterManager = composterManager;
        }
        public void OnLootEntityOpened(BasePlayer player, BaseEntity entity)
        {
            if (entity is not Composter composter) return;
            CreateSpreadButton(player, composter);
        }
        public void OnLootEntityClosed(BasePlayer player, BaseEntity entity)
        {
            if (entity is not Composter) return;
            DestroySpreadButton(player);
        }
        private void CreateSpreadButton(BasePlayer player, Composter composter)
        {
            if (!_plugin.HasPermission(player, Consts.PERMISSION_USE)) return;
            var elements = new CuiElementContainer();
            var button = new CuiButton
            {
                Button = {
                    Command = $"{Consts.CMD_SPREAD} {composter.net.ID}",
                    Color = "0.8 0.4 0.2 0.9"
                },
                RectTransform = {
                    AnchorMin = "0.70 0.90",
                    AnchorMax = "0.95 0.98"
                },
                Text = {
                    Text = "SPREAD",
                    FontSize = 12,
                    Align = TextAnchor.MiddleCenter,
                    Color = "1 1 1 1"
                }
            };
            elements.Add(button, "Overlay", Consts.UI_SPREAD_BUTTON);
            CuiHelper.AddUi(player, elements);
            _activeUIs[player.userID] = Consts.UI_SPREAD_BUTTON;
        }
        private void DestroySpreadButton(BasePlayer player)
        {
            if (!_activeUIs.TryGetValue(player.userID, out var uiName)) return;
            CuiHelper.DestroyUi(player, uiName);
            _activeUIs.Remove(player.userID);
        }
        public void HandleSpreadCommand(BasePlayer player, string[] args)
        {
            if (!_plugin.HasPermission(player, Consts.PERMISSION_USE))
            {
                player.ChatMessage(_plugin.GetMessage(Consts.LANG_NO_PERMISSION, player));
                return;
            }
            if (args.Length < 1)
            {
                player.ChatMessage(_plugin.GetMessage(Consts.LANG_INVALID_COMMAND, player));
                return;
            }
            if (!ulong.TryParse(args[0], out var netId))
            {
                player.ChatMessage(_plugin.GetMessage(Consts.LANG_INVALID_COMPOSTER, player));
                return;
            }
            var composter = BaseNetworkable.serverEntities.Find(new NetworkableId(netId)) as Composter;
            if (composter == null || composter.IsDestroyed)
            {
                player.ChatMessage(_plugin.GetMessage(Consts.LANG_COMPOSTER_NOT_FOUND, player));
                return;
            }
            if (Vector3.Distance(player.transform.position, composter.transform.position) > 5f)
            {
                player.ChatMessage(_plugin.GetMessage(Consts.LANG_TOO_FAR_AWAY, player));
                return;
            }
            var result = _composterManager.ProcessComposterManually(composter);
            if (result == null)
            {
                player.ChatMessage(_plugin.GetMessage(Consts.LANG_PROCESS_FAILED, player));
                return;
            }
            if (result.FertilizerFound == 0)
            {
                player.ChatMessage(_plugin.GetMessage(Consts.LANG_NO_FERTILIZER, player, result.StopReason));
                return;
            }
            player.ChatMessage(result.FertilizerDistributed > 0
                ? _plugin.GetMessage(Consts.LANG_DISTRIBUTE_SUCCESS, player, result.FertilizerDistributed, result.FertilizerFound, result.PlantersReceived)
                : _plugin.GetMessage(Consts.LANG_DISTRIBUTE_FAILED, player, result.FertilizerFound, result.StopReason));
            if (result.FertilizerRemaining > 0)
            {
                player.ChatMessage(_plugin.GetMessage(Consts.LANG_FERTILIZER_REMAINING, player, result.FertilizerRemaining));
            }
        }
        public void OnPlayerDisconnected(BasePlayer player)
        {
            _activeUIs.Remove(player.userID);
        }
        public void Cleanup()
        {
            foreach (var kvp in _activeUIs)
            {
                var player = BasePlayer.FindByID(kvp.Key);
                if (player != null && !player.IsDestroyed)
                {
                    CuiHelper.DestroyUi(player, kvp.Value);
                }
            }
            _activeUIs.Clear();
        }
    }
    // --- Utils/Consts.cs ---
    internal static class Consts
    {
        public const string LOG_PREFIX = "CompostHelper";
        public const string PERMISSION_USE = "composthelper.use";
        public const string UI_SPREAD_BUTTON = "ComposterButton";
        public const string CMD_SPREAD = "composter.spread";
        public const string LANG_NO_PERMISSION = "NoPermission";
        public const string LANG_INVALID_COMMAND = "InvalidCommand";
        public const string LANG_INVALID_COMPOSTER = "InvalidComposterId";
        public const string LANG_COMPOSTER_NOT_FOUND = "ComposterNotFound";
        public const string LANG_TOO_FAR_AWAY = "TooFarAway";
        public const string LANG_DISTRIBUTE_SUCCESS = "DistributeSuccess";
        public const string LANG_DISTRIBUTE_FAILED = "DistributeFailed";
        public const string LANG_FERTILIZER_REMAINING = "FertilizerRemaining";
        public const string LANG_NO_FERTILIZER = "NoFertilizer";
        public const string LANG_PROCESS_FAILED = "ProcessFailed";
    }
    // --- Utils/ItemUtils.cs ---
    public static class ItemUtils
    {
        public static Item CreateFertilizerItem(int amount = 1)
        {
            var definition = ItemManager.FindItemDefinition(PluginConfig.Instance.FertilizerItem);
            return definition != null ? ItemManager.Create(definition, amount) : null;
        }
    }
    // --- Utils/Log.cs ---
    public static class Log
    {
        public static void Info(string message)
        {
            if (!PluginConfig.Instance.Debug) return;
            Interface.Oxide.LogInfo($"[{Consts.LOG_PREFIX}] {message}");
        }
        public static void Warning(string message)
        {
            if (!PluginConfig.Instance.Debug) return;
            Interface.Oxide.LogWarning($"[{Consts.LOG_PREFIX}] {message}");
        }
        public static void Error(string message)
        {
            Interface.Oxide.LogError($"[{Consts.LOG_PREFIX}] {message}");
        }
    }
    // --- Utils/StartupDiagnostics.cs ---
    internal static class StartupDiagnostics
    {
        public static void Run(Permission permissionSystem)
        {
            if (!PluginConfig.Instance.Debug) return;
            var config = PluginConfig.Instance;
            Log.Info("=== CompostHelper Startup ===");
            Log.Info($"  - Distribution Range: {config.MaxDistributionRange}m");
            Log.Info($"  - Fertilizer Item: {config.FertilizerItem}");
            Log.Info($"  - Supported Planters: {config.SupportedPlanterTypes?.Length ?? 0} types");
            if (!permissionSystem.PermissionExists(Consts.PERMISSION_USE))
                Log.Error($"Permission not registered: {Consts.PERMISSION_USE}");
        }
    }
}

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