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

FREE RaidableShelters : 1.0.2 1.0.2

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
/*
 * Copyright (C) 2024 Game4Freak.io
 * This mod is provided under the Game4Freak EULA.* Full legal terms can be found at https://game4freak.io/eula/
 */

/*v1.0.1 - Added random skin lists for entities, added raidme skin to door, added custom item names if needed.*cont - Added TruePve Support
 * v1.0.2 - Added a Player Notification Message on Shelter Spawn.*/

using Facepunch;
using Newtonsoft.Json;
using Oxide.Core;
using Rust;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Oxide.Core.Plugins;
using UnityEngine;
using Random = UnityEngine.Random;

namespace Oxide.Plugins
{
    [Info("Raidable Shelters", "VisEntities", "1.0.2")]
    [Description("Spawns shelters filled with loot for players to raid.")]
    public class RaidableShelters : RustPlugin
    {
        
        [PluginReference] private Plugin TruePVE;
        
        #region Fields

        private static RaidableShelters _plugin;
        private static Configuration _config;

        private System.Random _randomGenerator = new System.Random();
        private Timer _sheltersRespawnTimer;
        private Dictionary<LegacyShelter, List<BaseEntity>> _spawnedShelters = new Dictionary<LegacyShelter, List<BaseEntity>>();
        
        private const int LAYER_TERRAIN = Layers.Mask.Terrain;
        private const int LAYER_ENTITIES = Layers.Mask.Deployed | Layers.Mask.Construction;
        private const string PREFAB_LEGACY_SHELTER = "assets/prefabs/building/legacy.shelter.wood/legacy.shelter.wood.deployed.prefab";
        private const float SPAWNABLE_AREA_RADIUS_INSIDE_SHELTER = 1.7f;

        #endregion Fields

        #region Configuration

        private class Configuration
        {
            [JsonProperty("Version")]
            public string Version { get; set; }

            [JsonProperty("Number Of Attempts To Find Shelter Position Near Players")]
            public int NumberOfAttemptsToFindShelterPositionNearPlayers { get; set; }

            [JsonProperty("Minimum Search Radius For Shelter Position Around Player")]
            public float MinimumSearchRadiusForShelterPositionAroundPlayer { get; set; }

            [JsonProperty("Maximum Search Radius For Shelter Position Around Player")]
            public float MaximumSearchRadiusForShelterPositionAroundPlayer { get; set; }

            [JsonProperty("Shelters Respawn Frequency Minutes")]
            public float SheltersRespawnFrequencyMinutes { get; set; }

            [JsonProperty("Delay Between Each Shelter Spawn Seconds")]
            public float DelayBetweenEachShelterSpawnSeconds { get; set; }

            [JsonProperty("Nearby Entities Avoidance Radius")]
            public float NearbyEntitiesAvoidanceRadius { get; set; }

            [JsonProperty("Rocks Avoidance Radius")]
            public float RocksAvoidanceRadius { get; set; }

            [JsonProperty("Distance From No Build Zones")]
            public float DistanceFromNoBuildZones { get; set; }

            [JsonProperty("Shelter Lifetime Seconds")]
            public float ShelterLifetimeSeconds { get; set; }

            [JsonProperty("Number Of Attempts For Determining Entity Position Inside Shelter")]
            public int NumberOfAttemptsForDeterminingEntityPositionInsideShelter { get; set; }

            [JsonProperty("Number Of Attempts For Determining Entity Rotation Inside Shelter")]
            public int NumberOfAttemptsForDeterminingEntityRotationInsideShelter { get; set; }

            [JsonProperty("Interior Entities")]
            public List<InteriorEntityConfig> InteriorEntities { get; set; }

            [JsonProperty("Items To Spawn Inside Entity Containers")]
            public List<ItemInfo> ItemsToSpawnInsideEntityContainers { get; set; }
        }

        public class InteriorEntityConfig
        {
            [JsonProperty("Prefab Name")]
            public string PrefabName { get; set; }

