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

FREE MushroomPlanter : 1.0.1 1.0.1

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

namespace Oxide.Plugins
{
    [Info("MushroomPlanter", "NINJA WORKS", "1.0.1")]
    [Description("Grows mushroom clusters in empty spaces of planter boxes")]
    public class MushroomPlanter : RustPlugin
    {
        private Configuration config;

        private class Configuration
        {
            public float MushroomGrowthChance { get; set; } = 0.8f;
            public float MushroomGrowthInterval { get; set; } = 1800f;
            public float MushroomWaterRequired { get; set; } = 100f;
            public float MinimumWaterForGrowth { get; set; } = 0f;
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                config = Config.ReadObject<Configuration>();
                if (config == null)
                {
                    throw new Exception();
                }
            }
            catch
            {
                Config.WriteObject(config, true);
                PrintWarning("Created new config file.");
            }
        }

        protected override void LoadDefaultConfig()
        {
            config = new Configuration();
        }

        protected override void SaveConfig()
        {
            Config.WriteObject(config);
        }

        private static readonly string[] MushroomClusterPrefabs = new string[]
        {
            "assets/bundled/prefabs/autospawn/collectable/mushrooms/mushroom-cluster-5.prefab",
            "assets/bundled/prefabs/autospawn/collectable/mushrooms/mushroom-cluster-6.prefab"
        };

        private const string LargePlanterPrefab = "assets/prefabs/deployable/planters/planter.large.deployed.prefab";
        private const string SmallPlanterPrefab = "assets/prefabs/deployable/planters/planter.small.deployed.prefab";
        private const string BathtubPlanterPrefab = "assets/prefabs/misc/decor_dlc/bath tub planter/bathtub.planter.deployed.prefab";
        private const string MinecartPlanterPrefab = "assets/prefabs/misc/decor_dlc/minecart planter/minecart.planter.deployed.prefab";
        private const string RailRoadPlanterPrefab = "assets/prefabs/misc/decor_dlc/rail road planter/railroadplanter.deployed.prefab";
        private const string SinglePlantPotPrefab = "assets/prefabs/deployable/plant pots/plantpot.single.deployed.prefab";
        private const string TrianglePlanterPrefab = "assets/prefabs/deployable/planters/planter.triangle.deployed.prefab";
        private const string RailRoadTrianglePlanterPrefab = "assets/prefabs/misc/decor_dlc/rail road planter/triangle_railroad_planter.deployed.prefab";

        private Dictionary<NetworkableId, float> planterTime = new Dictionary<NetworkableId, float>();
        private Dictionary<string, List<SerializableMushroomData>> savedMushrooms = new Dictionary<string, List<SerializableMushroomData>>();

        [Serializable]
        private class SerializableMushroomData
        {
            public string PrefabName;
            public Vector3 LocalPosition;
            public Vector3 LocalRotationEuler;

            public SerializableMushroomData() { }

            public SerializableMushroomData(BaseEntity mushroom)
            {
                PrefabName = mushroom.PrefabName;
                LocalPosition = mushroom.transform.localPosition;
                LocalRotationEuler = mushroom.transform.localRotation.eulerAngles;
            }

            public BaseEntity CreateMushroom(PlanterBox planter)
            {
                BaseEntity mushroom = GameManager.server.CreateEntity(
                    PrefabName, 
                    planter.transform.TransformPoint(LocalPosition), 
                    planter.transform.rotation * Quaternion.Euler(LocalRotationEuler)
                );
                
                if (mushroom != null)
                {
                    mushroom.Spawn();
                    mushroom.SetParent(planter, worldPositionStays: true);
                }
                return mushroom;
            }
        }

        void OnServerInitialized()
        {
            try
            {
                timer.Every(config.MushroomGrowthInterval, CheckPlantersForMushrooms);

                timer.Once(5f, () => 
                {
                    CleanupInvalidPlanterData();
                    RemoveAllMushrooms();
                    LoadMushrooms();
                    Puts("Mushroom grower initialized - mushrooms restored.");
                });

                Puts("MushroomGrower plugin initialized successfully.");
            }
            catch (Exception ex)
            {
                Puts($"Error in OnServerInitialized: {ex.Message}");
                Puts($"StackTrace: {ex.StackTrace}");
            }
        }

