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

FREE RandomBox : 1.0.2 1.0.2

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using UnityEngine;
using System;
using Facepunch;
using Newtonsoft.Json;
using Object = System.Object;
using Oxide.Core;
using System.Collections.Generic;
using Oxide.Core.Plugins;
using Random = Oxide.Core.Random;
using Rust;
using System.Text;
		   		 		  						  	   		  	  			  	   		  	  			  				
namespace Oxide.Plugins
{
    [Info("RandomBox", "Mercury", "1.0.2")]
    [Description("Random box in map")]
    class RandomBox : RustPlugin
    {
        private void OnNewSave(String filename) => ParseMonuments(true);
        
        private const Single dropHeight = 200f;

        
        
        [ChatCommand("tpbox")]
        private void AdminCommandTpBox(BasePlayer player)
        {
            if (!player.IsAdmin) return;
            if (randomBox == null) return;
            if (randomBox.IsDestroyed) return;
            
            player.Teleport(randomBox.transform.position);
        }
        private readonly HashSet<String> blockedNames = new HashSet<String> { "MeshColliderBatch", "iceberg_3", "iceberg_2" };
        
        
        
                private String GetLang(in String LangKey, in String userID = null, params Object[] args)
        {
            if (args == null) 
                return lang.GetMessage(LangKey, this, userID);

            StringBuilder sb = Pool.Get<StringBuilder>();

            try
            {
                sb.AppendFormat(lang.GetMessage(LangKey, this, userID), args);
                return sb.ToString();
            }
            finally
            {
                sb.Clear();
                Pool.FreeUnmanaged(ref sb);
            }
        }
        
        
                private static Configuration config = new Configuration();

                
                
        private Single GetGroundPosition(Vector3 pos)
        {
            Single y = TerrainMeta.HeightMap.GetHeight(pos);
            if (Physics.Raycast(
                    new Vector3(pos.x, pos.y + 200f, pos.z),
                    Vector3.down,
                    out RaycastHit hit,
                    Mathf.Infinity,
                    LayerMask.GetMask("Terrain", "World", "Default", "Construction", "Deployed")) && !hit.collider.name.Contains("rock_cliff"))
            {
                return Mathf.Max(hit.point.y, y);
            }

            return y;
        }
        private const Single monumentProximityThreshold = 250f;
        private const Single colliderRadius = 1f;

        
        
        private void ParseMonuments(Boolean isNewSave = false)
        {
            if(!isNewSave)
                if (monuments.Count != 0)
                    return;

            monuments.Clear();
            
            Int32 countAddedMonuments = 0;
            foreach (MonumentInfo monument in TerrainMeta.Path.Monuments)
            {
                if (monument.IsSafeZone ||
                    monument.Type == MonumentType.WaterWell ||
                    monument.Type == MonumentType.Cave ||
                    monument.Bounds.size == Vector3.zero)
                {
                    continue;
                } 
                
                Vector3 posMonument = monument.transform.position;

                monuments.Add(posMonument);
                countAddedMonuments++;
            }
            
            Puts(LanguageEn ? $"Information received about {countAddedMonuments} monuments on the map" : $"Получена информация о {countAddedMonuments} монументах на карте");
            WriteData();
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                config = Config.ReadObject<Configuration>();
                if (config == null) LoadDefaultConfig();
            }
            catch
            {
                PrintWarning(LanguageEn 
                    ? "Error reading configuration #324552 'oxide/config/{Name}', creating a new configuration!!" 
                    : $"Ошибка чтения #324552 конфигурации 'oxide/config/{Name}', создаём новую конфигурацию!!");
                LoadDefaultConfig();
            }

            NextTick(SaveConfig);
        }
        
        private Vector3 GetSafeDropPosition(Vector3 position)
        {
            position.y += dropHeight;

            if (!Physics.Raycast(position, Vector3.down, out RaycastHit hit))
                return Vector3.zero;

            if (hit.collider == null || hit.collider.gameObject == null)
                return Vector3.zero;

            String colliderName = hit.collider.name;
            Int32 layer = hit.collider.gameObject.layer;

            if (BlockedLayers.Contains(layer) || blockedNames.Contains(colliderName) || colliderName.Contains("rock_cliff"))
                return Vector3.zero;

            Single groundHeight = TerrainMeta.HeightMap.GetHeight(position);
            position.y = Mathf.Max(hit.point.y, groundHeight);

            if (Physics.OverlapSphere(position, colliderRadius, blockedMask, QueryTriggerInteraction.Collide).Length == 0)
                return position;

            return Vector3.zero; 
        }
        /// <summary>
        /// - Исправление после обновления и гры
        /// </summary>
        
        
        private const Boolean LanguageEn = false;
        