            [JsonProperty("Skin Id")]
            public ulong[] SkinId { get; set; }

            [JsonProperty("Minimum Number To Spawn")]
            public int MinimumNumberToSpawn { get; set; }

            [JsonProperty("Maximum Number To Spawn")]
            public int MaximumNumberToSpawn { get; set; }

            [JsonProperty("Percentage To Fill Container With Items If Present")]
            public int PercentageToFillContainerWithItemsIfPresent { get; set; }
        }

        public class ItemInfo
        {
            [JsonProperty("Shortname")]
            public string Shortname { get; set; }
            
            [JsonProperty("Custom Name")]
            public string CustomName { get; set; } //Adding Custom Name

            [JsonProperty("Skin Id")]
            public ulong SkinId { get; set; }

            [JsonProperty("Minimum Amount")]
            public int MinimumAmount { get; set; }

            [JsonProperty("Maximum Amount")]
            public int MaximumAmount { get; set; }
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            _config = Config.ReadObject<Configuration>();

            if (string.Compare(_config.Version, Version.ToString()) < 0)
                UpdateConfig();

            SaveConfig();
        }

        protected override void LoadDefaultConfig()
        {
            _config = GetDefaultConfig();
        }

        protected override void SaveConfig()
        {
            Config.WriteObject(_config, true);
        }

        private void UpdateConfig()
        {
            PrintWarning("Config changes detected! Updating...");

            Configuration defaultConfig = GetDefaultConfig();

            if (string.Compare(_config.Version, "1.0.0") < 0)
                _config = defaultConfig;

            PrintWarning("Config update complete! Updated from version " + _config.Version + " to " + Version.ToString());
            _config.Version = Version.ToString();
        }

