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

FREE UsableHoppers : 1.0.2 1.0.2

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

namespace Oxide.Plugins
{
    [Info("UsableHoppers", "Mattffhh", "1.0.2")]
    [Description("A plugin that collects nearby loot into a container.")]
    public class UsableHoppers : RustPlugin
    {
        private ConfigData config;
        private StoredData storedData;
        private Dictionary<ulong, List<ulong>> hoppers = new Dictionary<ulong, List<ulong>>();
        private LayerMask hopperLayerMask;

        private Dictionary<ulong, float> commandCooldowns = new Dictionary<ulong, float>();
        private Dictionary<ulong, StorageContainer> hopperCache = new Dictionary<ulong, StorageContainer>();
        private List<SphereEntity> spheres = new List<SphereEntity>();

        private const string adminPermission = "usablehoppers.admin";

        #region Configuration and Data

        private class ConfigData
        {
            [JsonProperty(PropertyName = "Hopper radius")]
            public float HopperRadius { get; set; } 

            [JsonProperty(PropertyName = "Max items per tick")]
            public int MaxItemsPerTick { get; set; }

            [JsonProperty(PropertyName = "How often the hopper collects items")]
            public float CollectionIntervalSeconds { get; set; }

            [JsonProperty(PropertyName = "Debug mode")]
            public bool EnableDebug { get; set; }

            [JsonProperty(PropertyName = "Max hoppers per players")]
            public int MaxHoppersPerPlayer { get; set; }

            [JsonProperty(PropertyName = "Command cooldown")]
            public float CommandCooldown { get; set; }

            [JsonProperty(PropertyName = "Allowed containers for hoppers")]
            public List<string> AllowedContainerTypes { get; set; }

            [JsonProperty(PropertyName = "Item types allowed")]
            public Dictionary<string, bool> ItemTypeSettings { get; set; }
        }

        private class StoredData
        {
            public Dictionary<ulong, List<ulong>> SavedHoppers = new Dictionary<ulong, List<ulong>>();
        }

        protected override void LoadDefaultConfig()
        {
            ConfigData defaultConfig = new ConfigData
            {
                CommandCooldown = 0,
                HopperRadius = 3.0f,
                MaxItemsPerTick = 10,
                CollectionIntervalSeconds = 5.0f,
                EnableDebug = false,
                MaxHoppersPerPlayer = 5,
                AllowedContainerTypes = new List<string> { "woodbox_deployed", "box.wooden.large", "furnace", "storage_barrel_c", "storage_barrel_b" },
                ItemTypeSettings = new Dictionary<string, bool>
                {
                    { "weapon", true },
                    { "resources", true },
                    { "medical", true },
                    { "construction", true },
                    { "attire", true },
                    { "tool", true },
                    { "food", true },
                    { "ammunition", true },
                    { "traps", true },
                    { "misc", true },
                    { "component", true },
                    { "blueprint", true },
                    { "items", true },
                    { "electrical", true },
                    { "fun", true }
                }
            };
            Config.WriteObject(defaultConfig, true);
        }

        private void LoadConfigValues()
        {
            config = Config.ReadObject<ConfigData>() ?? new ConfigData();

            if (config.CommandCooldown < 0)
            {
                Puts("CommandCooldown in config was set to a negative value. Automatically setting the value to 0.");
                config.CommandCooldown = 0;
            }
        }

        private void SaveData(bool forceSave = false)
        {
            if (storedData == null)
            {
                storedData = new StoredData();
            }

            storedData.SavedHoppers = hoppers;

            if (forceSave)
            {
                Interface.Oxide.DataFileSystem.WriteObject("UsableHoppers", storedData);
            }
            else
            {
                timer.Once(300f, () => Interface.Oxide.DataFileSystem.WriteObject("UsableHoppers", storedData));
            }
        }

        private void LoadData()
        {
            storedData = Interface.Oxide.DataFileSystem.ReadObject<StoredData>("UsableHoppers") ?? new StoredData();
            hoppers = storedData.SavedHoppers ?? new Dictionary<ulong, List<ulong>>();
        }

        #endregion

        private void Init()
        {
            permission.RegisterPermission(adminPermission, this);
        }

        private void OnServerInitialized()
        {
            hopperLayerMask = LayerMask.GetMask("Physics Debris");
            LoadConfigValues();
            LoadData();
            timer.Every(config.CollectionIntervalSeconds, HopperScan);
        }