        private Boolean isInit = false;
        
        private List<Vector3> monuments = new List<Vector3>();
        private void WriteData() =>  Oxide.Core.Interface.Oxide.DataFileSystem.WriteObject("RandomBox", monuments);
        private class Configuration
        {
            [JsonProperty(LanguageEn ? "Loot Configuration" : "Настройка лута")]
            public LootSetting controllerLott = new();
            [JsonProperty(LanguageEn ? "IQChat: Chat Prefix" : "IQChat : Префикс в чате")]
            public String chatPrefix;
            [JsonProperty(LanguageEn ? "Box SkinID (Be Sure to Specify ID)" : "SkinID ящика (обязательно укажите ID)")]
            public UInt64 skinIdBox;
            [JsonProperty(LanguageEn ? "Use Red alarm" : "Использовать красную мигалку")]
            public Boolean useAlarm;
            [JsonProperty(LanguageEn ? "Time Interval for Box Appearance (Seconds)" : "Раз во сколько будет появляться ящик (секунды)")]
            public Int32 secondSpawn;

            public static Configuration GetNewConfiguration()
            {
                return new Configuration
                {
                    secondSpawn = 30,
                    useAlarm = false,
                    skinIdBox = 824194136,
                    chatAvatar = "0",
                    chatPrefix = "<color=#CD412B>[RandomBox]</color>\n",
                    controllerLott = new LootSetting
                    {
                        countLootInBox = new LootSetting.AmountController
                        {
                            minAmount = 3,
                            maxAmount = 6
                        },
                        itemForBox = new List<LootSetting.LootBox>
                        {
                            new LootSetting.LootBox
                            {
                                shortname = "wood",
                                skinID = 0,
                                amountLoot = new LootSetting.AmountController()
                                {
                                    minAmount = 300,
                                    maxAmount = 1000
                                }
                            },
                            new LootSetting.LootBox
                            {
                                shortname = "metal.fragments",
                                skinID = 0,
                                amountLoot = new LootSetting.AmountController()
                                {
                                    minAmount = 150,
                                    maxAmount = 500
                                }
                            },
                            new LootSetting.LootBox
                            {
                                shortname = "scrap",
                                skinID = 0,
                                amountLoot = new LootSetting.AmountController()
                                {
                                    minAmount = 30,
                                    maxAmount = 100
                                }
                            },
                            new LootSetting.LootBox
                            {
                                shortname = "xmas.present.medium",
                                skinID = 0,
                                amountLoot = new LootSetting.AmountController()
                                {
                                    minAmount = 1,
                                    maxAmount = 1
                                }
                            },
                            new LootSetting.LootBox
                            {
                                shortname = "xmas.present.large",
                                skinID = 0,
                                amountLoot = new LootSetting.AmountController()
                                {
                                    minAmount = 1,
                                    maxAmount = 1
                                }
                            },
                        }
                    }
                };
            }
            
            public class LootSetting
            {
                [JsonProperty(LanguageEn ? "List of Items (Selected Randomly)" : "Список предметов (выбираются случайно)")]
                public List<LootBox> itemForBox = new();
		   		 		  						  	   		  	  			  	   		  	  			  				
                internal class LootBox
                {
                    [JsonProperty("SkinID")] 
                    public UInt64 skinID;
                    [JsonProperty(LanguageEn ? "Loot Quantity Configuration" : "Настройка количества лута")] 
                    public AmountController amountLoot;
                    
                    public Item GetItem()
                    {
                        Item item = ItemManager.CreateByName(shortname, amountLoot.GetAmount(), skinID);
                        return item;
                    }
                    [JsonProperty("Shortname")] 
                    public String shortname;
                }

                private void ShuffleList(List<LootBox> list)
                {
                    Int32 n = list.Count;
                    for (Int32 i = 0; i < n - 1; i++)
                    {
                        Int32 j = Oxide.Core.Random.Range(i, n);
                        (list[i], list[j]) = (list[j], list[i]);
                    }
                }