        private Configuration GetDefaultConfig()
        {
            return new Configuration
            {
                Version = Version.ToString(),
                NumberOfAttemptsToFindShelterPositionNearPlayers = 5,
                MinimumSearchRadiusForShelterPositionAroundPlayer = 20f,
                MaximumSearchRadiusForShelterPositionAroundPlayer = 50f,
                NearbyEntitiesAvoidanceRadius = 6f,
                RocksAvoidanceRadius = 5f,
                DistanceFromNoBuildZones = 10f,
                ShelterLifetimeSeconds = 600f,
                NumberOfAttemptsForDeterminingEntityPositionInsideShelter = 30,
                NumberOfAttemptsForDeterminingEntityRotationInsideShelter = 30,
                SheltersRespawnFrequencyMinutes = 60f,
                DelayBetweenEachShelterSpawnSeconds = 5f,
                InteriorEntities = new List<InteriorEntityConfig>
                {
                    new InteriorEntityConfig
                    {
                        PrefabName = "assets/prefabs/deployable/woodenbox/woodbox_deployed.prefab",
                        SkinId = new ulong[] {3235609440, 3215453447, 3189116172},
                        MinimumNumberToSpawn = 1,
                        MaximumNumberToSpawn = 3,
                        PercentageToFillContainerWithItemsIfPresent = 20,
                    },
                    new InteriorEntityConfig
                    {
                        PrefabName = "assets/prefabs/deployable/furnace/furnace.prefab",
                        SkinId = new ulong[] {1575177513, 1458047080, 1630511618},
                        MinimumNumberToSpawn = 1,
                        MaximumNumberToSpawn = 1,
                        PercentageToFillContainerWithItemsIfPresent = 0,
                    },
                },
                ItemsToSpawnInsideEntityContainers = new List<ItemInfo>()
                {
                    new ItemInfo
                    {
                        Shortname = "fat.animal",
                        CustomName = "",
                        SkinId = 0,
                        MinimumAmount = 10,
                        MaximumAmount = 25,
                    },
                    new ItemInfo
                    {
                        Shortname = "cloth",
                        CustomName = "",
                        SkinId = 0,
                        MinimumAmount = 20,
                        MaximumAmount = 30,
                    },
                    new ItemInfo
                    {
                        Shortname = "wood",
                        CustomName = "",
                        SkinId = 0,
                        MinimumAmount = 200,
                        MaximumAmount = 400,
                    },
                    new ItemInfo
                    {
                        Shortname = "syringe.medical",
                        CustomName = "",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 2,
                    },
                    new ItemInfo
                    {
                        Shortname = "rope",
                        CustomName = "",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 3,
                    },
                    new ItemInfo
                    {
                        Shortname = "cctv.camera",
                        CustomName = "",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 1,
                    },
                    new ItemInfo
                    {
                        Shortname = "roadsigns",
                        CustomName = "",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 2,
                    },
                    new ItemInfo
                    {
                        Shortname = "stones",
                        CustomName = "",
                        SkinId = 0,
                        MinimumAmount = 150,
                        MaximumAmount = 350,
                    },
                    new ItemInfo
                    {
                        Shortname = "metal.fragments",
                        CustomName = "",
                        SkinId = 0,
                        MinimumAmount = 30,
                        MaximumAmount = 90,
                    },
                    new ItemInfo
                    {
                        Shortname = "ammo.grenadelauncher.he",
                        CustomName = "",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 2,
                    },
                    new ItemInfo
                    {
                        Shortname = "coffeecan.helmet",
                        CustomName = "",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 1,
                    },
                    new ItemInfo
                    {
                        Shortname = "scrap",
                        CustomName = "",
                        SkinId = 0,
                        MinimumAmount = 10,
                        MaximumAmount = 25,
                    },
                    new ItemInfo
                    {
                        Shortname = "icepick.salvaged",
                        CustomName = "",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 1,
                    },
                    new ItemInfo
                    {
                        Shortname = "ptz.cctv.camera",
                        CustomName = "",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 1,
                    },
                    new ItemInfo
                    {
                        Shortname = "corn",
                        CustomName = "",
                        SkinId = 0,
                        MinimumAmount = 3,
                        MaximumAmount = 5,
                    },
                    new ItemInfo
                    {
                        Shortname = "ammo.rocket.mlrs",
                        CustomName = "",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 1,
                    },
                    new ItemInfo
                    {
                        Shortname = "wall.frame.garagedoor",
                        CustomName = "",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 1,
                    },
                    new ItemInfo
                    {
                        Shortname = "pistol.revolver",
                        CustomName = "",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 1,
                    },
                }
            };
        }

        #endregion Configuration

        #region Oxide Hooks

        private void Init()
        {
            _plugin = this;
        }

        private void Unload()
        {
            if (_sheltersRespawnTimer != null)
                _sheltersRespawnTimer.Destroy();

            CoroutineUtil.StopAllCoroutines();
            KillAllShelters();
            _config = null;
            _plugin = null;
        }

        private void OnServerInitialized(bool isStartup)
        {
            _sheltersRespawnTimer = timer.Every(_config.SheltersRespawnFrequencyMinutes * 60f, () =>
            {
                CoroutineUtil.StartCoroutine("RespawnSheltersCoroutine", RespawnSheltersCoroutine());
            });
        }

        #endregion Oxide Hooks

        #region Shelters Spawning and Setup

        private IEnumerator RespawnSheltersCoroutine()
        {
            foreach (BasePlayer player in BasePlayer.activePlayerList)
            {
                if (player != null && !PlayerUtil.Wounded(player) && !PlayerUtil.Sleeping(player) && !PlayerUtil.InBase(player)
                    && !PlayerUtil.Swimming(player) && !PlayerUtil.Boating(player) && !PlayerUtil.Flying(player) && PlayerUtil.OnGround(player)
                    && !PlayerUtil.NearEnemyBase(player) && !TerrainUtil.InRadTown(player.transform.position))
                {
                    Vector3 shelterPosition;
                    Quaternion shelterRotation;

                    if (TryFindSuitableShelterSpawnPoint(player.transform.position, _config.MinimumSearchRadiusForShelterPositionAroundPlayer, _config.MaximumSearchRadiusForShelterPositionAroundPlayer,
                        _config.NumberOfAttemptsToFindShelterPositionNearPlayers, out shelterPosition, out shelterRotation))
                    {
                        LegacyShelter shelter = SpawnLegacyShelter(shelterPosition, shelterRotation, player);
                    }
                }

                yield return CoroutineEx.waitForSeconds(_config.DelayBetweenEachShelterSpawnSeconds);
            }
        }