        private void OnServerSave()
        {
            SaveData(true);
        }

        private void Unload()
        {
            hopperCache.Clear();

            foreach (var sphere in spheres)
            {
                if (sphere != null && !sphere.IsDestroyed)
                {
                    sphere.Kill();
                }
            }
            SaveData(true);
        }

        #region Chat Commands

        [ChatCommand("uh")]
        private void ListCommands(BasePlayer player)
        {
            if (!permission.UserHasPermission(player.UserIDString, adminPermission))
            {
                player.ChatMessage("[UsableHoppers] commands: " +
                    "\nuhset - set the container you are looking at to a hopper. " +
                    "\nuhremove - remove the hopper from the container you are looking at." +
                    "\nuhlist - shows a list of all your hoppers." +
                    "\nuhrange - shows the pickup radius of your hoppers.");
            }
            else
            {
                player.ChatMessage("[UsableHoppers] commands: " +
                    "\nuhset - set the container you are looking at to a hopper. " +
                    "\nuhremove - remove the hopper from the container you are looking at." +
                    "\nuhlist - shows a list of all your hoppers." +
                    "\nuhrange - shows the pickup radius of your hoppers." +
                    "\nuhclearplayer <playername or steamid> - clears the player's hoppers." +
                    "\nuhclearall - clear all the player's hoppers.");
            }
        }

        [ChatCommand("uhset")]
        private void SetHopperCommand(BasePlayer player)
        {
            if (IsOnCooldown(player, config.CommandCooldown)) return;

            var entity = GetLookEntity(player);
            if (entity is StorageContainer container)
            {
                if (!IsAllowedContainer(container.ShortPrefabName))
                {
                    player.ChatMessage($"You cannot set {container.ShortPrefabName} as a hopper.");
                    return;
                }

                if (!hoppers.ContainsKey(player.userID))
                {
                    hoppers[player.userID] = new List<ulong>();
                }

                if (hoppers[player.userID].Count >= config.MaxHoppersPerPlayer)
                {
                    player.ChatMessage($"You have reached the maximum number of hoppers ({config.MaxHoppersPerPlayer}).");
                    return;
                }

                if (IsHopperClaimed(container.net.ID.Value))
                {
                    player.ChatMessage("This container is already marked as a hopper by another player.");
                    return;
                }

                hoppers[player.userID].Add(container.net.ID.Value);
                player.ChatMessage("This container has been marked as a hopper.");
                SaveData();
            }
            else
            {
                player.ChatMessage("You are not looking at a valid container!");
            }
        }

        [ChatCommand("uhremove")]
        private void RemoveHopperCommand(BasePlayer player)
        {
            if (IsOnCooldown(player, config.CommandCooldown)) return;

            var entity = GetLookEntity(player);
            if (entity is StorageContainer container)
            {
                if (!hoppers.ContainsKey(player.userID) || hoppers[player.userID].Count == 0)
                {
                    player.ChatMessage("You don't have any hoppers to remove.");
                    return;
                }

                if (hoppers[player.userID].Contains(container.net.ID.Value))
                {
                    hoppers[player.userID].Remove(container.net.ID.Value);
                    player.ChatMessage("The hopper you were looking at has been removed.");
                    SaveData();
                }
                else
                {
                    player.ChatMessage("This container is not marked as a hopper.");
                }
            }
            else
            {
                player.ChatMessage("You are not looking at a valid container!");
            }
        }

        [ChatCommand("uhlist")]
        private void ShowActiveHoppers(BasePlayer player)
        {
            if (IsOnCooldown(player, config.CommandCooldown)) return;

            if (!hoppers.ContainsKey(player.userID) || hoppers[player.userID].Count == 0)
            {
                player.ChatMessage("You have no active hoppers.");
                return;
            }

            player.ChatMessage($"You have the following hoppers ({hoppers[player.userID].Count} / {config.MaxHoppersPerPlayer}):");

            foreach (var hopperID in hoppers[player.userID])
            {
                var container = FindChestByID(hopperID);
                if (container != null)
                {
                    player.ChatMessage($"Hopper {container.ShortPrefabName} at:{container.transform.position}");
                    Vector3 spherePosition = container.transform.position + new Vector3(0, 1.0f, 0);
                    CreateSphereEntity(spherePosition, 0.5f, player);
                }
            }   
        }