                public class AmountController
                {
                    [JsonProperty(LanguageEn ? "Minimum Quantity" : "Минимальное количество")]
                    public Int32 minAmount;
                    [JsonProperty(LanguageEn ? "Maximum Quantity" : "Максимальное количество")]
                    public Int32 maxAmount;

                    public Int32 GetAmount() => Oxide.Core.Random.Range(minAmount, maxAmount);
                }
                
                public List<Item> GetRandomItems()
                {
                    List<Item> resultItems = new List<Item>();
		   		 		  						  	   		  	  			  	   		  	  			  				
                    Int32 countLoot = countLootInBox.GetAmount();

                    if (itemForBox.Count < countLoot)
                        countLoot = itemForBox.Count;

                    ShuffleList(itemForBox);

                    for (Int32 i = 0; i < countLoot; i++)
                    {
                        LootBox lootBox = itemForBox[i];
                        Item item = lootBox.GetItem();
        
                        resultItems.Add(item);
                    }

                    return resultItems;
                }
                [JsonProperty(LanguageEn ? "Loot Quantity Configuration in a Box" : "Настройка количество лута в одном ящике")] 
                public AmountController countLootInBox;
            }
            [JsonProperty(LanguageEn ? "IQChat: Chat Avatar (Use Steam64ID)" : "IQChat : Аватарка в чате (Используйте Steam64ID)")]
            public String chatAvatar;
        }
        
