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

FREE PowerSpawn : 1.1.0 1.1.0

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

namespace Oxide.Plugins
{
    [Info("Power Spawn", "Iv Misticos", "1.1.0")]
    [Description("Control players' spawning")]
    class PowerSpawn : RustPlugin
    {
        #region Variables

        private int _worldSize;

        private readonly int _layerTerrain = LayerMask.NameToLayer("Terrain");

        private readonly Random _random = new Random();

        private static PowerSpawn _ins;

        private static List<Vector3> _preGeneratedLocations = new List<Vector3>();
        
        #endregion
        
        #region Configuration

        private static Configuration _config;
        
        private class Configuration
        {
            [JsonProperty(PropertyName = "Minimal Distance To Building")]
            public int DistanceBuilding = 10;

            [JsonProperty(PropertyName = "Minimal Distance To Collider")]
            public int DistanceCollider = 10;

            [JsonProperty(PropertyName = "Maximum Number Of Attempts To Find A Location")]
            public int AttemptsMax = 200;

            [JsonProperty(PropertyName = "Respawn Locations Group")]
            public int RespawnGroup = -2;

            [JsonProperty(PropertyName = "Enable Respawn Locations")]
            public bool EnableRespawnGroup = false;

            [JsonProperty(PropertyName = "Pre-Generate Spawn Locations")]
            public bool PreGenerateSpawn = false;

            [JsonProperty(PropertyName = "Pre-Generated Spawn Locations Amount")]
            public int PreGenerateAmount = 1000;

            [JsonProperty(PropertyName = "Maximum Number Of Attempts To Find Pre-Generated Spawn Locations")]
            public int PreGenerateAttempts = 500;

            [JsonProperty(PropertyName = "Location Management Command")]
            public string LocationCommand = "loc";

            [JsonProperty(PropertyName = "Location Management Permission")]
            public string LocationPermission = "powerspawn.location";

            [JsonProperty(PropertyName = "Debug")]
            public bool Debug = false;
        }
        
        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                _config = Config.ReadObject<Configuration>();
                if (_config == null) throw new Exception();
            }
            catch
            {
                Config.WriteObject(_config, false, $"{Interface.Oxide.ConfigDirectory}/{Name}.jsonError");
                PrintError("The configuration file contains an error and has been replaced with a default config.\n" +
                           "The error configuration file was saved in the.jsonError extension");
                LoadDefaultConfig();
            }