        void OnServerSave()
        {
            SaveMushrooms();
        }

        void Unload()
        {
            SaveMushrooms();
            RemoveAllMushrooms();
            planterTime.Clear();
        }

        void RemoveAllMushrooms()
        {
            var planters = UnityEngine.Object.FindObjectsOfType<PlanterBox>();
            int removedCount = 0;

            foreach (var planter in planters)
            {
                var mushroomsToRemove = new List<BaseEntity>();
                foreach (var child in planter.children)
                {
                    if (MushroomClusterPrefabs.Contains(child.PrefabName))
                    {
                        mushroomsToRemove.Add(child);
                    }
                }

                foreach (var mushroom in mushroomsToRemove)
                {
                    mushroom.Kill();
                    removedCount++;
                }
            }

            if (removedCount > 0)
            {
                Puts($"Removed {removedCount} mushrooms.");
            }
        }

        void SaveMushrooms()
        {
            savedMushrooms.Clear();
            var planters = UnityEngine.Object.FindObjectsOfType<PlanterBox>();
            
            foreach (var planter in planters)
            {
                var mushroomList = new List<SerializableMushroomData>();
                foreach (var child in planter.children)
                {
                    if (MushroomClusterPrefabs.Contains(child.PrefabName))
                    {
                        mushroomList.Add(new SerializableMushroomData(child));
                    }
                }
                
                if (mushroomList.Count > 0)
                {
                    savedMushrooms[planter.net.ID.Value.ToString()] = mushroomList;
                }
            }
            
            Interface.Oxide.DataFileSystem.WriteObject("MushroomGrower", savedMushrooms);
        }

        void LoadMushrooms()
        {
            savedMushrooms = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<string, List<SerializableMushroomData>>>("MushroomGrower");
            
            if (savedMushrooms == null)
            {
                savedMushrooms = new Dictionary<string, List<SerializableMushroomData>>();
                Puts("No saved mushroom data found. Starting fresh.");
                return;
            }

            HashSet<string> validPlanterIds = new HashSet<string>();
            var planters = UnityEngine.Object.FindObjectsOfType<PlanterBox>();
            
            foreach (var planter in planters)
            {
                validPlanterIds.Add(planter.net.ID.Value.ToString());
            }

            int restoredCount = 0;
            foreach (var entry in savedMushrooms.ToList())
            {
                if (validPlanterIds.Contains(entry.Key) && ulong.TryParse(entry.Key, out ulong entityId))
                {
                    var planter = BaseNetworkable.serverEntities.Find(new NetworkableId(entityId)) as PlanterBox;
                    if (planter != null)
                    {
                        foreach (var mushroomData in entry.Value)
                        {
                            BaseEntity mushroom = mushroomData.CreateMushroom(planter);
                            if (mushroom != null)
                            {
                                restoredCount++;
                            }
                        }
                    }
                }
                else
                {
                    savedMushrooms.Remove(entry.Key);
                }
            }
            
            Interface.Oxide.DataFileSystem.WriteObject("MushroomGrower", savedMushrooms);
            Puts($"Restored {restoredCount} mushrooms across {savedMushrooms.Count} planters.");
        }

        void CleanupInvalidPlanterData()
        {
            HashSet<string> validPlanterIds = new HashSet<string>();
            var planters = UnityEngine.Object.FindObjectsOfType<PlanterBox>();
            
            foreach (var planter in planters)
            {
                validPlanterIds.Add(planter.net.ID.Value.ToString());
            }

            List<string> invalidKeys = savedMushrooms.Keys
                .Where(key => !validPlanterIds.Contains(key))
                .ToList();

            if (invalidKeys.Count > 0)
            {
                foreach (string key in invalidKeys)
                {
                    savedMushrooms.Remove(key);
                }
                
                Interface.Oxide.DataFileSystem.WriteObject("MushroomGrower", savedMushrooms);
                Puts($"Cleanup: Removed {invalidKeys.Count} invalid planter entries.");
            }
        }