        private bool TryFindSuitableShelterSpawnPoint(Vector3 center, float minSearchRadius, float maxSearchRadius, int maxAttempts, out Vector3 suitablePosition, out Quaternion suitableRotation)
        {
            for (int attempt = 0; attempt < maxAttempts; attempt++)
            {
                Vector3 position = TerrainUtil.GetRandomPositionAround(center, minSearchRadius, maxSearchRadius);

                if (!TerrainUtil.InsideRock(position, _config.RocksAvoidanceRadius) && !TerrainUtil.InRadTown(position)
                    && !TerrainUtil.HasEntityNearby(position, _config.NearbyEntitiesAvoidanceRadius, LAYER_ENTITIES)
                    && !PlayerUtil.HasPlayerNearby(position, _config.NearbyEntitiesAvoidanceRadius)
                    && !TerrainUtil.InWater(position) && !TerrainUtil.OnRoadOrRail(position)
                    && TerrainUtil.OnTerrain(position, 4f) && !TerrainUtil.InNoBuildZone(position, _config.DistanceFromNoBuildZones))
                {
                    RaycastHit groundHit;
                    if (TerrainUtil.GetGroundInfo(position, out groundHit, 5f, LAYER_TERRAIN))
                    {
                        suitablePosition = groundHit.point;

                        Quaternion surfaceRotation = Quaternion.FromToRotation(Vector3.up, groundHit.normal);
                        Quaternion randomYRotation = Quaternion.Euler(0, Random.Range(0, 360), 0);
                        suitableRotation = surfaceRotation * randomYRotation;

                        return true;
                    }
                }
            }

            suitablePosition = Vector3.zero;
            suitableRotation = Quaternion.identity;
            return false;
        }

        private LegacyShelter SpawnLegacyShelter(Vector3 position, Quaternion rotation, BasePlayer player)
        {
            LegacyShelter shelter = GameManager.server.CreateEntity(PREFAB_LEGACY_SHELTER, position, rotation) as LegacyShelter;
            if (shelter == null)
                return null;

            shelter.OnPlaced(player);
            shelter.Spawn();
            NotifyPlayer(player);
            shelter.EnableSaving(false);// Added incase of server crash
            if (TruePVE)
            {
                timer.Once(1f, () => shelter.OwnerID = 0); // Added for TruePVE Damage
            }
            // Set the lock owner id to 0 to prevent the player from opening the shelter door.LegacyShelterDoor shelterDoor = shelter.GetChildDoor();
            if (shelterDoor != null)
            {
                BaseLock baseLock = shelterDoor.GetSlot(BaseEntity.Slot.Lock) as BaseLock;
                if (baseLock != null)
                    baseLock.OwnerID = 0;
            }
            shelterDoor.skinID = 2058693041; //Setting as Raid Me Skin can make random cfg later if wanted.StartRemovalTimer(shelter, _config.ShelterLifetimeSeconds);
            _spawnedShelters[shelter] = new List<BaseEntity>();
            SpawnShelterInteriorEntities(shelter);

            return shelter;
        }
        
        private void NotifyPlayer(BasePlayer player)
        {
           player.ChatMessage("[<color=orange>Raidable Shelters</color>] An Abandoned Shelter has been detected near you!");
        }

        #endregion Shelters Spawning and Setup

        #region Interior Entities Spawning