            SaveConfig();
        }

        protected override void LoadDefaultConfig() => _config = new Configuration();

        protected override void SaveConfig() => Config.WriteObject(_config);
        
        #endregion

        #region Work with Data

        private static PluginData _data = new PluginData();

        private class PluginData
        {
            public List<Location> Locations = new List<Location>();

            // ReSharper disable once MemberCanBePrivate.Local
            public int LastID = 0;
            
            public class Location
            {
                public string Name;
                public int ID = _data.LastID++;
                public int Group = -1;
                public Vector3 Position;

                public string Format(string player)
                {
                    var text = new StringBuilder(GetMsg("Location: Format", player));
                    text.Replace("{name}", Name);
                    text.Replace("{id}", ID.ToString());
                    text.Replace("{group}", Group.ToString());
                    text.Replace("{position}", Position.ToString());

                    return text.ToString();
                }

                public static int? FindIndex(int id)
                {
                    for (var i = 0; i < _data.Locations.Count; i++)
                    {
                        if (_data.Locations[i].ID == id)
                            return i;
                    }

                    return null;
                }

                public static IEnumerable<Location> FindByGroup(int group)
                {
                    for (var i = 0; i < _data.Locations.Count; i++)
                    {
                        var location = _data.Locations[i];
                        if (location.Group == group)
                            yield return location;
                    }
                }
            }
        }

        private static void SaveData() => Interface.Oxide.DataFileSystem.WriteObject(_ins.Name, _data);

        private void LoadData()
        {
            try
            {
                _data = Interface.Oxide.DataFileSystem.ReadObject<PluginData>(Name);
            }
            catch (Exception e)
            {
                PrintError(e.ToString());
            }

            if (_data == null) _data = new PluginData();
        }
        
        #endregion
        
        #region Hooks

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                { "No Permission", "nope" },
                { "Location: Syntax", "Location Syntax:\n" +
                                     "new (Name) - Create a new location with a specified name\n" +
                                     "delete (ID) - Delete a location with the specified ID\n" +
                                     "edit (ID) <Parameter 1> <Value> <...> - Edit a location with the specified ID\n" +
                                     "update - Apply datafile changes\n" +
                                     "list - Get a list of locations\n" +
                                     "validate (ID) - Validate location for buildings and colliders" },
                { "Location: Edit Syntax", "Location Edit Parameters:\n" +
                                          "move (x;y;z / here) - Move a location to the specified position\n" +
                                          "group (ID / reset) - Set group of a location or reset the group" },
                { "Location: Unable To Parse Position", "Unable to parse the position" },
                { "Location: Unable To Parse Group", "Unable to parse the entered group" },
                { "Location: Format", "Location ID: {id}; Group: {group}; Position: {position}; Name: {name}" },
                { "Location: Not Found", "Sorry, I couldn't find the location you specified." },
                { "Location: Edit Finished", "Edit was finished." },
                { "Location: Removed", "Location was removed from our database." },
                { "Location: Updated", "Datafile changes were applied." },
                { "Location: Validation Format", "Buildings invalid: {buildings}; Colliders invalid: {colliders}" },
                { "Generated Respawn Locations", "We have pre-generated respawn locations ({count})" }
            }, this);
        }

        private void OnServerInitialized()
        {
            _ins = this;
            _worldSize = ConVar.Server.worldsize;
            LoadData();

            if (_config.PreGenerateSpawn)
            {
                if (_config.EnableRespawnGroup)
                {
                    PrintError("Cannot use both pre-generated spawn locations and respawn group.Disable one of them.");
                    Interface.Oxide.UnloadPlugin(Name);
                    return;
                }
                
                while (_preGeneratedLocations.Count < _config.PreGenerateAmount)
                {
                    Vector3? position = null;
                    for (var i = 0; i < _config.PreGenerateAttempts && !position.HasValue; i++)
                    {
                        position = TryFindPosition();
                    }

                    if (!position.HasValue)
                    {
                        PrintWarning("Could not pre-generate respawn locations");
                        Interface.Oxide.UnloadPlugin(Name);
                        return;
                    }
                    
                    _preGeneratedLocations.Add(position.Value);
                }
                
                Puts(GetMsg("Generated Respawn Locations").Replace("{count}", _preGeneratedLocations.Count.ToString()));
            }

            permission.RegisterPermission(_config.LocationPermission, this);
            AddCovalenceCommand(_config.LocationCommand, nameof(CommandLocation));
        }

        private object OnPlayerRespawn(BasePlayer player)
        {
            var position = FindPosition();
            if (!position.HasValue)
            {
                PrintDebug($"Haven't found a position for {player.displayName}");
                return null;
            }
            
            PrintDebug($"Found position for {player.displayName}: {position}");
            
            return new BasePlayer.SpawnPoint
            {
                pos = position.Value
            };
        }

        #endregion
        
        #region Commands

        private void CommandLocation(IPlayer player, string command, string[] args)
        {
            if (!player.HasPermission(_config.LocationPermission))
            {
                player.Reply(GetMsg("No Permission", player.Id));
                return;
            }

            if (args.Length == 0)
            {
                goto syntax;
            }

            switch (args[0])
            {
                case "new":
                case "n":
                {
                    if (args.Length != 2)
                    {
                        goto syntax;
                    }

                    var location = new PluginData.Location
                    {
                        Name = args[1]
                    };

                    player.Position(out location.Position.x, out location.Position.y, out location.Position.z);
                    _data.Locations.Add(location);
                    
                    player.Reply(location.Format(player.Id));
                    goto saveData;
                }

                case "delete":
                case "remove":
                case "d":
                case "r":
                {
                    int id;
                    if (args.Length != 2 || !int.TryParse(args[1], out id))
                    {
                        goto syntax;
                    }

                    var locationIndex = PluginData.Location.FindIndex(id);
                    if (!locationIndex.HasValue)
                    {
                        player.Reply(GetMsg("Location: Not Found", player.Id));
                        return;
                    }
                    
                    _data.Locations.RemoveAt(locationIndex.Value);
                    player.Reply(GetMsg("Location: Removed", player.Id));
                    goto saveData;
                }

                case "edit":
                case "e":
                {
                    int id;
                    if (args.Length < 4 || !int.TryParse(args[1], out id))
                    {
                        player.Reply(GetMsg("Location: Edit Syntax", player.Id));
                        return;
                    }

                    var locationIndex = PluginData.Location.FindIndex(id);
                    if (!locationIndex.HasValue)
                    {
                        player.Reply(GetMsg("Location: Not Found", player.Id));
                        return;
                    }

                    var locationCD = new CommandLocationData
                    {
                        Player = player,
                        Location = _data.Locations[locationIndex.Value]
                    };
                    
                    locationCD.Apply(args);
                    player.Reply(GetMsg("Location: Edit Finished", player.Id));
                    goto saveData;
                }

                case "update":
                case "u":
                {
                    LoadData();
                    player.Reply(GetMsg("Location: Updated", player.Id));
                    return;
                }

                case "list":
                case "l":
                {
                    var table = new TextTable();
                    table.AddColumns("ID", "Name", "Group", "Position");

                    foreach (var location in _data.Locations)
                    {
                        table.AddRow(location.ID.ToString(), location.Name, location.Group.ToString(), location.Position.ToString());
                    }

                    player.Reply(table.ToString());
                    return;
                }

                case "valid":
                case "validate":
                case "v":
                {
                    int id;
                    if (args.Length < 2 || !int.TryParse(args[1], out id))
                    {
                        player.Reply(GetMsg("Location: Syntax", player.Id));
                        return;
                    }
                    
                    var locationIndex = PluginData.Location.FindIndex(id);
                    if (!locationIndex.HasValue)
                    {
                        player.Reply(GetMsg("Location: Not Found", player.Id));
                        return;
                    }

                    var location = _data.Locations[locationIndex.Value];
                    player.Reply(GetMsg("Location: Validation Format", player.Id).Replace("{buildings}", CheckBadBuilding(location.Position).ToString()).Replace("{colliders}", CheckBadCollider(location.Position).ToString()));
                    return;
                }

                default:
                {
                    goto syntax;
                }
            }
            
            syntax:
            player.Reply(GetMsg("Location: Syntax", player.Id));
            return;
            
            saveData:
            SaveData();
        }

        private class CommandLocationData
        {
            public IPlayer Player;
            
            public PluginData.Location Location;
            
            private const int FirstArgumentIndex = 2;
            
            public void Apply(string[] args)
            {
                for (var i = FirstArgumentIndex; i + 1 < args.Length; i += 2)
                {
                    switch (args[i])
                    {
                        case "move":
                        {
                            var position = ParseVector(args[i + 1]);
                            if (!position.HasValue)
                            {
                                Player.Reply(GetMsg("Location: Unable To Parse Position", Player.Id));
                                break;
                            }

                            Location.Position = position.Value;
                            break;
                        }

                        case "group":
                        {
                            int group = -1;
                            if (args[i + 1] != "reset" && !int.TryParse(args[i + 1], out group))
                            {
                                Player.Reply(GetMsg("Location: Unable To Parse Group", Player.Id));
                                break;
                            }

                            Location.Group = group;
                            break;
                        }
                    }
                }

                SaveData();
            }

            private Vector3? ParseVector(string argument)
            {
                var vector = new Vector3();
                
                if (argument == "here")
                {
                    Player.Position(out vector.x, out vector.y, out vector.z);
                }
                else
                {
                    var coordinates = argument.Split(';');
                    if (coordinates.Length != 3 || !float.TryParse(coordinates[0], out vector.x) ||
                        !float.TryParse(coordinates[1], out vector.y) || !float.TryParse(coordinates[2], out vector.z))
                    {
                        return null;
                    }
                }
                
                return vector;
            }
        }
        
        #endregion
        
        #region API

        private Vector3? GetLocation(int id)
        {
            var locationIndex = PluginData.Location.FindIndex(id);
            if (!locationIndex.HasValue)
                return null;

            return _data.Locations[locationIndex.Value].Position;
        }

        private JObject GetGroupLocations(int group)
        {
            var locations = PluginData.Location.FindByGroup(group);
            return JObject.FromObject(locations);
        }
        
        #endregion
        
        #region Helpers

        private Vector3? FindPosition()
        {
            Vector3? position = null;
            for (var i = 0; i < _config.AttemptsMax && !position.HasValue; i++)
            {
                // Getting position
                if (_config.PreGenerateSpawn)
                {
                    position = _preGeneratedLocations[_random.Next(0, _config.PreGenerateAmount)];
                }
                else if (_config.EnableRespawnGroup)
                {
                    var locationsEn = PluginData.Location.FindByGroup(_config.RespawnGroup);
                    if (locationsEn == null)
                        continue;
                    
                    var locations = new List<PluginData.Location>(locationsEn);
                    if (locations.Count != 0)
                    {
                        var location = locations[_random.Next(0, locations.Count)];
                        PrintDebug($"Using location {location.Name}");
                        position = location.Position;
                    }
                }
                else
                {
                    position = TryFindPosition();
                }

                if (!position.HasValue) continue;
                
                PrintDebug($"Found position: {position.Value}");
                
                // If it's a "bad" position, continue trying to find a good one.if (CheckBadBuilding(position.Value) || CheckBadCollider(position.Value))
                    position = null; // :P
            }

            return position;
        }

        private Vector3? TryFindPosition()
        {
            var position = new Vector3(GetRandomPosition(), 0, GetRandomPosition());
            var height = TerrainMeta.HeightMap.GetHeight(position);
            if (height > 0)
                position.y = height;
            else
                return null;

            return position;
        }

        private int GetRandomPosition() => _random.Next(_worldSize / -2, _worldSize / 2);

        private void PrintDebug(string message)
        {
            if (_config.Debug)
                Interface.Oxide.LogDebug($"{Name} > " + message);
        }

        private bool CheckBadBuilding(Vector3 position)
        {
            var buildings = new List<BuildingBlock>();
            Vis.Entities(position, _config.DistanceBuilding, buildings, Layers.Construction);
            return buildings.Count > 0;
        }

        private bool CheckBadCollider(Vector3 position)
        {
            var colliders = new List<Collider>();
            Vis.Components(position, _config.DistanceCollider, colliders);
            foreach (var collider in colliders)
            {
                var gameObject = collider.gameObject;
                if (gameObject.layer == _layerTerrain)
                    continue;
                
                return true;
            }
            
            return false;
        }

        private static string GetMsg(string key, string userId = null) => _ins.lang.GetMessage(key, _ins, userId);

        #endregion
    }
}

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