        void CheckPlantersForMushrooms()
        {
            var planters = UnityEngine.Object.FindObjectsOfType<PlanterBox>();
            
            foreach (var planter in planters)
            {
                if (!planterTime.ContainsKey(planter.net.ID))
                {
                    planterTime[planter.net.ID] = 0f;
                }
                
                planterTime[planter.net.ID] += config.MushroomGrowthInterval;

                if (planterTime[planter.net.ID] >= config.MushroomGrowthInterval)
                {
                    TryGrowMushroomCluster(planter);
                }
            }
        }

        void TryGrowMushroomCluster(PlanterBox planter)
        {
            if (UnityEngine.Random.value > config.MushroomGrowthChance)
                return;

            if (planter.soilSaturation < config.MinimumWaterForGrowth)
                return;

            if (planter.soilSaturation < config.MushroomWaterRequired)
                return;

            if (IsPlayerOnPlanter(planter))
                return;

            PlanterInfo planterInfo = GetPlanterInfo(planter);
            List<Vector3> availablePositions = GetAvailablePositions(planter, planterInfo);

            if (availablePositions.Count == 0)
                return;

            Vector3 position = availablePositions[UnityEngine.Random.Range(0, availablePositions.Count)];
            string selectedPrefab = MushroomClusterPrefabs[UnityEngine.Random.Range(0, MushroomClusterPrefabs.Length)];
            Quaternion randomRotation = Quaternion.Euler(0, UnityEngine.Random.Range(0f, 360f), 0);

            BaseEntity mushroomCluster = GameManager.server.CreateEntity(selectedPrefab, position, randomRotation);

            if (mushroomCluster != null)
            {
                planter.soilSaturation -= (int)config.MushroomWaterRequired;
                if (planter.soilSaturation < 0)
                    planter.soilSaturation = 0;

                mushroomCluster.Spawn();
                mushroomCluster.SetParent(planter, worldPositionStays: true);
                mushroomCluster.SendNetworkUpdate();
                planter.SendNetworkUpdate();
            }
        }

        private bool IsPlayerOnPlanter(PlanterBox planter)
        {
            if (planter == null || planter.IsDestroyed)
                return false;

            Bounds planterBounds = GetPlanterBounds(planter);
            planterBounds.Expand(new Vector3(0.0f, 0.5f, 0.0f));

            var players = BasePlayer.activePlayerList;
            foreach (var player in players)
            {
                if (player == null || player.IsDestroyed || player.IsDead())
                    continue;

                if (planterBounds.Contains(player.transform.position))
                    return true;

                if (player.IsSleeping() && planterBounds.Contains(player.eyes.position))
                    return true;
            }

            return false;
        }

        private Bounds GetPlanterBounds(PlanterBox planter)
        {
            var collider = planter.GetComponent<Collider>();
            if (collider != null)
            {
                return collider.bounds;
            }

            Vector3 size = Vector3.one;

            switch (planter.PrefabName)
            {
                case LargePlanterPrefab:
                case RailRoadPlanterPrefab:
                    size = new Vector3(3f, 0.5f, 3f);
                    break;
                case SmallPlanterPrefab:
                    size = new Vector3(1.5f, 0.5f, 0.5f);
                    break;
                case BathtubPlanterPrefab:
                    size = new Vector3(2f, 0.5f, 0.8f);
                    break;
                case MinecartPlanterPrefab:
                    size = new Vector3(1.5f, 0.5f, 0.8f);
                    break;
                case SinglePlantPotPrefab:
                    size = new Vector3(0.5f, 0.5f, 0.5f);
                    break;
                case TrianglePlanterPrefab:
                case RailRoadTrianglePlanterPrefab:
                    size = new Vector3(1.5f, 0.5f, 1.5f);
                    break;
            }

            return new Bounds(planter.transform.position, size);
        }