        private void SpawnShelterInteriorEntities(LegacyShelter shelter)
        {
            Vector3 shelterCenter = shelter.transform.position;
            float spawnRadius = SPAWNABLE_AREA_RADIUS_INSIDE_SHELTER;

            foreach (InteriorEntityConfig interiorEntityConfig in _config.InteriorEntities)
            {
                int numberToSpawn = Random.Range(interiorEntityConfig.MinimumNumberToSpawn, interiorEntityConfig.MaximumNumberToSpawn + 1);

                for (int i = 0; i < numberToSpawn; i++)
                {
                    Vector3 randomPosition;
                    int maxPositionAttempts = _config.NumberOfAttemptsForDeterminingEntityPositionInsideShelter;
                    int maxRotationAttempts = _config.NumberOfAttemptsForDeterminingEntityRotationInsideShelter;

                    for (int posAttempt = 0; posAttempt < maxPositionAttempts; posAttempt++)
                    {
                        randomPosition = TerrainUtil.GetRandomPositionAround(shelterCenter, minimumRadius: 0f, maximumRadius: spawnRadius);

                        RaycastHit groundHit;
                        if (!TerrainUtil.GetGroundInfo(randomPosition, out groundHit, 2f, LAYER_TERRAIN))
                            continue;

                        randomPosition = groundHit.point;

                        for (int rotAttempt = 0; rotAttempt < maxRotationAttempts; rotAttempt++)
                        {
                            Quaternion surfaceRotation = Quaternion.FromToRotation(Vector3.up, groundHit.normal);
                            Quaternion randomYRotation = Quaternion.Euler(0, Random.Range(0, 360), 0);
                            Quaternion finalRotation = surfaceRotation * randomYRotation;

                            if (!EntityFitsInShelter(shelter, interiorEntityConfig.PrefabName, randomPosition, finalRotation))
                                continue;

                            BaseEntity entity = SpawnInteriorEntity(shelter, randomPosition, finalRotation, interiorEntityConfig);
                            if (entity == null)
                                continue;

                            posAttempt = maxPositionAttempts;
                            break;
                        }
                    }
                }
            }
        }

        private bool EntityFitsInShelter(LegacyShelter shelter, string prefabPath, Vector3 potentialPosition, Quaternion potentialRotation)
        {
            BaseEntity tempEntity = GameManager.server.CreateEntity(prefabPath, potentialPosition, potentialRotation, false);
            if (tempEntity == null)
                return false;

            OBB bounds = tempEntity.WorldSpaceBounds();
            tempEntity.Kill();

            Vector3[] corners = new Vector3[8];
            corners[0] = bounds.GetPoint(-1f, -1f, -1f);
            corners[1] = bounds.GetPoint(-1f, -1f, 1f);
            corners[2] = bounds.GetPoint(-1f, 1f, -1f);
            corners[3] = bounds.GetPoint(-1f, 1f, 1f);
            corners[4] = bounds.GetPoint(1f, -1f, -1f);
            corners[5] = bounds.GetPoint(1f, -1f, 1f);
            corners[6] = bounds.GetPoint(1f, 1f, -1f);
            corners[7] = bounds.GetPoint(1f, 1f, 1f);

            // Ensure the entity is within the shelter bounds and not clipping through or colliding with other objects inside.Collider[] colliders = Physics.OverlapBox(bounds.position, bounds.extents, bounds.rotation, LAYER_ENTITIES);
            foreach (Collider collider in colliders)
            {
                if (collider.gameObject != tempEntity.gameObject && collider.gameObject != shelter.gameObject)
                    return false;
            }

            return true;
        }

        private BaseEntity SpawnInteriorEntity(LegacyShelter shelter, Vector3 position, Quaternion rotation, InteriorEntityConfig interiorEntityConfig)
        {
            BaseEntity entity = GameManager.server.CreateEntity(interiorEntityConfig.PrefabName, position, rotation);
            if (entity == null)
                return null;

            entity.skinID = GetRandomSkinId(interiorEntityConfig.SkinId); // Adding a method for random skin lists per entity
            entity.Spawn();
            entity.EnableSaving(false); // Added incase of server crash
            RemoveProblematicComponents(entity);

            if (entity is StorageContainer storageContainer)
                PopulateItems(storageContainer.inventory, _config.ItemsToSpawnInsideEntityContainers, interiorEntityConfig.PercentageToFillContainerWithItemsIfPresent);

            _spawnedShelters[shelter].Add(entity);

            return entity;
        }

