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

FREE AnimalSpawner : 1.0.0 1.0.0

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;

namespace Oxide.Plugins
{
    [Info("AnimalSpawner", "REIN", "1.0.0")]
    [Description("Allows configurable spawning of animals across the map")]
    public class AnimalSpawner : RustPlugin
    {
        private ConfigData configData;
        private const float WorldSize = 4000f; // Стандартный размер карты Rust
        private Dictionary<string, string> animalPrefabMap;

        private class ConfigData
        {
            public Dictionary<string, AnimalConfig> Animals { get; set; }
            public float SpawnCheckInterval { get; set; }
        }

        private class AnimalConfig
        {
            public int MaxAmount { get; set; }
            public float SpawnChance { get; set; }
            public float MinSpawnDistance { get; set; }
            public float MaxSpawnDistance { get; set; }
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                configData = Config.ReadObject<ConfigData>();
                if (configData == null)
                {
                    LoadDefaultConfig();
                }
            }
            catch
            {
                LoadDefaultConfig();
            }
            SaveConfig();
        }

        protected override void LoadDefaultConfig()
        {
            configData = new ConfigData
            {
                SpawnCheckInterval = 10f, // Уменьшаем интервал проверки до 10 секунд
                Animals = new Dictionary<string, AnimalConfig>
                {
                    ["bear"] = new AnimalConfig
                    {
                        MaxAmount = 5,
                        SpawnChance = 0.3f,
                        MinSpawnDistance = 50f,
                        MaxSpawnDistance = 200f
                    },
                    ["wolf"] = new AnimalConfig
                    {
                        MaxAmount = 8,
                        SpawnChance = 0.4f,
                        MinSpawnDistance = 50f,
                        MaxSpawnDistance = 200f
                    },
                    ["boar"] = new AnimalConfig
                    {
                        MaxAmount = 10,
                        SpawnChance = 0.5f,
                        MinSpawnDistance = 50f,
                        MaxSpawnDistance = 200f
                    },
                    ["chicken"] = new AnimalConfig
                    {
                        MaxAmount = 12,
                        SpawnChance = 0.6f,
                        MinSpawnDistance = 50f,
                        MaxSpawnDistance = 200f
                    }
                }
            };
            PrintWarning("Загружена конфигурация по умолчанию");
        }

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

        void OnServerInitialized()
        {
            try 
            {
                // Инициализируем карту префабов
                animalPrefabMap = new Dictionary<string, string>
                {
                    ["assets/rust.ai/agents/bear/bear.prefab"] = "bear",
                    ["assets/rust.ai/agents/wolf/wolf.prefab"] = "wolf",
                    ["assets/rust.ai/agents/boar/boar.prefab"] = "boar",
                    ["assets/rust.ai/agents/chicken/chicken.prefab"] = "chicken"
                };

                // Отключаем стандартный спавн
                var count = 0;
                foreach (var entity in BaseNetworkable.serverEntities.OfType<BaseAnimalNPC>())
                {
                    entity.Kill();
                    count++;
                }
                PrintWarning($"[AnimalSpawner] Удалено {count} существующих животных");

                // Сразу спавним первую партию животных
                CheckAndSpawnAnimals();

                // Устанавливаем таймер на регулярную проверку спавна
                timer.Every(configData.SpawnCheckInterval, () => {
                    CheckAndSpawnAnimals();
                });

                // Устанавливаем таймер на подсчёт животных каждые 120 секунд
                timer.Every(120f, () => {
                    var stats = new Dictionary<string, int>();
                    var totalAnimals = 0;

                    // Подсчитываем количество каждого типа животных
                    foreach (var animalKvp in configData.Animals)
                    {
                        string animalName = animalKvp.Key;
                        var count = BaseNetworkable.serverEntities.OfType<BaseAnimalNPC>().Count(x => x.ShortPrefabName.Contains(animalName));
                        stats[animalName] = count;
                        totalAnimals += count;
                    }

                    // Выводим статистику
                    PrintWarning($"[AnimalSpawner] Статистика животных на карте:");
                    foreach (var stat in stats)
                    {
                        PrintWarning($"[AnimalSpawner] {stat.Key}: {stat.Value}");
                    }
                    PrintWarning($"[AnimalSpawner] Всего животных: {totalAnimals}");
                });

                PrintWarning("[AnimalSpawner] Успешно инициализирован!");
            }
            catch (System.Exception ex)
            {
                PrintError($"[AnimalSpawner] Ошибка при инициализации плагина: {ex.Message}");
            }
        }

        object OnEntitySpawn(BaseAnimalNPC animal)
        {
            if (animal == null) return null;

            string prefabPath = animal.PrefabName;
            if (animalPrefabMap.ContainsKey(prefabPath))
            {
                // Отменяем стандартный спавн
                NextTick(() => {
                    if (animal != null && !animal.IsDestroyed)
                    {
                        animal.Kill();
                    }
                });
                return true; // Блокируем спавн
            }