        PlanterInfo GetPlanterInfo(PlanterBox planter)
        {
            switch (planter.PrefabName)
            {
                case LargePlanterPrefab:
                    return new PlanterInfo(3, 3, 3f, 9, 0.3f);
                case SmallPlanterPrefab:
                    return new PlanterInfo(1, 3, 1.5f, 3, 0.3f);
                case BathtubPlanterPrefab:
                    return new PlanterInfo(1, 3, 2f, 3, 0.6f);
                case MinecartPlanterPrefab:
                    return new PlanterInfo(1, 2, 1.5f, 2, 0.8f);
                case RailRoadPlanterPrefab:
                    return new PlanterInfo(3, 3, 3f, 9, 0.4f);
                case SinglePlantPotPrefab:
                    return new PlanterInfo(1, 1, 0.5f, 1, 0.3f);
                case TrianglePlanterPrefab:
                case RailRoadTrianglePlanterPrefab:
                    return new PlanterInfo(2, 2, 1.5f, 4, 0.3f);
                default:
                    return new PlanterInfo(1, 3, 1.5f, 3, 0.3f);
            }
        }

        List<Vector3> GetAvailablePositions(PlanterBox planter, PlanterInfo info)
        {
            switch (planter.PrefabName)
            {
                case LargePlanterPrefab:
                case RailRoadPlanterPrefab:
                    return GetLargePlanterPositions(planter, info);
                case SmallPlanterPrefab:
                    return GetSmallPlanterPositions(planter, info);
                case BathtubPlanterPrefab:
                    return GetLinearPlanterPositions(planter, info, 0.9f, planter.transform.right);
                case MinecartPlanterPrefab:
                    return GetLinearPlanterPositions(planter, info, 0.6f, planter.transform.right);
                case SinglePlantPotPrefab:
                    return GetSinglePlantPotPositions(planter, info);
                case TrianglePlanterPrefab:
                case RailRoadTrianglePlanterPrefab:
                    return GetTrianglePlanterPositions(planter, info);
                default:
                    return GetSmallPlanterPositions(planter, info);
            }
        }

        List<Vector3> GetLargePlanterPositions(PlanterBox planter, PlanterInfo info)
        {
            List<Vector3> positions = new List<Vector3>();
            float cellSizeX = info.Size / info.GridSizeX;
            float cellSizeZ = info.Size / info.GridSizeZ;
            float startOffsetX = -cellSizeX * (info.GridSizeX - 1) / 2;
            float startOffsetZ = -cellSizeZ * (info.GridSizeZ - 1) / 2;

            for (int row = 0; row < info.GridSizeZ; row++)
            {
                for (int col = 0; col < info.GridSizeX; col++)
                {
                    float xOffset = startOffsetX + col * cellSizeX;
                    float zOffset = startOffsetZ + row * cellSizeZ;

                    Vector3 position = planter.transform.position +
                                       planter.transform.right * xOffset +
                                       planter.transform.forward * zOffset +
                                       new Vector3(0, info.Height, 0);

                    if (!IsPositionOccupied(planter, position, Mathf.Min(cellSizeX, cellSizeZ) / 2))
                    {
                        positions.Add(position);
                    }
                }
            }
            return positions;
        }

        List<Vector3> GetSmallPlanterPositions(PlanterBox planter, PlanterInfo info)
        {
            List<Vector3> positions = new List<Vector3>();
            float planterLength = info.Size;
            float effectiveLength = planterLength * 1.3f;
            float spacing = effectiveLength / (info.MaxMushrooms - 1);

            for (int i = 0; i < info.MaxMushrooms; i++)
            {
                float offset = (i - 1) * spacing;
                Vector3 position = planter.transform.position +
                                   planter.transform.right * offset +
                                   new Vector3(0, info.Height, 0);
                
                if (!IsPositionOccupied(planter, position, spacing / 2))
                {
                    positions.Add(position);
                }
            }
            return positions;
        }