        private ulong GetRandomSkinId(ulong[] skinIds)
        { 
            var rnd = Random.Range(0, skinIds.Length); 
            return skinIds[rnd]; 
        }

        #endregion Interior Entities Spawning

        #region Entity Containers Filling

        private void PopulateItems(ItemContainer itemContainer, List<ItemInfo> items, int fillContainerPercentage)
        {
            Shuffle(items);
            int slotsToFill = Mathf.CeilToInt(itemContainer.capacity * (fillContainerPercentage / 100f));

            for (int i = 0; i < slotsToFill; i++)
            {
                if (i >= items.Count)
                    break;

                ItemInfo itemInfo = items[i];
                var itemDefinition = ItemManager.FindItemDefinition(itemInfo.Shortname);
                if (itemDefinition != null)
                {
                    int amountToAdd = Random.Range(itemInfo.MinimumAmount, itemInfo.MaximumAmount + 1);
                    Item item = ItemManager.Create(itemDefinition, amountToAdd, itemInfo.SkinId);
                    if (!string.IsNullOrWhiteSpace(itemInfo.CustomName))
                    {
                        item.name = itemInfo.CustomName; // Adding check for stack support if empty name
                    }
                    if (!item.MoveToContainer(itemContainer))
                    {
                        item.Remove();
                    }
                }
            }
        }

        #endregion Entity Container Filling

        #region Shelters Removal

        private void StartRemovalTimer(LegacyShelter shelter, float lifetimeSeconds)
        {
            timer.Once(lifetimeSeconds, () =>
            {
                if (shelter != null)
                {
                    if (_spawnedShelters.TryGetValue(shelter, out var entities))
                    {
                        foreach (BaseEntity entity in entities)
                        {
                            if (entity != null)
                                entity.Kill();
                        }
                        _spawnedShelters.Remove(shelter);
                    }
                    shelter.Kill();
                }
            });
        }

        private void KillAllShelters()
        {
            if (_spawnedShelters != null)
            {
                foreach (var kvp in _spawnedShelters)
                {
                    var shelter = kvp.Key;
                    var entities = kvp.Value;

                    if (shelter != null)
                    {
                        foreach (BaseEntity entity in entities)
                        {
                            if (entity != null)
                                entity.Kill();
                        }

                        shelter.Kill();
                    }
                }

                _spawnedShelters.Clear();
            }
        }

        #endregion Shelters Removal

        #region Helper Functions

        private static BaseEntity FindBaseEntityForPrefab(string prefabName)
        {
            var prefab = GameManager.server.FindPrefab(prefabName);
            if (prefab == null)
                return null;

            return prefab.GetComponent<BaseEntity>();
        }

        private static void Shuffle<T>(List<T> list)
        {
            int remainingItems = list.Count;

            while (remainingItems > 1)
            {
                remainingItems--;
                int randomIndex = _plugin._randomGenerator.Next(remainingItems + 1);

                T itemToSwap = list[randomIndex];
                list[randomIndex] = list[remainingItems];
                list[remainingItems] = itemToSwap;
            }
        }

        private static void RemoveProblematicComponents(BaseEntity entity)
        {
            UnityEngine.Object.DestroyImmediate(entity.GetComponent<DestroyOnGroundMissing>());
            UnityEngine.Object.DestroyImmediate(entity.GetComponent<GroundWatch>());
        }

        #endregion Helper Functions

        #region Helper Classes

        public static class TerrainUtil
        {
            public static bool OnTopology(Vector3 position, TerrainTopology.Enum topology)
            {
                return (TerrainMeta.TopologyMap.GetTopology(position) & (int)topology) != 0;
            }