            return null;
        }

        void OnEntityDeath(BaseAnimalNPC animal, HitInfo info)
        {
            if (animal == null) return;

            // Запускаем проверку спавна при смерти животного
            timer.Once(1f, () => CheckAndSpawnAnimals());
        }

        private void CheckAndSpawnAnimals()
        {
            if (configData?.Animals == null)
            {
                PrintError("Конфигурация отсутствует или повреждена!");
                return;
            }

            foreach (var animalKvp in configData.Animals)
            {
                string animalName = animalKvp.Key;
                AnimalConfig config = animalKvp.Value;

                // Подсчет текущего количества животных данного типа
                var currentAmount = BaseNetworkable.serverEntities.OfType<BaseAnimalNPC>().Count(x => x.ShortPrefabName.Contains(animalName));

                // Пытаемся создать животных, если их меньше максимума
                int attemptsLeft = config.MaxAmount - currentAmount;
                for (int i = 0; i < attemptsLeft; i++)
                {
                    float chance = UnityEngine.Random.value;
                    
                    if (chance <= config.SpawnChance)
                    {
                        if (SpawnAnimal(animalName, config))
                        {
                            currentAmount++;
                            PrintWarning($"[AnimalSpawner] Создано животное {animalName}");
                            // Небольшая задержка между спавном животных
                            if (i < attemptsLeft - 1)
                            {
                                timer.Once(0.5f, () => CheckAndSpawnAnimals());
                                return;
                            }
                        }
                    }
                }
            }
        }

        private bool SpawnAnimal(string animalName, AnimalConfig config)
        {
            // Получаем случайную позицию на карте
            Vector3 randomPos = GetRandomPosition(config);
            if (randomPos == Vector3.zero)
            {
                return false;
            }

            // Получаем правильный путь к префабу
            string prefabPath = $"assets/rust.ai/agents/{animalName}/{animalName}.prefab";
            
            // Создаем сущность с небольшой задержкой
            timer.Once(0.1f, () =>
            {
                var entity = GameManager.server.CreateEntity(prefabPath, randomPos);
                if (entity != null)
                {
                    entity.Spawn();
                }
                else
                {
                    PrintError($"[AnimalSpawner] Ошибка создания {animalName}");
                }
            });

            return true;
        }

        private Vector3 GetRandomPosition(AnimalConfig config)
        {
            var tries = 0;
            const int maxTries = 30;

            while (tries < maxTries)
            {
                var randomPoint = TerrainMeta.Position + new Vector3(
                    UnityEngine.Random.Range(-WorldSize/2f, WorldSize/2f),
                    0,
                    UnityEngine.Random.Range(-WorldSize/2f, WorldSize/2f)
                );

                float height = TerrainMeta.HeightMap.GetHeight(randomPoint);
                
                if (height <= 0f || height > 100f)
                {
                    tries++;
                    continue;
                }

                randomPoint.y = height + 0.5f;

                if (IsValidSpawnPoint(randomPoint))
                {
                    return randomPoint;
                }

                tries++;
            }

            return Vector3.zero;
        }

        private bool IsValidSpawnPoint(Vector3 position)
        {
            // Проверяем, что точка находится на земле и не в воде
            float water = TerrainMeta.WaterMap.GetHeight(position);
            float ground = TerrainMeta.HeightMap.GetHeight(position);
            
            // Упрощенные проверки
            if (position.y <= water || // Точка под водой
                position.y <= 0f || // Ниже уровня моря
                position.y > 100f) // Слишком высоко
            {
                return false;
            }

            // Проверяем наличие препятствий сверху с увеличенной дистанцией
            RaycastHit hit;
            if (GamePhysics.Trace(new Ray(position + new Vector3(0, 3f, 0), Vector3.down), 0f, out hit, 4f, LayerMask.GetMask("Terrain", "World")))
            {
                if (hit.distance > 3.5f) // Увеличенный допустимый просвет сверху
                {
                    return false;
                }
            }

            // Проверяем, нет ли построек рядом с увеличенной дистанцией
            var entities = new List<BaseEntity>();
            Vis.Entities<BaseEntity>(position, 3f, entities); // Уменьшена дистанция проверки построек
            bool hasBuildings = entities.Any(e => e is BuildingBlock || e is BuildingPrivlidge);
            
            return !hasBuildings;
        }

        [ChatCommand("animals")]
        private void CmdAnimals(BasePlayer player, string command, string[] args)
        {
            if (!player.IsAdmin) return;

            var message = "Текущее количество животных:\n";
            foreach (var animalKvp in configData.Animals)
            {
                string animalName = animalKvp.Key;
                var count = BaseNetworkable.serverEntities.OfType<BaseAnimalNPC>().Count(x => x.ShortPrefabName.Contains(animalName));
                message += $"{animalName}: {count}/{animalKvp.Value.MaxAmount}\n";
            }

            player.ChatMessage(message);
        }
    }
}

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