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

FREE DecaySystem : 1.2.0 1.2.0

Нет прав для скачивания
C#:
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using System;
using System.Collections;
using System.Diagnostics;
using Rust;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Plugins;
namespace Oxide.Plugins {
    [Info("DecaySystem", "TopPlugin.ru", "1.2.0")]
    public class DecaySystem : RustPlugin {
#region Ref
        [PluginReference]
        Plugin ZoneManager;
#endregion
        private float doorTimeout;
        private float doorRadius;
        private float timeout = 3600;
        private float TwigsTicks;
        private float MultiplierWood;
        private float MultiplierStone;
        private float MultiplierMetal;
        private float MultiplierTopTier;
        private Dictionary<string, int> decaySettingsInCupboard = new Dictionary<string, int>();
        private Dictionary<string, int> decaySettingsWithoutCupboard = new Dictionary<string, int>();
        private List<string> baseDecayPrefabs = new List<string>() {
            "foundation", "foundation.triangle", "gates.external.high.wood", "wall.external.high.wood", "gates.external.high.stone", "wall.external.high.stone",
        }
        ;
        private List<string> defaultDecayPrefabs = new List<string>() {
            "foundation", "foundation.triangle", "wall.external.high.stone", "cupboard.tool.deployed", "box.wooden.large", "sleepingbag_leather_deployed", "stocking_large_deployed", "stocking_small_deployed", "furnace", "woodbox_deployed", "barricade.sandbags", "barricade.stone", "jackolantern.happy", "barricade.concrete", "floor.grill", "barricade.metal", "autoturret_deployed", "campfire", "repairbench_deployed", "beartrap", "wall.external.high.wood", "bed_deployed", "gates.external.high.stone", "furnace.large", "refinery_small_deployed", "reactivetarget_deployed", "barricade.woodwire", "landmine", "lantern.deployed", "ceilinglight.deployed", "gates.external.high.wood", "spikes.floor", "barricade.wood", "jackolantern.angry", "water_catcher_large"
        }
        ;
        static Dictionary<string, Stopwatch> watches = new Dictionary<string, Stopwatch>();
        private static int TriggerMask = LayerMask.GetMask("Trigger");
        private DynamicConfigFile doortimers_file = Interface.Oxide.DataFileSystem.GetFile("DecaySystem_DoorTimers");
        private DynamicConfigFile blocksDoorFile = Interface.Oxide.DataFileSystem.GetFile("DecaySystem_Blocks");
        Dictionary<uint, float> doorTimers = new Dictionary<uint, float>();
        Dictionary<uint, uint> blocksDoor = new Dictionary<uint, uint>();
        List<BaseCombatEntity> decayEntities;
        Dictionary<uint, uint> blockCupboards = new Dictionary<uint, uint>();
        int WorldBuildingsLayer = LayerMask.GetMask("Construction", "World", "Terrain");
        int BuildingsLayer = LayerMask.GetMask("Construction");
        int DeployedLayer = LayerMask.GetMask("Deployed");
        private bool init = false;
        private bool isdecay = false;
        private UnityEngine.Vector3 offset = new UnityEngine.Vector3(0, 0.5f, 0);
        private Coroutine decayCoroutine;
        [ChatCommand("decay")]
        void cmdChatDecay(BasePlayer player) {
            if (!player.IsAdmin) return;
            RunDecay();
        }
        [ConsoleCommand("decay")]
        void cmdDecay(ConsoleSystem.Arg arg) {
            if (arg.Connection != null) return;
            RunDecay();
        }
        protected override void LoadDefaultConfig() {
            Config["Настройки: гниение соломяных обьектов (в часах)"] = TwigsTicks = GetConfig("Настройки: гниение соломяных обьектов (в часах)", 1f);
            Config["Приумножение гниения дерева"] = MultiplierWood = GetConfig("Приумножение гниения дерева", 1f);
            Config["Приумножение гниения камня"] = MultiplierStone = GetConfig("Приумножение гниения камня", 1f);
            Config["Приумножение гниения металла"] = MultiplierMetal = GetConfig("Приумножение гниения металла", 1f);
            Config["Приумножение гниения мвк"] = MultiplierTopTier = GetConfig("Приумножение гниения мвк", 1f);
            Config["Настройки: задержка перед гниением фундаментов, если в радиусе (настройка) метров открывали дверь (в часах)"] = doorTimeout = GetConfig("Настройки: задержка перед гниением фундаментов, если в радиусе (настройка) метров открывали дверь (в часах)", 5.0f);
            Config["Настройки: размер радиуса для поиска дверей"] = doorRadius = GetConfig("Настройки: размер радиуса для поиска дверей", 10f);
            Config["Гниение объектов которые находятся в зоне действия шкафа (в часах)"] = decaySettingsInCupboard = GetConfig("Гниение объектов которые находятся в зоне действия шкафа (в часах)", defaultDecayPrefabs.ToDictionary(p => p, p => (object)24)).ToDictionary(p => p.Key, p => int.Parse(p.Value.ToString()));
            Config["Гниение объектов которые находятся вне зоны действия шкафа (в часах)"] = decaySettingsWithoutCupboard = GetConfig("Гниение объектов которые находятся вне зоны действия шкафа (в часах)", defaultDecayPrefabs.ToDictionary(p => p, p => (object)36)).ToDictionary(p => p.Key, p => int.Parse(p.Value.ToString()));
            SaveConfig();
        }
        T GetConfig<T>(string name, T defaultValue) {
            return Config[name] == null ? defaultValue : (T)Convert.ChangeType(Config[name], typeof(T));
        }
        void DoorHandle(Door door) {
            doorTimers[door.net.ID] = doorTimeout;
        }
        float GetDoorTimeout(BaseCombatEntity block) {
            uint blockID = block.net.ID;
            uint doorNetID;
            if (blocksDoor.TryGetValue(blockID, out doorNetID)) {
                float doorDecayCooldown;
                if (doorTimers.TryGetValue(doorNetID, out doorDecayCooldown)) {
                    Door door = BaseNetworkable.serverEntities.Find(doorNetID) as Door;
                    if (door != null && doorDecayCooldown > 0) {
                        return doorDecayCooldown;
                    }
                    else {
                        doorTimers.Remove(doorNetID);
                    }
                }
                blocksDoor.Remove(blockID);
            }
            var position = block.GetNetworkPosition();
            List<BaseEntity> nearby = new List<BaseEntity>();
            Vis.Entities(position, doorRadius, nearby, BuildingsLayer, QueryTriggerInteraction.Ignore);
            float timeout = -1;
            foreach (var entity in nearby) {
                var door = entity as Door;
                if (door != null) {
                    if (!doorTimers.TryGetValue(door.net.ID, out timeout) || timeout <= 0) continue;
                    blocksDoor[blockID] = door.net.ID;
                    break;
                }
            }
            return timeout;
        }
        void RunDecay() {
            if (decayCoroutine != null) CommunityEntity.ServerInstance.StopCoroutine(decayCoroutine);
            decayCoroutine = CommunityEntity.ServerInstance.StartCoroutine(Decay());
        }
        /// <summary>
        /// Start Stopwatch
        /// </summary>
        /// <param name = "name">KEY</param>
        public static void StopwatchStart(string name) {
            watches[name] = Stopwatch.StartNew();
        }
        /// <summary>
        /// Get Elapsed Milliseconds
        /// </summary>
        /// <param name = "name">KEY</param>
        /// <returns></returns>
        public static long StopwatchElapsedMilliseconds(string name) {
            return watches[name].ElapsedMilliseconds;
        }
        /// <summary>
        /// Remove StopWatch
        /// </summary>
        /// <param name = "name"></param>
        public static void StopwatchStop(string name) {
            watches.Remove(name);
        }
        IEnumerator Decay() {
            isdecay = true;
            PrintToChat("");
            List<uint> remove = doorTimers.Keys.ToList().Where(door => (doorTimers[door] -= timeout / 3600f) < 0).ToList();
            foreach (var d in remove) doorTimers.Remove(d);
            int i = 0;
            int count = decayEntities.Count;
            int die = 0;
            int lastpercent = -1;
            var start = DateTime.UtcNow;
            decayEntities.RemoveAll(item => item == null || item.IsDestroyed);
            StopwatchStart("DecaySystem");
            foreach (var block in decayEntities.ToArray()) {
                i++;
                var percent = (int)(i / (float)count * 100);
                if (StopwatchElapsedMilliseconds("DecaySystem") > 10 || percent != lastpercent) {
                    StopwatchStart("DecaySystem");
                    if (percent != lastpercent) {
                        if (percent % 20 == 0) Puts($"");
                        lastpercent = percent;
                        yield return new WaitForSeconds(0.2f);
                    }
                }
                if (Performance.report.frameRate < 150 || Performance.current.frameRate < 150 || i % 10 == 0) yield return new WaitForEndOfFrame();
                if (block == null) continue;
                if (block.IsDestroyed) continue;
                if (block.transform == null) continue;
                var t = GetDoorTimeout(block);
                var buildingBlock = block as BuildingBlock;
                if (t <= 0 || (buildingBlock != null && buildingBlock.grade == BuildingGrade.Enum.Twigs)) {
                    var inCupboard = block.GetBuildingPrivilege(block.WorldSpaceBounds());
                    var DecaySettings = inCupboard ? decaySettingsInCupboard : decaySettingsWithoutCupboard;
                    var multiplier = 1f;
                    var reply = 16;
                    float hp = 0f;
                    if (buildingBlock != null) {
                        switch (buildingBlock.grade) {
                            case BuildingGrade.Enum.Twigs : hp = block.MaxHealth() / TwigsTicks;
                            break;
                            case BuildingGrade.Enum.Wood : multiplier = MultiplierWood;
                            break;
                            case BuildingGrade.Enum.Stone : multiplier = MultiplierStone;
                            break;
                            case BuildingGrade.Enum.Metal : multiplier = MultiplierMetal;
                            break;
                            case BuildingGrade.Enum.TopTier : multiplier = MultiplierTopTier;
                            break;
                        }
                    }
                    if (Math.Abs(hp) < 0.001f) hp = block.MaxHealth() / (DecaySettings[block.ShortPrefabName] * multiplier);
                    block.Hurt(hp, DamageType.Decay);
                    if (block.IsDead()) {
                        die++;
                        yield return new WaitForEndOfFrame();
                    }
                }
            }
            var time = DateTime.UtcNow.Subtract(start).TotalSeconds.ToString("F2");
            Puts($"");
            PrintToChat($"");
            List<BaseCombatEntity> list = new List<BaseCombatEntity>(decayEntities.Count);
            i = 0;
            foreach (var p in decayEntities.ToArray()) {
                if (p != null) list.Add(p);
                if (i++ % 100 == 0) yield return new WaitForFixedUpdate();
            }
            decayEntities = list;
            isdecay = false;
        }
        void LoadDoorTimers() {
            doorTimers = doortimers_file.ReadObject<Dictionary<string, float>>().ToDictionary(v => uint.Parse(v.Key), t => t.Value);
            blocksDoor = blocksDoorFile.ReadObject<Dictionary<string, uint>>().ToDictionary(k => Convert.ToUInt32(k.Key), v => v.Value);
        }
        void Unload() {
            OnServerSave();
            if (decayCoroutine != null) ServerMgr.Instance.StopCoroutine(decayCoroutine);
        }
        void OnServerSave() {
            Dictionary<string, float> serializedTimers = new Dictionary<string, float>();
            foreach (var d in doorTimers) {
                if (!serializedTimers.ContainsKey(d.Key.ToString())) serializedTimers.Add(d.Key.ToString(), d.Value);
            }
            doortimers_file.WriteObject(serializedTimers);
            blocksDoorFile.WriteObject(blocksDoor.ToDictionary(k => k.Key.ToString(), v => v.Value));
        }
        void OnServerInitialized() {
            LoadDefaultConfig();
            LoadDoorTimers();
            timer.Every(timeout, RunDecay);
            InitDecayEntities();
        }
        void InitDecayEntities() {
            var ents = UnityEngine.Object.FindObjectsOfType<BaseCombatEntity>();
            decayEntities = new List<BaseCombatEntity>(ents.Length);
            foreach (var ent in ents) {
                if (ent == null) continue;
                DecayEntity decEnt = ent as DecayEntity;
                NextTick(() => {
                    if (decEnt != null) {
                        decEnt.CancelInvoke("RunDecay");
                    }
                    if (IsDecayEntity(ent)) decayEntities.Add(ent);
                }
                );
            }
            timer.Once(0.03f, () => {
                Puts($"Загрузка объектов прошла успешно! подсчитано: {decayEntities.Count}");
            }
            );
            init = true;
        }
        void OnEntitySpawned(BaseNetworkable entity) {
            if (!init) return;
            if (entity?.net?.ID == null) return;
            if (IsDecayEntity(entity) && !decayEntities.Contains((BaseCombatEntity)entity)) decayEntities.Add((BaseCombatEntity)entity);
            if (entity is Door) doorTimers[entity.net.ID] = doorTimeout;
            NextTick(() => {
                DecayEntity decEnt = entity as DecayEntity;
                if (decEnt != null) {
                    decEnt.CancelInvoke("RunDecay");
                }
            }
            );
        }
        bool IsDecayEntity(BaseNetworkable entity) {
            if (decaySettingsInCupboard.ContainsKey(entity.ShortPrefabName)) {
                if (!baseDecayPrefabs.Contains(entity.ShortPrefabName)) {
                    RaycastHit hit;
                    var ray = new Ray(entity.transform.position + offset, entity.transform.TransformDirection(UnityEngine.Vector3.down));
                    if (!Physics.Raycast(ray, out hit, 5, WorldBuildingsLayer, QueryTriggerInteraction.Ignore)) return true;
                    if (hit.transform.gameObject.layer == BuildingsLayer) return false;
                }
                return true;
            }
            return false;
        }
        void OnEntityKill(BaseNetworkable entity) {
            if (!init) return;
            if (entity?.net?.ID == null) return;
            if (entity is Door) doorTimers.Remove(entity.net.ID);
            var combatEnt = entity as BaseCombatEntity;
            if (combatEnt != null && decaySettingsInCupboard.ContainsKey(entity.ShortPrefabName)) decayEntities.Remove(combatEnt);
        }
        void OnDoorOpened(Door door, BasePlayer player) {
            DoorHandle(door);
        }
        void OnDoorClosed(Door door, BasePlayer player) {
            DoorHandle(door);
        }
        bool inZone(UnityEngine.Vector3 vec) {
            if (ZoneManager == null) return false;
            return (bool)ZoneManager.Call("inZone", vec);
        }
    }
}

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