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

FREE BestRespawner : 1.0.9 1.0.9

Нет прав для скачивания
C#:
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Facepunch;
using Newtonsoft.Json;
using Oxide.Core;
using Rust;
using UnityEngine;
namespace Oxide.Plugins {
    [Info("BestRespawner", "l1berty", "1.0.9")]
    [Description("Плагин позволяет игрокам спавниться в случайной точке на карте")]
    internal class BestRespawner : RustPlugin {
        private const string PERMISSION_USE = "bestrespawner.use";
        // дефолтный пермишен
        private const int MASK_BIOME = (int)(TerrainBiome.Enum.Arid | TerrainBiome.Enum.Temperate | TerrainBiome.Enum.Tundra | TerrainBiome.Enum.Arctic);
        private const int MASK_SPLAT = (int)(TerrainSplat.Enum.Dirt | TerrainSplat.Enum.Snow | TerrainSplat.Enum.Sand | TerrainSplat.Enum.Rock | TerrainSplat.Enum.Grass | TerrainSplat.Enum.Forest | TerrainSplat.Enum.Stones | TerrainSplat.Enum.Gravel);
        private Coroutine findSpawnPosCoroutine;
        private readonly List<Vector3> spawnPositionCache = new List<Vector3>();
        private List<Collider> colliders;
        private List<BaseEntity> entities;
        private List<BasePlayer> players;
#region Oxide Hooks
        private void Init() {
            colliders = Pool.GetList<Collider>();
            entities = Pool.GetList<BaseEntity>();
            players = Pool.GetList<BasePlayer>();
            permission.RegisterPermission(PERMISSION_USE, this);
        }
        private void OnServerInitialized() {
            findSpawnPosCoroutine = ServerMgr.Instance.StartCoroutine(FindSpawnPositions(5000));
        }
        private void Unload() {
            Pool.Free(ref entities);
            Pool.Free(ref colliders);
            Pool.Free(ref players);
            if (findSpawnPosCoroutine != null) {
                ServerMgr.Instance.StopCoroutine(findSpawnPosCoroutine);
            }
        }
        private IEnumerator FindSpawnPositions(int attempts = 1500)  // поиск точек спавна
        {
            List<Vector3> list = Pool.GetList<Vector3>();
            float mapSizeX = TerrainMeta.Size.x / 2;
            float mapSizeZ = TerrainMeta.Size.z / 2;
            Vector3 randomPos = Vector3.zero;
            for (int i = 0; i < attempts; i++) {
                randomPos.x = UnityEngine.Random.Range(-mapSizeX, mapSizeX);
                randomPos.z = UnityEngine.Random.Range(-mapSizeZ, mapSizeZ);
                if (TestPos(ref randomPos)) {
                    list.Add(randomPos);
                }
                if (i % 20 == 0) yield return CoroutineEx.waitForEndOfFrame;
            }
            spawnPositionCache.AddRange(list);
            PrintWarning($"Удачно найдено {list.Count} точек спавна игроков.");
            Pool.FreeList(ref list);
            findSpawnPosCoroutine = null;
        }
        private object OnPlayerRespawn(BasePlayer player)  // проверка
        {
            if (!permission.UserHasPermission(player.UserIDString, PERMISSION_USE)) {
                return null;
            }
            var spawnPos = GetRandomSpawnPos();
            // неудача
            if (!spawnPos.HasValue) {
                PrintWarning("Невозможно сгенерировать случайные точки спавына, превышен лимит, спавню по дефолту");
                return null;
            }
            if (Interface.CallHook("OnRandomRespawn", player, spawnPos.Value) != null) {
                return null;
            }
            return new BasePlayer.SpawnPoint {
                pos = spawnPos.Value,
            }
            ;
        }
#endregion Oxide Hooks
        private Vector3? GetRandomSpawnPos()  // основная функция плагина
        {
            for (int i = 0; i < configData.maxAttempts; i++) {
                if (spawnPositionCache.Count <= 0) return null;
                var spawnPos = spawnPositionCache.GetRandom();
                if (TestPosAgain(spawnPos)) {
                    return spawnPos;
                }
                spawnPositionCache.Remove(spawnPos);
                if (spawnPositionCache.Count < 50 && findSpawnPosCoroutine == null) {
                    findSpawnPosCoroutine = ServerMgr.Instance.StartCoroutine(FindSpawnPositions());
                }
            }
            return null;
        }
        private bool TestPos(ref Vector3 randomPos) {
            RaycastHit hitInfo;
            if (!Physics.Raycast(randomPos + Vector3.up * 300f, Vector3.down, out hitInfo, 400f, Layers.Solid) || hitInfo.GetEntity() != null) {
                return false;
            }
            randomPos.y = hitInfo.point.y;
            var slope = GetPosSlope(randomPos);
            if (slope < configData.minSlope || slope > configData.maxSlope) {
                return false;
            }
            bool flag;
            var biome = GetPosBiome(randomPos);
            if (configData.biomes.TryGetValue(biome, out flag) && !flag) {
                return false;
            }
            var splat = GetPosSplat(randomPos);
            if (configData.splats.TryGetValue(splat, out flag) && !flag) {
                return false;
            }
            if (AntiHack.TestInsideTerrain(randomPos)) {
                return false;
            }
            if (!ValidBounds.Test(randomPos)) {
                return false;
            }
            return TestPosAgain(randomPos);
        }
        private bool TestPosAgain(Vector3 spawnPos) {
            if (WaterLevel.Test(spawnPos)) {
                return false;
            }
            colliders.Clear();
            Vis.Colliders(spawnPos, 3f, colliders);
            foreach (var collider in colliders) {
                switch (collider.gameObject.layer) {
                    case (int)Layer.Prevent_Building : if (configData.preventSpawnAtMonument) {
                        return false;
                    }
                    break;
                    case (int)Layer.Vehicle_Large :  // тестирование карго
                    case (int)Layer.Vehicle_World : case (int)Layer.Vehicle_Detailed : return false;
                }
                if (configData.preventSpawnAtZone && collider.name.Contains("zonemanager", CompareOptions.IgnoreCase))  // в конфиге - зона
                {
                    return false;
                }
                if (configData.preventSpawnAtRadZone && collider.name.Contains("radiation", CompareOptions.IgnoreCase))  // в конфиге - рад. зона
                {
                    return false;
                }
                if (collider.name.Contains("fireball", CompareOptions.IgnoreCase) || collider.name.Contains("iceberg", CompareOptions.IgnoreCase) || collider.name.Contains("ice_sheet", CompareOptions.IgnoreCase)) {
                    return false;
                }
            }
            if (configData.radiusFromPlayers > 0)  // настройка радиуса спавна от других игроков (Настройка в конфиге)
            {
                players.Clear();
                Vis.Entities(spawnPos, configData.radiusFromPlayers, players, Layers.Mask.Player_Server);
                foreach (var player in players) {
                    if (!player.IsSleeping()) {
                        return false;
                    }
                }
            }
            if (configData.radiusFromBuilding > 0)  // настройка радиуса спавна от построек (Настройка в конфиге)
            {
                entities.Clear();
                Vis.Entities(spawnPos, configData.radiusFromBuilding, entities, Layers.PlayerBuildings);
                if (entities.Any()) return false;
            }
            return true;
        }
#region Helpers
        private static TerrainBiome.Enum GetPosBiome(Vector3 position) => (TerrainBiome.Enum)TerrainMeta.BiomeMap.GetBiomeMaxType(position, MASK_BIOME);
        private static TerrainSplat.Enum GetPosSplat(Vector3 position) => (TerrainSplat.Enum)TerrainMeta.SplatMap.GetSplatMaxType(position, MASK_SPLAT);
        private static float GetPosSlope(Vector3 position) => TerrainMeta.HeightMap.GetSlope(position);
#endregion Helpers
#region ConfigurationFile
        private ConfigData configData;
        private class ConfigData {
            [JsonProperty(PropertyName = "Максимальное кол-во попыток респавна")]
            public int maxAttempts = 200;
            [JsonProperty(PropertyName = "Мин. дистанция респавна от других игроков (НПС включительно)")]
            public float radiusFromPlayers = 20.0f;
            [JsonProperty(PropertyName = "Мин. дистанция респавна от построек других игроков")]
            public float radiusFromBuilding = 20.0f;
            [JsonProperty(PropertyName = "Запретить игрокам спавниться в постройках")]
            public bool preventSpawnAtMonument = true;
            [JsonProperty(PropertyName = "Запретить игрокам спавниться за зоной")]
            public bool preventSpawnAtZone = true;
            [JsonProperty(PropertyName = "Запретить игрокам спавниться в Рад. Зоне")]
            public bool preventSpawnAtRadZone = true;
            [JsonProperty(PropertyName = "Минимальный уклон (Не знаешь - не трогай)")]
            public float minSlope = 0f;
            [JsonProperty(PropertyName = "Максимальный уклон (Не знаешь - не трогай)")]
            public float maxSlope = 60f;
            [JsonProperty(PropertyName = "Настройка биомов")]
            // Для спавна в определённом биоме (true - спавнить, false - нет)
            public Dictionary<TerrainBiome.Enum, bool> biomes = new Dictionary<TerrainBiome.Enum, bool> {
                [TerrainBiome.Enum.Arid]
                = true, [TerrainBiome.Enum.Temperate] = true, [TerrainBiome.Enum.Tundra] = true, [TerrainBiome.Enum.Arctic] = true,
            }
            ;
            [JsonProperty(PropertyName = "Настройка поверхностей")]
            // Для запрета спавна на любой поверхности (Точки не будут генерироваться)
            public Dictionary<TerrainSplat.Enum, bool> splats = new Dictionary<TerrainSplat.Enum, bool> {
                [TerrainSplat.Enum.Dirt]
                = true, [TerrainSplat.Enum.Snow] = true, [TerrainSplat.Enum.Sand] = true, [TerrainSplat.Enum.Rock] = true, [TerrainSplat.Enum.Grass] = true, [TerrainSplat.Enum.Forest] = true, [TerrainSplat.Enum.Stones] = true, [TerrainSplat.Enum.Gravel] = true,
            }
            ;
        }
        protected override void LoadConfig()  // последние штрихи
        {
            base.LoadConfig();
            try {
                configData = Config.ReadObject<ConfigData>();
                if (configData == null) LoadDefaultConfig();
            }
            catch {
                PrintError("Конфигурационный файл повреждён!");
                LoadDefaultConfig();
            }
            SaveConfig();
        }
        protected override void LoadDefaultConfig() {
            PrintWarning("Создание нового конфигурационного файла!");
            configData = new ConfigData();
        }
        protected override void SaveConfig() => Config.WriteObject(configData);
#endregion ConfigurationFile
    }
}

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