            public static bool OnRoadOrRail(Vector3 position)
            {
                var combinedTopology = TerrainTopology.Enum.Road | TerrainTopology.Enum.Roadside |
                                   TerrainTopology.Enum.Rail | TerrainTopology.Enum.Railside;

                return OnTopology(position, combinedTopology);
            }

            public static bool OnTerrain(Vector3 position, float radius)
            {
                return Physics.CheckSphere(position, radius, LAYER_TERRAIN, QueryTriggerInteraction.Ignore);
            }

            public static bool InNoBuildZone(Vector3 position, float radius)
            {
                return Physics.CheckSphere(position, radius, Layers.Mask.Prevent_Building);
            }
            
            public static bool InWater(Vector3 position)
            {
                return WaterLevel.Test(position, false, false);
            }

            public static bool InsideRock(Vector3 position, float radius)
            {
                List<Collider> colliders = Pool.GetList<Collider>();
                Vis.Colliders(position, radius, colliders, Layers.Mask.World, QueryTriggerInteraction.Ignore);

                bool result = false;

                foreach (Collider collider in colliders)
                {
                    if (collider.name.Contains("rock", CompareOptions.OrdinalIgnoreCase)
                        || collider.name.Contains("cliff", CompareOptions.OrdinalIgnoreCase)
                        || collider.name.Contains("formation", CompareOptions.OrdinalIgnoreCase))
                    {
                        result = true;
                        break;
                    }
                }

                Pool.FreeList(ref colliders);
                return result;
            }
            
            public static bool InRadTown(Vector3 position, bool shouldDisplayOnMap = false)
            {
                foreach (var monumentInfo in TerrainMeta.Path.Monuments)
                {
                    bool inBounds = monumentInfo.IsInBounds(position);

                    bool hasLandMarker = true;
                    if (shouldDisplayOnMap)
                        hasLandMarker = monumentInfo.shouldDisplayOnMap;

                    if (inBounds && hasLandMarker)
                        return true;
                }

                return OnTopology(position, TerrainTopology.Enum.Monument);
            }

            public static bool HasEntityNearby(Vector3 position, float radius, LayerMask mask, string prefabName = null)
            {
                List<Collider> hitColliders = Pool.GetList<Collider>();
                GamePhysics.OverlapSphere(position, radius, hitColliders, mask, QueryTriggerInteraction.Ignore);

                bool hasEntityNearby = false;
                foreach (Collider collider in hitColliders)
                {
                    BaseEntity entity = collider.gameObject.ToBaseEntity();
                    if (entity != null)
                    {
                        if (prefabName == null || entity.PrefabName == prefabName)
                        {
                            hasEntityNearby = true;
                            break;
                        }
                    }
                }

                Pool.FreeList(ref hitColliders);
                return hasEntityNearby;
            }

            public static Vector3 GetRandomPositionAround(Vector3 center, float minimumRadius, float maximumRadius, bool adjustToWaterHeight = false)
            {
                Vector3 randomDirection = Random.onUnitSphere;
                float randomDistance = Random.Range(minimumRadius, maximumRadius);
                Vector3 randomPosition = center + randomDirection * randomDistance;

                if (adjustToWaterHeight)
                    randomPosition.y = TerrainMeta.WaterMap.GetHeight(randomPosition);
                else
                    randomPosition.y = TerrainMeta.HeightMap.GetHeight(randomPosition);

                return randomPosition;
            }

            public static bool GetGroundInfo(Vector3 startPosition, out RaycastHit raycastHit, float range, LayerMask mask)
            {
                return Physics.Linecast(startPosition + new Vector3(0.0f, range, 0.0f), startPosition - new Vector3(0.0f, range, 0.0f), out raycastHit, mask);
            }

