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

FREE RaidableShelters : 1.7.3 1.7.3

Нет прав для скачивания
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/
 */

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

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

        private static RaidableShelters _plugin;
        private static Configuration _config;
        private StoredData _storedData;

        private System.Random _randomGenerator = new System.Random();
        private Timer _sheltersRespawnTimer;

        private const int LAYER_GROUND = Layers.Mask.Terrain | Layers.Mask.World | Layers.Mask.Default;
        private const int LAYER_PLAYERS = Layers.Mask.Player_Server;
        private const int LAYER_ENTITIES = Layers.Mask.Deployed | Layers.Mask.Construction;

        private const string PREFAB_AUTO_TURRET = "assets/prefabs/npc/autoturret/autoturret_deployed.prefab";
        private const string PREFAB_LEGACY_SHELTER = "assets/prefabs/building/legacy.shelter.wood/legacy.shelter.wood.deployed.prefab";
        private const string PREFAB_LANDMINE = "assets/prefabs/deployable/landmine/landmine.prefab";
        private const string PREFAB_BEAR_TRAP = "assets/prefabs/deployable/bear trap/beartrap.prefab";

        private const float SPAWNABLE_AREA_RADIUS_INSIDE_SHELTER = 1.7f;

        private static readonly Vector3 _autoTurretPosition = new Vector3(0.084f, 3.146f, 0.481f);
        private static readonly Vector3 _autoTurretRotation = new Vector3(355.103f, 0f, 0f);

        #endregion Fields

        #region Configuration

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

            [JsonProperty("Enable Debug")]
            public bool EnableDebug { 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 Health")]
            public float ShelterHealth { 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("Door")]
            public DoorConfig Door { get; set; }

            [JsonProperty("Turret")]
            public TurretConfig Turret { get; set; }

            [JsonProperty("Trap")]
            public TrapConfig Trap { get; set; }

            [JsonProperty("Notification")]
            public NotificationConfig Notification { 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 DoorConfig
        {
            [JsonProperty("Skin Ids")]
            public List<ulong> SkinIds { get; set; }
        }

        public class TurretConfig
        {
            [JsonProperty("Spawn Auto Turret")]
            public bool SpawnAutoTurret { get; set; }

            [JsonProperty("Health")]
            public float Health { get; set; }

            [JsonProperty("Weapon Short Name")]
            public string WeaponShortName { get; set; }

            [JsonProperty("Clip Ammo")]
            public ItemInfo ClipAmmo { get; set; }

            [JsonProperty("Reserve Ammo")]
            public List<ItemInfo> ReserveAmmo { get; set; }

            [JsonProperty("Attachment Short Names")]
            public List<string> AttachmentShortNames { get; set; }

            [JsonProperty("Peacekeeper")]
            public bool Peacekeeper { get; set; }
        }

        public class TrapConfig
        {
            [JsonProperty("Spawn Landmines")]
            public bool SpawnLandmines { get; set; }

            [JsonProperty("Spawn Bear Traps")]
            public bool SpawnBearTraps { get; set; }

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

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

            [JsonProperty("Minimum Spawn Radius Around Shelter")]
            public float MinimumSpawnRadiusAroundShelter { get; set; }

            [JsonProperty("Maximum Spawn Radius Around Shelter")]
            public float MaximumSpawnRadiusAroundShelter { get; set; }
        }

        public class NotificationConfig
        {
            [JsonProperty("Notify Surrounding Players Of Shelter Spawn")]
            public bool NotifySurroundingPlayersOfShelterSpawn { get; set; }

            [JsonProperty("Radius For Notifying Nearby Players")]
            public float RadiusForNotifyingNearbyPlayers { get; set; }

            [JsonProperty("Send As Toast")]
            public bool SendAsToast { get; set; }
        }

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

            [JsonProperty("Skin Ids")]
            public List<ulong> SkinIds { get; set; }

            [JsonProperty("Spawn Chance")]
            public int SpawnChance { 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("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;

            if (string.Compare(_config.Version, "1.1.0") < 0)
            {
                _config.Notification = defaultConfig.Notification;

                foreach (InteriorEntityConfig interiorEntityConfig in _config.InteriorEntities)
                {
                    interiorEntityConfig.SkinIds = new List<ulong>();
                }
            }

            if (string.Compare(_config.Version, "1.2.0") < 0)
            {
                _config.Door = defaultConfig.Door;
            }

            if (string.Compare(_config.Version, "1.3.0") < 0)
            {
                foreach (InteriorEntityConfig interiorEntityConfig in _config.InteriorEntities)
                {
                    interiorEntityConfig.SpawnChance = 50;
                }
            }

            if (string.Compare(_config.Version, "1.4.0") < 0)
            {
                _config.EnableDebug = defaultConfig.EnableDebug;
            }

            if (string.Compare(_config.Version, "1.5.0") < 0)
            {
                _config.ShelterHealth = defaultConfig.ShelterHealth;
            }

            if (string.Compare(_config.Version, "1.6.0") < 0)
            {
                _config.Turret = defaultConfig.Turret;
            }

            if (string.Compare(_config.Version, "1.7.0") < 0)
            {
                _config.Trap = defaultConfig.Trap;
            }

            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(),
                EnableDebug = false,
                NumberOfAttemptsToFindShelterPositionNearPlayers = 5,
                MinimumSearchRadiusForShelterPositionAroundPlayer = 20f,
                MaximumSearchRadiusForShelterPositionAroundPlayer = 50f,
                NearbyEntitiesAvoidanceRadius = 6f,
                RocksAvoidanceRadius = 5f,
                DistanceFromNoBuildZones = 10f,
                ShelterHealth = 500f,
                ShelterLifetimeSeconds = 600f,
                NumberOfAttemptsForDeterminingEntityPositionInsideShelter = 30,
                NumberOfAttemptsForDeterminingEntityRotationInsideShelter = 30,
                SheltersRespawnFrequencyMinutes = 60f,
                DelayBetweenEachShelterSpawnSeconds = 5f,
                Door = new DoorConfig
                {
                    SkinIds = new List<ulong>
                    {
                        809253752,
                        2246937402,
                        2483070538,
                        3076134051
                    }
                },
                Turret = new TurretConfig
                {
                    SpawnAutoTurret = false,
                    Health = 1000f,
                    WeaponShortName = "rifle.ak",
                    ClipAmmo = new ItemInfo
                    {
                        ShortName = "ammo.rifle",
                        MinimumAmount = 30,
                        MaximumAmount = 30
                    },
                    ReserveAmmo = new List<ItemInfo>
                    {
                        new ItemInfo
                        {
                            ShortName = "ammo.rifle",
                            MinimumAmount = 128,
                            MaximumAmount = 128
                        }
                    },
                    AttachmentShortNames = new List<string>
                    {
                        "weapon.mod.lasersight"
                    },
                    Peacekeeper = false,
                },
                Trap = new TrapConfig
                {
                    SpawnLandmines = false,
                    SpawnBearTraps = true,
                    MinimumSpawnRadiusAroundShelter = 3f,
                    MaximumSpawnRadiusAroundShelter = 5f,
                    MinimumNumberOfTrapsToSpawn = 1,
                    MaximumNumberOfTrapsToSpawn = 5
                },
                Notification = new NotificationConfig
                {
                    NotifySurroundingPlayersOfShelterSpawn = false,
                    RadiusForNotifyingNearbyPlayers = 40f,
                    SendAsToast = true
                },
                InteriorEntities = new List<InteriorEntityConfig>
                {
                    new InteriorEntityConfig
                    {
                        PrefabName = "assets/prefabs/deployable/woodenbox/woodbox_deployed.prefab",
                        SkinIds = new List<ulong>
                        {
                            0
                        },
                        SpawnChance = 50,
                        MinimumNumberToSpawn = 1,
                        MaximumNumberToSpawn = 3,
                        PercentageToFillContainerWithItemsIfPresent = 20,
                    },
                    new InteriorEntityConfig
                    {
                        PrefabName = "assets/prefabs/deployable/furnace/furnace.prefab",
                        SkinIds = new List<ulong>
                        {
                            0
                        },
                        SpawnChance = 50,
                        MinimumNumberToSpawn = 1,
                        MaximumNumberToSpawn = 1,
                        PercentageToFillContainerWithItemsIfPresent = 0,
                    },
                },
                ItemsToSpawnInsideEntityContainers = new List<ItemInfo>()
                {
                    new ItemInfo
                    {
                        ShortName = "fat.animal",
                        SkinId = 0,
                        MinimumAmount = 10,
                        MaximumAmount = 25,
                    },
                    new ItemInfo
                    {
                        ShortName = "cloth",
                        SkinId = 0,
                        MinimumAmount = 20,
                        MaximumAmount = 30,
                    },
                    new ItemInfo
                    {
                        ShortName = "wood",
                        SkinId = 0,
                        MinimumAmount = 200,
                        MaximumAmount = 400,
                    },
                    new ItemInfo
                    {
                        ShortName = "syringe.medical",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 2,
                    },
                    new ItemInfo
                    {
                        ShortName = "rope",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 3,
                    },
                    new ItemInfo
                    {
                        ShortName = "cctv.camera",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 1,
                    },
                    new ItemInfo
                    {
                        ShortName = "roadsigns",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 2,
                    },
                    new ItemInfo
                    {
                        ShortName = "stones",
                        SkinId = 0,
                        MinimumAmount = 150,
                        MaximumAmount = 350,
                    },
                    new ItemInfo
                    {
                        ShortName = "metal.fragments",
                        SkinId = 0,
                        MinimumAmount = 30,
                        MaximumAmount = 90,
                    },
                    new ItemInfo
                    {
                        ShortName = "ammo.grenadelauncher.he",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 2,
                    },
                    new ItemInfo
                    {
                        ShortName = "coffeecan.helmet",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 1,
                    },
                    new ItemInfo
                    {
                        ShortName = "scrap",
                        SkinId = 0,
                        MinimumAmount = 10,
                        MaximumAmount = 25,
                    },
                    new ItemInfo
                    {
                        ShortName = "icepick.salvaged",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 1,
                    },
                    new ItemInfo
                    {
                        ShortName = "ptz.cctv.camera",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 1,
                    },
                    new ItemInfo
                    {
                        ShortName = "corn",
                        SkinId = 0,
                        MinimumAmount = 3,
                        MaximumAmount = 5,
                    },
                    new ItemInfo
                    {
                        ShortName = "ammo.rocket.mlrs",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 1,
                    },
                    new ItemInfo
                    {
                        ShortName = "wall.frame.garagedoor",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 1,
                    },
                    new ItemInfo
                    {
                        ShortName = "pistol.revolver",
                        SkinId = 0,
                        MinimumAmount = 1,
                        MaximumAmount = 1,
                    },
                }
            };
        }

        #endregion Configuration

        #region Stored Data

        public class StoredData
        {
            [JsonProperty("Raidable Shelters")]
            public Dictionary<ulong, ShelterData> Shelters { get; set; } = new Dictionary<ulong, ShelterData>();
        }

        public class ShelterData
        {
            [JsonProperty("Interior Entities")]
            public List<ulong> InteriorEntities { get; set; } = new List<ulong>();

            [JsonProperty("Traps")]
            public List<ulong> Traps { get; set; } = new List<ulong>();

            [JsonProperty("Removal Timer")]
            public double RemovalTimer { get; set; }
        }

        #endregion Stored Data

        #region Oxide Hooks

        private void Init()
        {
            _plugin = this;
            _storedData = DataFileUtil.LoadOrCreate<StoredData>(DataFileUtil.GetFilePath());
        }

        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());
            });

            ResumeShelterRemovalTimers();
        }

        #endregion Oxide Hooks

        #region True PVE Hooks

        private object CanEntityTakeDamage(LegacyShelter shelter)
        {
            if (shelter == null || !API_IsShelterRaidable(shelter))
                return null;

            return true;
        }

        #endregion True PVE 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);
                        if (shelter != null)
                        {
                            NotifyOfShelterSpawn(shelter, player);

                            if (_config.EnableDebug)
                                DrawDebugInfo(shelterPosition, "Shelter spawn successful", ParseColor("#27AE60"), 4f);
                        }
                    }
                }
                else if (_config.EnableDebug)
                {
                    string reason = "unknown reason";

                    if (PlayerUtil.Wounded(player))
                        reason = "player wounded";
                    else if (PlayerUtil.Sleeping(player))
                        reason = "player sleeping";
                    else if (PlayerUtil.InBase(player))
                        reason = "player in base";
                    else if (PlayerUtil.Swimming(player))
                        reason = "player swimming";
                    else if (PlayerUtil.Boating(player))
                        reason = "player boating";
                    else if (PlayerUtil.Flying(player))
                        reason = "player flying";
                    else if (!PlayerUtil.OnGround(player))
                        reason = "player not on ground";
                    else if (PlayerUtil.NearEnemyBase(player))
                        reason = "player near enemy base";
                    else if (TerrainUtil.InRadTown(player.transform.position))
                        reason = "player in radtown";

                    DrawDebugInfo(player.transform.position, $"Shelter spawn failed:\n{reason}", ParseColor("#E12126"));
                }

                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))
                {
                    if (_config.EnableDebug)
                        DrawDebugInfo(position, "Spawn failed:\nInside rock", ParseColor("#E12126"), _config.RocksAvoidanceRadius);
                    continue;
                }

                if (TerrainUtil.InRadTown(position))
                {
                    if (_config.EnableDebug)
                        DrawDebugInfo(position, "Spawn failed:\nIn radtown", ParseColor("#E12126"));
                    continue;
                }

                if (TerrainUtil.HasEntityNearby(position, _config.NearbyEntitiesAvoidanceRadius, LAYER_ENTITIES))
                {
                    if (_config.EnableDebug)
                        DrawDebugInfo(position, "Spawn failed:\nNearby entities", ParseColor("#E12126"), _config.NearbyEntitiesAvoidanceRadius);
                    continue;
                }

                if (PlayerUtil.HasPlayerNearby(position, _config.NearbyEntitiesAvoidanceRadius))
                {
                    if (_config.EnableDebug)
                        DrawDebugInfo(position, "Spawn failed:\nNearby players", ParseColor("#E12126"), _config.NearbyEntitiesAvoidanceRadius);
                    continue;
                }

                if (TerrainUtil.InWater(position))
                {
                    if (_config.EnableDebug)
                        DrawDebugInfo(position, "Spawn failed:\nIn water", ParseColor("#E12126"));
                    continue;
                }

                if (TerrainUtil.OnRoadOrRail(position))
                {
                    if (_config.EnableDebug)
                        DrawDebugInfo(position, "Spawn failed:\nOn road or rail", ParseColor("#E12126"));
                    continue;
                }

                if (!TerrainUtil.OnTerrain(position, 4f))
                {
                    if (_config.EnableDebug)
                        DrawDebugInfo(position, "Spawn failed:\nNot on terrain", ParseColor("#E12126"), 4f);
                    continue;
                }

                if (TerrainUtil.InNoBuildZone(position, _config.DistanceFromNoBuildZones))
                {
                    if (_config.EnableDebug)
                        DrawDebugInfo(position, "Spawn failed:\nIn no-build zone", ParseColor("#E12126"), _config.DistanceFromNoBuildZones);
                    continue;
                }

                RaycastHit groundHit;
                if (TerrainUtil.GetGroundInfo(position, out groundHit, 5f, LAYER_GROUND))
                {
                    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();

            shelter.InitializeHealth(_config.ShelterHealth, _config.ShelterHealth);
            shelter.SendNetworkUpdateImmediate();

            // Set the lock owner id to 0 to prevent the player from opening the shelter door.LegacyShelterDoor shelterDoor = shelter.GetChildDoor();
            if (shelterDoor != null)
            {
                shelterDoor.InitializeHealth(_config.ShelterHealth, _config.ShelterHealth);

                BaseLock baseLock = shelterDoor.GetSlot(BaseEntity.Slot.Lock) as BaseLock;
                if (baseLock != null)
                    baseLock.OwnerID = 0;

                if (_config.Door.SkinIds != null && _config.Door.SkinIds.Count > 0)
                {
                    shelterDoor.skinID = _config.Door.SkinIds[Random.Range(0, _config.Door.SkinIds.Count)];
                }
            }

            EntityPrivilege entityPrivilege = shelter.GetEntityPrivilege();
            if (entityPrivilege != null)
            {
                entityPrivilege.authorizedPlayers.Clear();
                entityPrivilege.SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
            }

            ShelterData shelterData = new ShelterData
            {
                RemovalTimer = Time.realtimeSinceStartup + _config.ShelterLifetimeSeconds
            };
            _storedData.Shelters[shelter.net.ID.Value] = shelterData;

            if (!SpawnShelterInteriorEntities(shelter, shelterData))
            {
                _storedData.Shelters.Remove(shelter.net.ID.Value);
                DataFileUtil.Save(DataFileUtil.GetFilePath(), _storedData);
                shelter.Kill();
                return null;
            }

            if (_config.Turret.SpawnAutoTurret)
                DeployAutoTurret(shelter, shelterData);

            if (_config.Trap.SpawnLandmines || _config.Trap.SpawnBearTraps)
                SpawnTrapsAroundShelter(shelter, shelterData);

            StartRemovalTimer(shelter, _config.ShelterLifetimeSeconds, shelterData);
            return shelter;
        }

        #endregion Shelters Spawning and Setup

        #region Shelter Spawn Notification

        private void NotifyOfShelterSpawn(LegacyShelter shelter, BasePlayer player)
        {
            if (_config.Notification.NotifySurroundingPlayersOfShelterSpawn)
            {
                List<BasePlayer> nearbyPlayers = Pool.Get<List<BasePlayer>>();
                Vis.Entities(shelter.transform.position, _config.Notification.RadiusForNotifyingNearbyPlayers, nearbyPlayers, LAYER_PLAYERS, QueryTriggerInteraction.Ignore);

                foreach (BasePlayer nearbyPlayer in nearbyPlayers)
                {
                    if (nearbyPlayer == null)
                        continue;

                    if (_config.Notification.SendAsToast)
                        ShowToast(nearbyPlayer, Lang.RaidableShelterSpawned);
                    else
                        MessagePlayer(nearbyPlayer, Lang.RaidableShelterSpawned);
                }

                Pool.FreeUnmanaged(ref nearbyPlayers);
            }
            else
            {
                if (_config.Notification.SendAsToast)
                    ShowToast(player, Lang.RaidableShelterSpawned);
                else
                    MessagePlayer(player, Lang.RaidableShelterSpawned);
            }
        }

        #endregion Shelter Spawn Notification

        #region Interior Entities Spawning

        private bool SpawnShelterInteriorEntities(LegacyShelter shelter, ShelterData shelterData)
        {
            Vector3 shelterCenter = shelter.transform.position;
            float spawnRadius = SPAWNABLE_AREA_RADIUS_INSIDE_SHELTER;
            bool anyEntitiesSpawned = false;

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

                for (int i = 0; i < numberToSpawn; i++)
                {
                    if (!ChanceSucceeded(interiorEntityConfig.SpawnChance))
                        continue;

                    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_GROUND))
                            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;

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

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

                            shelterData.InteriorEntities.Add(entity.net.ID.Value);
                            OnShelterInteriorEntitySpawned(shelter, entity);

                            anyEntitiesSpawned = true;

                            posAttempt = maxPositionAttempts;
                            break;
                        }
                    }
                }
            }

            return anyEntitiesSpawned;
        }

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

            BaseEntity prefabEntity = prefab.GetComponent<BaseEntity>();
            if (prefabEntity == null)
                return false;

            OBB entityBounds = new OBB(potentialPosition, potentialRotation, prefabEntity.bounds);

            Collider[] colliders = Physics.OverlapBox(
                entityBounds.position,
                entityBounds.extents,
                entityBounds.rotation,
                LAYER_ENTITIES,
                QueryTriggerInteraction.Ignore
            );

            if (colliders.Length > 0)
                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;

            if (interiorEntityConfig.SkinIds != null && interiorEntityConfig.SkinIds.Count > 0)
            {
                entity.skinID = interiorEntityConfig.SkinIds[Random.Range(0, interiorEntityConfig.SkinIds.Count)];
            }

            entity.Spawn();
            RemoveProblematicComponents(entity);

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

            return entity;
        }

        #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 (!item.MoveToContainer(itemContainer))
                    {
                        item.Remove();
                    }
                }
            }
        }

        #endregion Entity Container Filling

        #region Turret Deployment and Setup

        private void DeployAutoTurret(LegacyShelter shelter, ShelterData shelterData)
        {
            AutoTurret autoTurret = SpawnAutoTurret(shelter, _autoTurretPosition, Quaternion.Euler(_autoTurretRotation));
            if (autoTurret != null)
            {
                AddWeaponToTurret(autoTurret);

                LoadTurretWithReserveAmmo(autoTurret.inventory);
                autoTurret.UpdateTotalAmmo();
                autoTurret.EnsureReloaded();

                autoTurret.SetPeacekeepermode(_config.Turret.Peacekeeper);
                autoTurret.InitiateStartup();
                autoTurret.SendNetworkUpdate();

                shelterData.Traps.Add(autoTurret.net.ID.Value);
            }
        }

        private AutoTurret SpawnAutoTurret(LegacyShelter shelter, Vector3 position, Quaternion rotation)
        {
            AutoTurret autoTurret = GameManager.server.CreateEntity(PREFAB_AUTO_TURRET, position, rotation) as AutoTurret;
            if (autoTurret == null)
                return null;

            autoTurret.SetParent(shelter);
            autoTurret.Spawn();

            autoTurret.InitializeHealth(_config.Turret.Health, _config.Turret.Health);
            autoTurret.SendNetworkUpdateImmediate();

            RemoveProblematicComponents(autoTurret);
            HideIOInputsAndOutputs(autoTurret);

            return autoTurret;
        }

        private Item AddWeaponToTurret(AutoTurret autoTurret)
        {
            Item item = ItemManager.CreateByName(_config.Turret.WeaponShortName);
            if (item == null)
                return null;

            if (_config.Turret.AttachmentShortNames != null)
            {
                foreach (string attachmentShortname in _config.Turret.AttachmentShortNames)
                {
                    var attachmentItem = ItemManager.CreateByName(attachmentShortname);
                    if (attachmentItem != null)
                    {
                        if (!attachmentItem.MoveToContainer(item.contents))
                        {
                            attachmentItem.Remove();
                        }
                    }
                }
            }

            if (!item.MoveToContainer(autoTurret.inventory, 0))
            {
                item.Remove();
                return null;
            }

            BaseProjectile weapon = item.GetHeldEntity() as BaseProjectile;
            if (weapon != null)
            {
                if (_config.Turret.AttachmentShortNames != null)
                {
                    // Ensures the weapon's magazine capacity reflects the modifications applied, such as the extended magazine mod.weapon.DelayedModsChanged();
                    weapon.CancelInvoke(weapon.DelayedModsChanged);
                }

                autoTurret.UpdateAttachedWeapon();
                autoTurret.CancelInvoke(autoTurret.UpdateAttachedWeapon);

                if (_config.Turret.ClipAmmo != null)
                {
                    ItemDefinition loadedAmmoItemDefinition = ItemManager.FindItemDefinition(_config.Turret.ClipAmmo.ShortName);
                    if (loadedAmmoItemDefinition != null)
                    {
                        weapon.primaryMagazine.ammoType = loadedAmmoItemDefinition;

                        int clipAmmoAmount = UnityEngine.Random.Range(_config.Turret.ClipAmmo.MinimumAmount, _config.Turret.ClipAmmo.MaximumAmount + 1);
                        weapon.primaryMagazine.contents = Mathf.Min(weapon.primaryMagazine.capacity, clipAmmoAmount);
                    }
                }
            }

            return item;
        }

        private void LoadTurretWithReserveAmmo(ItemContainer autoTurretContainer)
        {
            if (_config.Turret.ReserveAmmo == null)
                return;

            // Starting from slot 1, because slot 0 is reserved for the weapon.int currentSlot = 1;
            int maximumAvailableSlots = autoTurretContainer.capacity - 1;

            foreach (ItemInfo ammo in _config.Turret.ReserveAmmo)
            {
                if (currentSlot > maximumAvailableSlots)
                    break;

                if (ammo.MinimumAmount <= 0 && ammo.MaximumAmount <= 0)
                    continue;

                ItemDefinition itemDefinition = ItemManager.FindItemDefinition(ammo.ShortName);
                if (itemDefinition == null)
                    continue;

                int reserveAmmoAmount = UnityEngine.Random.Range(ammo.MinimumAmount, ammo.MaximumAmount + 1);

                int amountToAdd = Math.Min(reserveAmmoAmount, itemDefinition.stackable);
                Item ammoItem = ItemManager.Create(itemDefinition, amountToAdd);
                if (!ammoItem.MoveToContainer(autoTurretContainer, currentSlot))
                {
                    ammoItem.Remove();
                }

                if (ammoItem.parent != autoTurretContainer)
                {
                    Item destinationItem = autoTurretContainer.GetSlot(currentSlot);
                    if (destinationItem != null)
                    {
                        destinationItem.amount = amountToAdd;
                        destinationItem.MarkDirty();
                    }

                    ammoItem.Remove();
                }

                currentSlot++;
            }
        }

        #endregion Turret Deployment and Setup

        #region Traps Spawning

        private void SpawnTrapsAroundShelter(LegacyShelter shelter, ShelterData shelterData)
        {
            Vector3 shelterPosition = shelter.transform.position;
            int numberOfTraps = Random.Range(_config.Trap.MinimumNumberOfTrapsToSpawn, _config.Trap.MaximumNumberOfTrapsToSpawn + 1);

            for (int i = 0; i < numberOfTraps; i++)
            {
                Vector3 randomPosition = TerrainUtil.GetRandomPositionAround(shelterPosition, _config.Trap.MinimumSpawnRadiusAroundShelter, _config.Trap.MaximumSpawnRadiusAroundShelter);

                RaycastHit groundHit;
                if (!TerrainUtil.GetGroundInfo(randomPosition, out groundHit, 5f, LAYER_GROUND))
                    continue;

                randomPosition = groundHit.point;
                Quaternion surfaceRotation = Quaternion.FromToRotation(Vector3.up, groundHit.normal);

                string trapPrefab = GetRandomTrapPrefab();
                if (string.IsNullOrEmpty(trapPrefab))
                    continue;

                BaseEntity trapEntity = GameManager.server.CreateEntity(trapPrefab, randomPosition, surfaceRotation);
                if (trapEntity != null)
                {
                    trapEntity.SetParent(shelter, true);
                    trapEntity.Spawn();
                    shelterData.Traps.Add(trapEntity.net.ID.Value);
                    RemoveProblematicComponents(trapEntity);
                }
            }
        }

        private string GetRandomTrapPrefab()
        {
            if (_config.Trap.SpawnLandmines && _config.Trap.SpawnBearTraps)
            {
                if (CoinFlip())
                    return PREFAB_LANDMINE;
                else
                    return PREFAB_BEAR_TRAP;
            }
            else if (_config.Trap.SpawnLandmines)
            {
                return PREFAB_LANDMINE;
            }
            else if (_config.Trap.SpawnBearTraps)
            {
                return PREFAB_BEAR_TRAP;
            }

            return null;
        }

        #endregion Traps Spawning

        #region Shelters Removal

        private void ResumeShelterRemovalTimers()
        {
            foreach (var kvp in _storedData.Shelters)
            {
                ShelterData shelterData = kvp.Value;
                LegacyShelter shelter = FindEntityById(kvp.Key) as LegacyShelter;

                if (shelter != null)
                {
                    double remainingTime = shelterData.RemovalTimer - Time.realtimeSinceStartup;
                    StartRemovalTimer(shelter, (float)remainingTime, shelterData);
                }
            }
        }

        private void StartRemovalTimer(LegacyShelter shelter, float lifetimeSeconds, ShelterData shelterData)
        {
            ulong shelterId = shelter != null && shelter.net != null ? shelter.net.ID.Value : 0;

            if (lifetimeSeconds <= 0)
            {
                if (shelter != null)
                    shelter.Kill();

                if (shelterData != null)
                {
                    foreach (ulong entityId in shelterData.InteriorEntities)
                    {
                        BaseEntity entity = FindEntityById(entityId);
                        if (entity != null)
                            entity.Kill();
                    }
                }

                if (_storedData.Shelters.ContainsKey(shelterId))
                {
                    _storedData.Shelters.Remove(shelterId);
                    DataFileUtil.Save(DataFileUtil.GetFilePath(), _storedData);
                }

                return;
            }

            if (shelter != null)
            {
                shelterData.RemovalTimer = Time.realtimeSinceStartup + lifetimeSeconds;
                DataFileUtil.Save(DataFileUtil.GetFilePath(), _storedData);

                timer.Once(lifetimeSeconds, () =>
                {
                    if (shelter != null)
                        shelter.Kill();

                    if (shelterData != null)
                    {
                        foreach (ulong entityId in shelterData.InteriorEntities)
                        {
                            BaseEntity entity = FindEntityById(entityId);
                            if (entity != null)
                                entity.Kill();
                        }
                    }

                    if (_storedData.Shelters.ContainsKey(shelterId))
                    {
                        _storedData.Shelters.Remove(shelterId);
                        DataFileUtil.Save(DataFileUtil.GetFilePath(), _storedData);
                    }
                });
            }
        }

        private void KillAllShelters()
        {
            foreach (var kvp in _storedData.Shelters)
            {
                ShelterData shelterData = kvp.Value;
                LegacyShelter shelter = BaseNetworkable.serverEntities.Find(new NetworkableId(kvp.Key)) as LegacyShelter;
                if (shelter != null)
                {
                    foreach (ulong entityId in shelterData.InteriorEntities)
                    {
                        BaseEntity entity = BaseNetworkable.serverEntities.Find(new NetworkableId(entityId)) as BaseEntity;
                        if (entity != null)
                            entity.Kill();
                    }

                    foreach (ulong trapId in shelterData.Traps)
                    {
        
// ... [Code preview truncated due to length. Full source in attached file] ...

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