        private new void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<String, String>
            {
                ["CREATE_SPAWN"] = "A <color=#738D45>gift box</color> has appeared!\nHurry up and find it!\nLocation: <color=#738D45>{0}</color>",
                ["CREATE_FINDING"] = "Someone found the gifts!",
            }, this);

            lang.RegisterMessages(new Dictionary<String, String>
            {
                ["CREATE_SPAWN"] = "Появилась <color=#738D45>коробка с подарками</color>!\nСкорее найди ее!\nМестоположение: <color=#738D45>{0}</color>",
                ["CREATE_FINDING"] = "Кто-то нашел подарки!",
            }, this, "ru");
            
            PrintWarning(LanguageEn 
                ? "Language file loaded successfully." 
                : "Языковой файл загружен успешно");
        }

        protected override void LoadDefaultConfig() => config = Configuration.GetNewConfiguration();
        
        
        private void ReadData() => monuments = Oxide.Core.Interface.Oxide.DataFileSystem.ReadObject<List<Vector3>>("RandomBox");
                
                
        [PluginReference] Plugin IQChat;

        private Vector3 GetEventPosition()
        {
            for (Int32 i = 0; i < maxRetries; i++)
            {
                Vector3 eventPos = GetSafeDropPosition(RandomDropPosition());

                Boolean tooCloseToMonument = false;
                foreach (Vector3 monument in monuments)
                    if (Vector3.Distance(eventPos, monument) < monumentProximityThreshold)
                    {
                        tooCloseToMonument = true;
                        break;
                    }

                if (tooCloseToMonument)
                    continue;

                eventPos.y = GetGroundPosition(eventPos);
                if (eventPos.y >= 0)
                    return eventPos; // Valid event position
            }

            return Vector3.zero;
        }
		   		 		  						  	   		  	  			  	   		  	  			  				
        private const String prefabAlarm = "assets/prefabs/deployable/playerioents/lights/sirenlight/electric.sirenlight.deployed.prefab";
        private Timer timerStart = null;
        private const String effectBox = "assets/prefabs/misc/casino/slotmachine/effects/payout_jackpot.prefab";
        private StorageContainer randomBox = null;
        
        private void OnServerInitialized()
        {
            if (config.skinIdBox == 0)
            {
                PrintWarning(LanguageEn 
                    ? "You have not set the SkinID - this is a mandatory field." 
                    : "У вас не установлен SkinID - это обязательный пункт");
                NextTick(() =>
                {
                    Interface.Oxide.UnloadPlugin(Name);
                });
            }
            
            ParseMonuments();
            
            StartEvent();
            isInit = true;
        }
        private const String prefabNameBox = "assets/prefabs/deployable/large wood storage/box.wooden.large.prefab";
        private void SendChat(String Message, BasePlayer player)
        {
            if (IQChat)
                 IQChat?.Call("API_ALERT_PLAYER", player, Message, config.chatPrefix, config.chatAvatar);
            else player.SendConsoleCommand("chat.add", ConVar.Chat.ChatChannel.Global, 0, Message);
        }
        
        
        
        
        private void StartEvent()
        {
            if (!isInit)
            {
                timerStart = timer.Once(config.secondSpawn, StartEvent);
                return;
            }
            
            if (timerStart is { Destroyed: false })
            {
                timerStart.Destroy();
                timerStart = null;
            }
            
            Vector3 positionEvent = GetEventPosition();
            if (positionEvent == Vector3.zero)
            {
                PrintError(LanguageEn 
                    ? "Failed to start the event, could not detect positions." 
                    : "Не удалось запустить мероприятие, не смогли обнаружить позиции");

                return;
            }

            String gMapKey = MapHelper.PositionToString(positionEvent);

            if (randomBox != null)
            {
                randomBox.inventory.Clear();
                randomBox.Kill();
                randomBox = null;
            }
            
            randomBox = (StorageContainer)GameManager.server.CreateEntity(prefabNameBox, positionEvent) as StorageContainer;
            randomBox.enableSaving = true;
            randomBox.skinID = config.skinIdBox;
            randomBox.Spawn();

            if (config.useAlarm)
            {
                BaseEntity AlarmEntity = GameManager.server.CreateEntity(prefabAlarm, randomBox.transform.position);
                AlarmEntity.Spawn();
                AlarmEntity.SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
                AlarmEntity.UpdateNetworkGroup();
                AlarmEntity.transform.localPosition = new Vector3(0, 0.4f, 0f);
                AlarmEntity.SetParent(randomBox);
                AlarmEntity.SetFlag(BaseEntity.Flags.Reserved8, true);
                AlarmEntity.SetFlag(BaseEntity.Flags.On, true);
            }

            List<Item> itemList = Pool.GetList<Item>();
            itemList = config.controllerLott.GetRandomItems();

            foreach (Item item in itemList)
                item.MoveToContainer(randomBox.inventory);
            
            Pool.FreeList(ref itemList);
            
            foreach (BasePlayer player in BasePlayer.activePlayerList)
                SendChat(GetLang("CREATE_SPAWN", player.UserIDString, gMapKey), player);

            timerStart = timer.Once(config.secondSpawn, StartEvent);
        }
        private readonly Int32 blockedMask = LayerMask.GetMask(new[] { "Player (Server)", "Trigger", "Prevent Building" });
        
        private SpawnFilter filter = new SpawnFilter();
        
        private const Int32 maxRetries = 100;
        
        private Object CanLootEntity(BasePlayer player, StorageContainer container)
        {
            if (container == null || player == null) return null;
            if (container.skinID != config.skinIdBox) return null;
            
            for (Int32 i = 0; i < container.inventory.itemList.Count; i++)
            {
                Item itemInBox = container.inventory.itemList[i];
                Single randomForce = Random.Range(1.5f, 3.0f);
                itemInBox.DropAndTossUpwards(container.transform.position, randomForce);
            }

            Effect effect = new Effect(effectBox, player, 0, new Vector3(), new Vector3());
            EffectNetwork.Send(effect, player.Connection);
            
            container.Kill();
            
            foreach (BasePlayer p in BasePlayer.activePlayerList)
                SendChat(String.Format(lang.GetMessage("CREATE_FINDING", this, p.UserIDString)), p);

            randomBox = null;

            return false;
        }

        
        
        private void Init() => ReadData();

        private Vector3 RandomDropPosition()
        {
            Vector3 vector = Vector3.zero;
            Single num = 1000f;
            Single x = TerrainMeta.Size.x / 3;

            do
            { vector = Vector3Ex.Range(-x, x); }
            while (filter.GetFactor(vector) == 0f && (num -= 1f) > 0f);

            Single height = TerrainMeta.HeightMap.GetHeight(vector);
            vector.y = height;
            return vector;
        }
        private readonly List<Int32> BlockedLayers = new List<Int32> { (Int32)Layer.Water, (Int32)Layer.Construction, (Int32)Layer.Trigger, (Int32)Layer.Prevent_Building, (Int32)Layer.Deployed, (Int32)Layer.Tree };

        private void Unload()
        {
            if (timerStart is { Destroyed: false })
            {
                timerStart.Destroy();
                timerStart = null;
            }
            
            if (randomBox != null)
            {
                randomBox.inventory.Clear();
                randomBox.Kill();
                randomBox = null;
            }
            
            WriteData();
        }
        protected override void SaveConfig() => Config.WriteObject(config);
            }
}

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