            public static bool GetGroundInfo(Vector3 startPosition, out RaycastHit raycastHit, float range, LayerMask mask, Transform ignoreTransform = null)
            {
                startPosition.y += 0.25f;
                range += 0.25f;
                raycastHit = default;

                RaycastHit hit;
                if (!GamePhysics.Trace(new Ray(startPosition, Vector3.down), 0f, out hit, range, mask, QueryTriggerInteraction.UseGlobal, null))
                    return false;

                if (ignoreTransform != null && hit.collider != null
                    && (hit.collider.transform == ignoreTransform || hit.collider.transform.IsChildOf(ignoreTransform)))
                {
                    return GetGroundInfo(startPosition - new Vector3(0f, 0.01f, 0f), out raycastHit, range, mask, ignoreTransform);
                }

                raycastHit = hit;
                return true;
            }
        }

        private static class PlayerUtil
        {
            public static BasePlayer FindById(ulong playerId)
            {
                return RelationshipManager.FindByID(playerId);
            }

            public static bool HasPlayerNearby(Vector3 position, float radius)
            {
                return BaseNetworkable.HasCloseConnections(position, radius);
            }

            public static bool AreTeammates(ulong firstPlayerId, ulong secondPlayerId)
            {
                RelationshipManager.PlayerTeam team = RelationshipManager.ServerInstance.FindPlayersTeam(firstPlayerId);
                if (team != null && team.members.Contains(secondPlayerId))
                    return true;

                return false;
            }

            public static bool Sleeping(BasePlayer player)
            {
                return player != null && player.IsSleeping();
            }

            public static bool Swimming(BasePlayer player)
            {
                return player != null && player.IsSwimming();
            }

            public static bool Boating(BasePlayer player)
            {
                return player != null && player.isMounted && player.GetMounted().mountTimeStatType == BaseMountable.MountStatType.Boating;
            }

            public static bool Flying(BasePlayer player)
            {
                return player != null && player.isMounted && player.GetMounted().mountTimeStatType == BaseMountable.MountStatType.Flying;
            }

            public static bool Driving(BasePlayer player)
            {
                return player != null && player.isMounted && player.GetMounted().mountTimeStatType == BaseMountable.MountStatType.Driving;
            }

            public static bool InBase(BasePlayer player)
            {
                return player != null && player.IsBuildingAuthed();
            }

            public static bool NearEnemyBase(BasePlayer player)
            {
                return player != null && player.IsNearEnemyBase();
            }

            public static bool Wounded(BasePlayer player)
            {
                return player != null && player.IsWounded();
            }

            public static bool Crawling(BasePlayer player)
            {
                return player != null && player.IsCrawling();
            }

            public static bool OnGround(BasePlayer player)
            {
                return player != null && player.IsOnGround();
            }
        }

        public static class CoroutineUtil
        {
            private static readonly Dictionary<string, Coroutine> _activeCoroutines = new Dictionary<string, Coroutine>();

            public static void StartCoroutine(string coroutineName, IEnumerator coroutineFunction)
            {
                StopCoroutine(coroutineName);

                Coroutine coroutine = ServerMgr.Instance.StartCoroutine(coroutineFunction);
                _activeCoroutines[coroutineName] = coroutine;
            }

            public static void StopCoroutine(string coroutineName)
            {
                if (_activeCoroutines.TryGetValue(coroutineName, out Coroutine coroutine))
                {
                    if (coroutine != null)
                        ServerMgr.Instance.StopCoroutine(coroutine);

                    _activeCoroutines.Remove(coroutineName);
                }
            }

            public static void StopAllCoroutines()
            {
                foreach (string coroutineName in _activeCoroutines.Keys.ToArray())
                {
                    StopCoroutine(coroutineName);
                }
            }
        }

        #endregion Helper Classes

        #region TruePvE 
        
        //TruePVE Hook
        object CanEntityTakeDamage(BaseCombatEntity entity)
        {
            foreach (var (shelter, entities) in _spawnedShelters)
            {
                if (entity == shelter || entities.Contains(entity))
                { 
                    return true;
                }
            }
            return null;
        }
        
        #endregion
    }
}

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