        [ChatCommand("uhrange")]
        private void DrawHopperRange(BasePlayer player)
        {
            if (IsOnCooldown(player, config.CommandCooldown)) return;

            if (!hoppers.ContainsKey(player.userID) || hoppers[player.userID].Count == 0)
            {
                player.ChatMessage("You have no active hoppers.");
                return;
            }

            foreach (var hopperID in hoppers[player.userID])
            {
                var container = FindChestByID(hopperID);
                if (container != null)
                {
                    CreateSphereEntity(container.transform.position, config.HopperRadius, player);
                }
            }
        }

        [ChatCommand("uhclearall")]
        private void ClearAllHoppersCommand(BasePlayer player)
        {
            if (!permission.UserHasPermission(player.UserIDString, adminPermission))
            {
                player.ChatMessage("You don't have permission to use this command.");
                return;
            }

            hoppers.Clear();
            SaveData();
            player.ChatMessage("All hoppers have been cleared.");
            Puts("All hoppers have been cleared by an admin.");
        }

        [ChatCommand("uhclearplayer")]
        private void ClearPlayerHoppersCommand(BasePlayer player, string command, string[] args)
        {
            if (!permission.UserHasPermission(player.UserIDString, adminPermission))
            {
                player.ChatMessage("You don't have permission to use this command.");
                return;
            }

            if (args.Length != 1)
            {
                player.ChatMessage("Usage: /uhclearplayer <playername or steamid>");
                return;
            }

            BasePlayer targetPlayer = FindPlayer(args[0]);
            if (targetPlayer == null)
            {
                player.ChatMessage("Player not found.");
                return;
            }

            if (hoppers.ContainsKey(targetPlayer.userID))
            {
                hoppers.Remove(targetPlayer.userID);
                SaveData();
                player.ChatMessage($"All hoppers for player {targetPlayer.displayName} have been cleared.");
                Puts($"Admin cleared hoppers for player {targetPlayer.displayName}.");
            }
            else
            {
                player.ChatMessage("This player has no hoppers.");
            }
        }

        #endregion

        private void OnEntityKill(BaseNetworkable entity)
        {
            if (entity is StorageContainer container)
            {
                RemoveHopperByChest(container.net.ID.Value);
            }
        }

        private void RemoveHopperByChest(ulong chestID)
        {
            if (hopperCache.ContainsKey(chestID))
            {
                hopperCache.Remove(chestID);
            }

            foreach (var playerHoppers in hoppers)
            {
                if (playerHoppers.Value.Contains(chestID))
                {
                    playerHoppers.Value.Remove(chestID);
                    if (playerHoppers.Value.Count == 0)
                    {
                        hoppers.Remove(playerHoppers.Key);
                    }
                    SaveData();
                    break;
                }
            }
        }

        private bool IsAllowedContainer(string prefabName)
        {
            return config.AllowedContainerTypes.Contains(prefabName);
        }

        private bool IsHopperClaimed(ulong hopperID)
        {
            foreach (var playerHoppers in hoppers.Values)
            {
                if (playerHoppers.Contains(hopperID))
                {
                    return true;
                }
            }
            return false;
        }

        private bool IsOnCooldown(BasePlayer player, float cooldown)
        {
            if (commandCooldowns.TryGetValue(player.userID, out var lastUsed) && Time.realtimeSinceStartup - lastUsed < cooldown)
            {
                player.ChatMessage("Please wait before using this command again.");
                return true;
            }

            commandCooldowns[player.userID] = Time.realtimeSinceStartup;
            return false;
        }

        private bool IsValidItem(Item item)
        {
            var itemCategory = item.info.category.ToString().ToLower();
            if (config.EnableDebug) Puts($"Item {item.info.displayName.english} belongs to category {itemCategory}");

            if (config.ItemTypeSettings.ContainsKey(itemCategory))
            {
                if (config.EnableDebug) Puts($"Item {item.info.displayName.english} is categorized as {itemCategory} and is {(config.ItemTypeSettings[itemCategory] ? "valid" : "invalid")}");
                return config.ItemTypeSettings[itemCategory]; 
            }
            if (config.EnableDebug) Puts($"Item {item.info.displayName.english} does not match any valid categories.");
            return false;
        }