        List<Vector3> GetLinearPlanterPositions(PlanterBox planter, PlanterInfo info, float effectiveLengthFactor, Vector3 direction)
        {
            List<Vector3> positions = new List<Vector3>();
            float planterLength = info.Size;
            float effectiveLength = planterLength * effectiveLengthFactor;
            float spacing = effectiveLength / (info.MaxMushrooms - 1);

            for (int i = 0; i < info.MaxMushrooms; i++)
            {
                float offset = (i - (info.MaxMushrooms - 1) / 2f) * spacing;
                Vector3 position = planter.transform.position +
                                   direction * offset +
                                   new Vector3(0, info.Height, 0);

                if (!IsPositionOccupied(planter, position, spacing / 2))
                {
                    positions.Add(position);
                }
            }
            return positions;
        }

        List<Vector3> GetSinglePlantPotPositions(PlanterBox planter, PlanterInfo info)
        {
            List<Vector3> positions = new List<Vector3>();
            Vector3 position = planter.transform.position + new Vector3(0, info.Height, 0);

            if (!IsPositionOccupied(planter, position, 0.25f))
            {
                positions.Add(position);
            }

            return positions;
        }

        List<Vector3> GetTrianglePlanterPositions(PlanterBox planter, PlanterInfo info)
        {
            List<Vector3> positions = new List<Vector3>();
            float radius = info.Size * 0.7f;
            float rotationOffset = Mathf.PI / 3.4f;
            float globalOffsetX = -0.2f;
            float globalOffsetZ = -0.0f;

            for (int i = 0; i < 3; i++)
            {
                float angle = (Mathf.PI * 2 / 3 * i) + rotationOffset;
                float adjustedRadius = radius * 0.6f;

                Vector3 localPosition = new Vector3(
                    Mathf.Cos(angle) * adjustedRadius + globalOffsetX,
                    info.Height,
                    Mathf.Sin(angle) * adjustedRadius + globalOffsetZ
                );

                Vector3 worldPosition = planter.transform.TransformPoint(localPosition);

                if (!IsPositionOccupied(planter, worldPosition, 0.3f))
                {
                    positions.Add(worldPosition);
                }
            }

            Vector3 centerLocalPosition = new Vector3(globalOffsetX, info.Height, globalOffsetZ);
            Vector3 centerWorldPosition = planter.transform.TransformPoint(centerLocalPosition);

            if (!IsPositionOccupied(planter, centerWorldPosition, 0.3f))
            {
                positions.Add(centerWorldPosition);
            }

            return positions;
        }

        bool IsPositionOccupied(PlanterBox planter, Vector3 position, float radius)
        {
            foreach (var child in planter.children)
            {
                if (child is GrowableEntity || MushroomClusterPrefabs.Contains(child.PrefabName))
                {
                    if (Vector3.Distance(child.transform.position, position) < radius * 1.5f)
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        void OnEntityKill(BaseNetworkable entity)
        {
            if (entity is PlanterBox planter)
            {
                string planterId = planter.net.ID.Value.ToString();
                planterTime.Remove(planter.net.ID);

                if (savedMushrooms.ContainsKey(planterId))
                {
                    savedMushrooms.Remove(planterId);
                    Interface.Oxide.DataFileSystem.WriteObject("MushroomGrower", savedMushrooms);
                }
            }
        }

        [ConsoleCommand("mushroom.clear")]
        void CommandClearMushrooms(ConsoleSystem.Arg arg)
        {
            if (arg.Connection != null && !arg.IsAdmin)
            {
                Puts("This command is admin only.");
                return;
            }

            savedMushrooms.Clear();
            Interface.Oxide.DataFileSystem.WriteObject("MushroomGrower", savedMushrooms);
            RemoveAllMushrooms();
            planterTime.Clear();

            Puts("All mushroom data has been cleared.");
        }

        class PlanterInfo
        {
            public int GridSizeX { get; private set; }
            public int GridSizeZ { get; private set; }
            public float Size { get; private set; }
            public int MaxMushrooms { get; private set; }
            public float Height { get; private set; }

            public PlanterInfo(int gridSizeX, int gridSizeZ, float size, int maxMushrooms, float height)
            {
                GridSizeX = gridSizeX;
                GridSizeZ = gridSizeZ;
                Size = size;
                MaxMushrooms = maxMushrooms;
                Height = height;
            }
        }
    }
}

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