        private void CreateSphereEntity(Vector3 position, float radius, BasePlayer player)
        {
            var sphere = GameManager.server.CreateEntity("assets/bundled/prefabs/modding/events/twitch/br_sphere.prefab", position) as SphereEntity;
            if (sphere != null)
            {
                sphere.currentRadius = radius * 2 - 0.1f;
                sphere.enableSaving = false;
                sphere.Spawn();
                sphere?.LerpRadiusTo(radius * 2, radius * 0.75f);
                sphere.SendNetworkUpdate();

                spheres.Add(sphere);

                timer.Once(10f, () =>
                {
                    if (sphere != null && !sphere.IsDestroyed)
                    {
                        spheres.Remove(sphere);
                        sphere.Kill();
                    }
                });
            }
        }

        private BasePlayer FindPlayer(string nameOrId)
        {
            return BasePlayer.activePlayerList.FirstOrDefault(player =>
                player.UserIDString == nameOrId || player.displayName.ToLower().Contains(nameOrId.ToLower()));
        }

        private void HopperScan()
        {
            List<ulong> toRemove = Pool.Get<List<ulong>>();
            //List<ulong> toRemove = Pool.GetList<ulong>(); Deprecated function

            foreach (var playerHoppers in hoppers)
            {
                foreach (var hopperID in playerHoppers.Value.ToList())
                {
                    var container = FindChestByID(hopperID);
                    if (container == null)
                    {
                        Puts($"Removed invalid hopper for player {playerHoppers.Key}");
                        playerHoppers.Value.Remove(hopperID);

                        if (playerHoppers.Value.Count == 0)
                        {
                            toRemove.Add(playerHoppers.Key);
                        }
                    }
                    else
                    {
                        ScanForItems(container);
                    }
                }
            }

            foreach (var userId in toRemove)
            {
                hoppers.Remove(userId);
            }

            Pool.FreeUnmanaged(ref toRemove);

            SaveData();
        }

        private void ScanForItems(StorageContainer container)
        {
            List<BaseEntity> nearbyEntities = Pool.Get<List<BaseEntity>>();
            //List<BaseEntity> nearbyEntities = Pool.GetList<BaseEntity>(); Deprecated function
            var hopperPosition = container.transform.position;

            Vis.Entities(hopperPosition, config.HopperRadius, nearbyEntities, hopperLayerMask);

            if (nearbyEntities.Count == 0)
            {
                if (config.EnableDebug) Puts("No entities found near hopper at " + hopperPosition);
                Pool.FreeUnmanaged(ref nearbyEntities);
                return;
            }

            foreach (var entity in nearbyEntities.Take(config.MaxItemsPerTick))
            {
                Item item = null;

                if (entity is DroppedItem droppedItemEntity)
                {
                    item = droppedItemEntity.item;
                }
                else if (entity is DroppedItemContainer itemContainerEntity)
                {
                    foreach (var containerItem in itemContainerEntity.inventory.itemList)
                    {
                        if (IsValidItem(containerItem) && MoveItemToChest(container, containerItem))
                        {
                            timer.Once(0.1f, () =>
                            {
                                containerItem.Remove();
                            });
                        }
                    }
                    continue;
                }

                if (item != null && item.amount > 0 && IsValidItem(item))
                {
                    if (MoveItemToChest(container, item))
                    {
                        timer.Once(0.1f, () =>
                        {
                            if (!entity.IsDestroyed)
                            {
                                entity.Kill();
                            }
                        });
                    }
                }
                else
                {
                    if (config.EnableDebug && entity.IsDestroyed)
                    {
                        Puts($"Entity {entity.ShortPrefabName} is already destroyed.");
                    }
                }
            }
            Pool.FreeUnmanaged(ref nearbyEntities);
        }

        private bool MoveItemToChest(StorageContainer container, Item item)
        {
            return container.inventory.itemList.Count < container.inventory.capacity && item.MoveToContainer(container.inventory);
        }

        private StorageContainer FindChestByID(ulong entityID)
        {
            if (hopperCache.TryGetValue(entityID, out var container) && container != null)
            {
                return container;
            }

            container = BaseNetworkable.serverEntities
                .OfType<StorageContainer>()
                .FirstOrDefault(c => c.net.ID.Value == entityID);

            if (container != null)
            {
                hopperCache[entityID] = container;
            }

            return container;
        }

        private BaseEntity GetLookEntity(BasePlayer player, float maxDistance = 5f)
        {
            Vector3 eyesPos = player.eyes.position;
            Vector3 direction = player.eyes.HeadForward();
            if (Physics.Raycast(eyesPos, direction, out RaycastHit hit, maxDistance))
            {
                return hit.GetEntity();
            }
            return null;
        }
    }
}

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