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

FREE SpawnControl : 1.3.9 1.3.9

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Text;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Reflection;
using UnityEngine;
using Oxide.Core;
using Oxide.Core.Configuration;
using ProtoBuf;
using Apex;
using Rust;
namespace Oxide.Plugins {
    [Info("SpawnControl", "Fujikura", "1.3.9", ResourceId = 18)]
    class SpawnControl : RustPlugin {
        bool Changed = false;
        bool _loaded;
        bool _startup;
        bool _terrainReady;
        bool heartbeatOn = false;
        double lastMinute;
        bool newSave;
        bool runningEnforceLimits;
        bool runningSpawnKill;
        bool runningSpawnLowerDensity;
        bool runningSpawnRaiseDensity;
        bool runningSpawnFill;
        Dictionary <string, object> spawnPopulations = new Dictionary <string, object>();
        Dictionary <string, object> spawnGroups = new Dictionary <string, object>();
        Dictionary<string, object> spawnDefaults = new Dictionary<string, object>();
        Dictionary<string, object> spawnPrefabDefaults = new Dictionary<string, object>();
        List<string> PopulationNames = new List<string>();
        Dictionary<string, ConvarControlledSpawnPopulation> convarCommands = new Dictionary<string, ConvarControlledSpawnPopulation>();
        Dictionary<string, string> populationConvars = new Dictionary<string, string>();
        Dictionary <string, int> fillPopulations = new Dictionary <string, int>();
        Dictionary <string, int> fillJobs = new Dictionary <string, int>();
        DynamicConfigFile defaultSpawnPops;
        DynamicConfigFile getFile(string file) => Interface.Oxide.DataFileSystem.GetDatafile($"{file}");
        bool chkFile(string file) => Interface.Oxide.DataFileSystem.ExistsDatafile($"{file}");
        FieldInfo _numToSpawn = typeof (SpawnPopulation).GetField("numToSpawn", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        FieldInfo _targetDensity = typeof (SpawnPopulation).GetField("_targetDensity", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        FieldInfo _SpawnInstances = typeof (SpawnGroup).GetField("spawnInstances", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        FieldInfo _SpawnDistributions = typeof(SpawnHandler).GetField("SpawnDistributions", (BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public));
        FieldInfo _spawnClock = typeof(SpawnGroup).GetField("spawnClock", BindingFlags.NonPublic | BindingFlags.Instance);
        FieldInfo _AllSpawnPopulations = typeof(SpawnHandler).GetField("AllSpawnPopulations", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        MethodInfo _SpawnGroupTick = typeof(SpawnHandler).GetMethod("SpawnGroupTick", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        MethodInfo _SpawnTick = typeof(SpawnHandler).GetMethod("SpawnTick", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        IEnumerator coSpawnTick;
        IEnumerator coSpawnGroupTick;
        SpawnHandler _Handle = SpawnHandler?.Instance;
        bool enableSpawnGroups;
        bool enableGroupTickData;
        bool enablePopulationPrefabs;
        bool normalizeDefaultVariables;
        bool reloadWithIncludedFill;
        bool logJobsToConsole;
        bool fixBarricadeStacking;
        float tickInterval;
        int minSpawnsPerTick;
        int maxSpawnsPerTick;
        object GetConfig(string menu, string datavalue, object defaultValue) {
            var data = Config[menu] as Dictionary<string, object>;
            if (data == null) {
                data = new Dictionary<string, object>();
                Config[menu] = data;
                Changed = true;
            }
            object value;
            if (!data.TryGetValue(datavalue, out value)) {
                value = defaultValue;
                data[datavalue] = value;
                Changed = true;
            }
            return value;
        }
        void LoadVariables() {
            spawnPopulations = (Dictionary <string, object>)GetConfig("Spawn", "Population", new Dictionary<string, object>());
            spawnGroups = (Dictionary <string, object>)GetConfig("Spawn", "Groups", new Dictionary<string, object>());
            enableSpawnGroups = Convert.ToBoolean(GetConfig("Generic", "enableSpawnGroups", false));
            enableGroupTickData = Convert.ToBoolean(GetConfig("Generic", "enableGroupTickData", false));
            enablePopulationPrefabs = Convert.ToBoolean(GetConfig("Generic", "enablePopulationPrefabs", false));
            normalizeDefaultVariables = Convert.ToBoolean(GetConfig("Generic", "normalizeDefaultVariables", true));
            reloadWithIncludedFill = Convert.ToBoolean(GetConfig("Generic", "reloadWithIncludedFill", false));
            logJobsToConsole = Convert.ToBoolean(GetConfig("Generic", "logJobsToConsole", true));
            fixBarricadeStacking = Convert.ToBoolean(GetConfig("Generic", "fixBarricadeStacking", true));
            tickInterval = Convert.ToSingle(GetConfig("Handler", "tickInterval", 120.0f));
            minSpawnsPerTick = Convert.ToInt32(GetConfig("Handler", "minSpawnsPerTick", 100));
            maxSpawnsPerTick = Convert.ToInt32(GetConfig("Handler", "maxSpawnsPerTick", 200));
            var configremoval = false;
            if ((Config.Get("Animals") as Dictionary<string, object>) != null) {
                Config.Remove("Animals");
                configremoval = true;
            }
            if (!Changed && !configremoval) return;
            SaveConfig();
            Changed = false;
            configremoval = false;
        }
        protected override void LoadDefaultConfig() {
            Config.Clear();
            LoadVariables();
        }
        void Init() {
            LoadVariables();
            _terrainReady = false;
            _startup = true;
            if (normalizeDefaultVariables) {
                ConVar.Spawn.max_density = 1f;
                ConVar.Spawn.max_rate = 1f;
                ConVar.Spawn.min_density = 0.5f;
                ConVar.Spawn.min_rate = 0.5f;
            }
            newSave = false;
            lastMinute = DateTime.UtcNow.Minute;
            _Handle = SpawnHandler.Instance;
        }
        void OnNewSave(string strFilename) {
            newSave = true;
        }
        void Unload() {
            ServerMgr.Instance.StopCoroutine("SpawnKill");
            ServerMgr.Instance.StopCoroutine("SpawnFill");
            ServerMgr.Instance.StopCoroutine("EnforceLimits");
            ServerMgr.Instance.StopCoroutine("SpawnLowerDensity");
            ServerMgr.Instance.StopCoroutine("SpawnRaiseDensity");
            runningEnforceLimits = false;
            runningSpawnKill = false;
            runningSpawnLowerDensity = false;
            runningSpawnRaiseDensity = false;
            runningSpawnFill = false;
        }
        void OnTerrainInitialized() {
            if (_startup && !newSave) {
                _terrainReady = true;
                GetPopulationDefaults();
            }
            _Handle.MaxSpawnsPerTick = maxSpawnsPerTick;
            _Handle.MinSpawnsPerTick = minSpawnsPerTick;
            if (spawnPopulations != null && spawnPopulations.Count > 0) {
                SpawnPopLoad();
            }
            else {
                SpawnPopDefaults();
            }
            if (enableSpawnGroups) {
                if (spawnGroups != null && spawnGroups.Count > 0) SpawnGroupLoad();
                else SpawnGroupDefaults();
            }
            if (_startup && !newSave) _terrainReady = true;
            _loaded = true;
        }
        void GetPopulationDefaults() {
            _Handle = SpawnHandler.Instance;
            spawnDefaults = new Dictionary<string, object>();
            spawnPrefabDefaults = new Dictionary<string, object>();
            foreach (var population in (_AllSpawnPopulations.GetValue(_Handle) as SpawnPopulation[]).ToList().Where(x => x != null)) {
                var prefabdata = new Dictionary<string, object>();
                var prefabs = population.Prefabs;
                if (prefabs == null || prefabs.Length == 0) {
                    if (!string.IsNullOrEmpty(population.ResourceFolder)) prefabs = Prefab.Load<Spawnable>(string.Concat("assets/bundled/prefabs/autospawn/", population.ResourceFolder), GameManager.server, PrefabAttribute.server);
                    if (population.ResourceList != null && population.ResourceList.Length > 0) prefabs = Prefab.Load<Spawnable>(population.ResourceList.Select(x => x.resourcePath).ToArray(), GameManager.server, PrefabAttribute.server);
                }
                var counts = prefabs.GroupBy(x => x.Name).ToDictionary(g => g.Key.ToLower(), g => g.Count());
                foreach (var prefab in counts) prefabdata.Add(prefab.Key.ToLower(), prefab.Value );
                spawnPrefabDefaults.Add(population.name, prefabdata);
                spawnDefaults.Add(population.name, population.TargetDensity);
            }
            defaultSpawnPops = getFile($"{this.Title}_defaults");
            defaultSpawnPops.Clear();
            defaultSpawnPops.Set("Backup", spawnDefaults);
            defaultSpawnPops.Set("PrefabBackup", spawnPrefabDefaults);
            defaultSpawnPops.Save();
        }
        void LoadPopulationDefaults() {
            if (spawnDefaults == null || spawnDefaults.Count == 0) {
                spawnDefaults = new Dictionary<string, object>();
                defaultSpawnPops = getFile($"{this.Title}_defaults");
                spawnDefaults = defaultSpawnPops["Backup"] as Dictionary<string, object>;
                spawnPrefabDefaults = defaultSpawnPops["PrefabBackup"] as Dictionary<string, object>;
            }
        }
        void OnServerInitialized() {
            _startup = false;
            GetPopulationNames();
            if (!_loaded) OnTerrainInitialized();
            if (fillJobs.Count > 0) Puts($"Planned {fillJobs.Count} job(s) for spawn population");
            FixBarricades();
            LoadPopulationDefaults();
            if (_terrainReady) {
                ReloadAnimals();
                NextTick(()=> Global.Runner.StartCoroutine(EnforceLimits(true, null)));
            }
        }
        void OnTick() {
            if (!_loaded || !heartbeatOn || lastMinute == DateTime.UtcNow.Minute || CheckRoutines() ) return;
            lastMinute = DateTime.UtcNow.Minute;
            foreach (var job in fillJobs.ToList()) {
                if ((int)fillJobs[job.Key] < 1) {
                    timer.Once(2f, ()=> ConsoleSystem.Run(ConsoleSystem.Option.Server.Quiet(), "sc.fill", new object[] {
                        job.Key.ToString(), "auto"
                    }
                    ));
                    fillJobs[job.Key] = fillPopulations[job.Key];
                }
                else fillJobs[job.Key] = (int)job.Value -1;
            }
        }
        bool CheckRoutines() {
            if (runningEnforceLimits || runningSpawnKill || runningSpawnLowerDensity || runningSpawnRaiseDensity || runningSpawnFill) return true;
            return false;
        }
        void GetPopulationNames() {
            _Handle = SpawnHandler.Instance;
            PopulationNames = new List<string>();
            foreach (var pop in _Handle.AllSpawnPopulations.Where(x => x != null).Distinct().ToList()) PopulationNames.Add(pop.name);
            convarCommands = new Dictionary<string, ConvarControlledSpawnPopulation>();
            populationConvars = new Dictionary<string, string>();
            foreach (var pop in _Handle.ConvarSpawnPopulations.ToList().Where(x => x != null)) {
                populationConvars.Add((pop as ConvarControlledSpawnPopulation).PopulationConvar, pop.name);
                convarCommands.Add(pop.name, pop as ConvarControlledSpawnPopulation);
            }
        }
        void OnServerCommand(ConsoleSystem.Arg arg) {
            if (arg == null || arg.cmd == null || arg.FullString == string.Empty || arg.cmd.FullName == string.Empty) return;
            if (populationConvars.ContainsKey(arg.cmd.FullName)) {
                float targetDensity = -2;
                float.TryParse(arg.Args[0], out targetDensity);
                (spawnPopulations[populationConvars[arg.cmd.FullName]] as Dictionary<string, object>)["spawndensity"] = targetDensity;
                Config["Spawn", "Population"] = spawnPopulations;
                Config.Save();
            }
        }
        void SpawnPopDefaults() {
            var data = new Dictionary<string, object>();
            spawnPopulations.Clear();
            foreach (var population in (_AllSpawnPopulations.GetValue(_Handle) as SpawnPopulation[]).ToList().Where(x => x != null)) {
                var populationdata = new Dictionary<string, object>();
                populationdata.Add("spawndensity", population.TargetDensity);
                populationdata.Add("spawnrate", population.SpawnRate);
                populationdata.Add("spawnlimits", population.EnforcePopulationLimits);
                populationdata.Add("spawnfillheartbeat", 0);
                if (enablePopulationPrefabs) {
                    var prefabs = population.Prefabs;
                    if (prefabs == null || prefabs.Length == 0) {
                        if (!string.IsNullOrEmpty(population.ResourceFolder)) population.Prefabs = Prefab.Load<Spawnable>(string.Concat("assets/bundled/prefabs/autospawn/", population.ResourceFolder), GameManager.server, PrefabAttribute.server);
                        if (population.ResourceList != null && population.ResourceList.Length > 0) population.Prefabs = Prefab.Load<Spawnable>(population.ResourceList.Select(x => x.resourcePath).ToArray(), GameManager.server, PrefabAttribute.server);
                        prefabs = population.Prefabs;
                    }
                    var counts = prefabs.GroupBy(x => x.Name).ToDictionary(g => g.Key.ToLower(), g => g.Count());
                    var prefabdata = new Dictionary<string, object>();
                    foreach (var prefab in counts) prefabdata.Add(prefab.Key.ToLower(), prefab.Value );
                }
                data.Add(population.name, populationdata);
            }
            spawnPopulations = new Dictionary<string, object>(data);
            Config["Spawn", "Population"] = spawnPopulations;
            Config.Save();
            Puts($"Created SpawnPopulation with '{data.Count}' populations.");
        }
        void SpawnPopLoad() {
            Dictionary<string, object> data = new Dictionary<string, object>(spawnPopulations);
            if (data == null || data.Count() == 0) {
                SpawnPopDefaults();
                return;
            }
            bool changed = false;
            if (PopulationNames == null || PopulationNames.Count == 0) foreach (var pop in (_AllSpawnPopulations.GetValue(_Handle) as SpawnPopulation[]).Where(x => x != null).Distinct().ToList()) PopulationNames.Add(pop.name);
            foreach (var population in data.ToList()) {
                if (!PopulationNames.Contains(population.Key.ToString())) {
                    data.Remove(population.Key);
                    Puts($"Removed old SpawnPopulation: {population.Key}");
                    changed = true;
                    continue;
                }
            }
            foreach (var population in (_AllSpawnPopulations.GetValue(_Handle) as SpawnPopulation[]).ToList().Where(x => x != null)) {
                var name = population.name;
                if (name == null) continue;
                if (!data.ContainsKey(name)) {
                    var populationdata = new Dictionary<string, object>();
                    populationdata.Add("spawndensity", population.TargetDensity);
                    populationdata.Add("spawnrate", population.SpawnRate);
                    populationdata.Add("spawnlimits", population.EnforcePopulationLimits);
                    populationdata.Add("spawnfillheartbeat", 0);
                    if (enablePopulationPrefabs) {
                        var prefabs = population.Prefabs;
                        if (prefabs == null || prefabs.Length == 0) {
                            if (!string.IsNullOrEmpty(population.ResourceFolder)) population.Prefabs = Prefab.Load<Spawnable>(string.Concat("assets/bundled/prefabs/autospawn/", population.ResourceFolder), GameManager.server, PrefabAttribute.server);
                            if (population.ResourceList != null && population.ResourceList.Length > 0) population.Prefabs = Prefab.Load<Spawnable>(population.ResourceList.Select(x => x.resourcePath).ToArray(), GameManager.server, PrefabAttribute.server);
                            prefabs = population.Prefabs;
                        }
                        var counts = prefabs.GroupBy(x => x.Name).ToDictionary(g => g.Key, g => g.Count());
                        var prefabdata = new Dictionary<string, object>();
                        foreach (var prefab in counts) prefabdata.Add(prefab.Key, prefab.Value );
                        populationdata.Add("spawnweights", prefabdata);
                    }
                    data.Add(name, populationdata);
                    Puts($"Added new SpawnPopulation: {name}");
                    changed = true;
                }
            }
            spawnPopulations = new Dictionary<string, object>(data);
            if (changed) {
                Config["Spawn", "Population"] = spawnPopulations;
                Config.Save();
            }
            bool addedPrefabs = false;
            foreach (var spawnPopulation in (_AllSpawnPopulations.GetValue(_Handle) as SpawnPopulation[]).ToList().Where(x => x != null)) {
                object spawndata;
                if (!data.TryGetValue(spawnPopulation.name, out spawndata)) continue;
                Dictionary<string, object> spawnData = spawndata as Dictionary<string, object>;
                if (enablePopulationPrefabs && !spawnData.ContainsKey("spawnweights")) {
                    var prefabs = spawnPopulation.Prefabs;
                    if (prefabs == null || prefabs.Length == 0) {
                        if (!string.IsNullOrEmpty(spawnPopulation.ResourceFolder)) spawnPopulation.Prefabs = Prefab.Load<Spawnable>(string.Concat("assets/bundled/prefabs/autospawn/", spawnPopulation.ResourceFolder), GameManager.server, PrefabAttribute.server);
                        if (spawnPopulation.ResourceList != null && spawnPopulation.ResourceList.Length > 0) spawnPopulation.Prefabs = Prefab.Load<Spawnable>(spawnPopulation.ResourceList.Select(x => x.resourcePath).ToArray(), GameManager.server, PrefabAttribute.server);
                        prefabs = spawnPopulation.Prefabs;
                    }
                    var counts = prefabs.GroupBy(x => x.Name).ToDictionary(g => g.Key.ToLower(), g => g.Count());
                    var prefabdata = new Dictionary<string, object>();
                    foreach (var prefab in counts) prefabdata.Add(prefab.Key.ToLower(), prefab.Value );
                    spawnData.Add("spawnweights", prefabdata);
                    addedPrefabs = true;
                }
                if (enablePopulationPrefabs && spawnData.ContainsKey("spawnweights")) {
                    Dictionary<string, object> prefabData = spawnData["spawnweights"] as Dictionary<string, object>;
                    var prefabs = new List<Prefab<Spawnable>>();
                    foreach (var prefab in prefabData.ToList()) {
                        var gameObject = GameManager.server.FindPrefab(prefab.Key);
                        if (gameObject == null) {
                            Puts($"Removed invalid/removed prefab from '{spawnPopulation.name}': {prefab.Key}");
                            ((data[spawnPopulation.name] as Dictionary<string, object>)["spawnweights"] as Dictionary<string, object>).Remove(prefab.Key);
                            addedPrefabs = true;
                        }
                        var component = gameObject?.GetComponent<Spawnable>();
                        if (component == null) continue;
                        for (var i = 0; i < Convert.ToInt32(prefab.Value);
                        i++) prefabs.Add(new Prefab<Spawnable>(prefab.Key.ToLower(), gameObject, component, GameManager.server, PrefabAttribute.server));
                    }
                    spawnPopulation.Prefabs= prefabs.ToArray();
                    _numToSpawn.SetValue(spawnPopulation, new int[prefabs.ToArray().Length]);
                }
                spawnPopulation.EnforcePopulationLimits = Convert.ToBoolean(spawnData["spawnlimits"]);
                spawnPopulation.SpawnRate = Convert.ToSingle(spawnData["spawnrate"]);
                _targetDensity.SetValue(spawnPopulation, Convert.ToSingle(spawnData["spawndensity"]));
                SetAnimal(spawnPopulation.name, Convert.ToSingle(spawnData["spawndensity"]));
                if ((int)spawnData["spawnfillheartbeat"] > 0 ) {
                    fillPopulations.Add(spawnPopulation.name, (int)spawnData["spawnfillheartbeat"]);
                    heartbeatOn = true;
                }
            }
            if (addedPrefabs) {
                spawnPopulations = new Dictionary<string, object>(data);
                Config["Spawn", "Population"] = spawnPopulations;
                Config.Save();
            }
            if (heartbeatOn) fillJobs = new Dictionary<string, int>(fillPopulations);
            Puts($"Loaded '{data.Count}' SpawnPopulations");
        }
        void ReloadAnimals() {
            Dictionary<string, object> data = new Dictionary<string, object>(spawnPopulations);
            if (data == null || data.Count() == 0) {
                SpawnPopDefaults();
                return;
            }
            foreach (var spawnPopulation in (_AllSpawnPopulations.GetValue(_Handle) as SpawnPopulation[]).ToList().Where(x => x != null)) {
                object spawndata;
                if (!data.TryGetValue(spawnPopulation.name, out spawndata)) continue;
                if (!convarCommands.ContainsKey(spawnPopulation.name)) continue;
                Dictionary<string, object> spawnData = spawndata as Dictionary<string, object>;
                spawnPopulation.EnforcePopulationLimits = Convert.ToBoolean(spawnData["spawnlimits"]);
                spawnPopulation.SpawnRate = Convert.ToSingle(spawnData["spawnrate"]);
                _targetDensity.SetValue(spawnPopulation, Convert.ToSingle(spawnData["spawndensity"]));
                SetAnimal(spawnPopulation.name, Convert.ToSingle(spawnData["spawndensity"]));
            }
        }
        void SetAnimal(string name, float value) {
            if (convarCommands.ContainsKey(name)) ConsoleSystem.Run(ConsoleSystem.Option.Server.Quiet(), $"{convarCommands[name].PopulationConvar} {value.ToString()}");
        }
        void SpawnGroupDefaults() {
            if (!enableSpawnGroups) return;
            spawnGroups.Clear();
            foreach (var monument in UnityEngine.Object.FindObjectsOfType<MonumentInfo>()) {
                if (spawnGroups.ContainsKey(PrefabCut(monument.name))) continue;
                foreach(var group in monument.gameObject.GetComponentsInChildren<SpawnGroup>()) {
                    if (group.name.StartsWith("door_barricade") || group.name.StartsWith("Barricades") || group.name.StartsWith("Ore")) continue;
                    Dictionary <string, object> spawner = new Dictionary <string, object>();
                    spawner.Add("_refName", group.name);
                    spawner.Add("_refNumber", group.maxPopulation);
                    spawner.Add("delayMin", group.respawnDelayMin);
                    spawner.Add("delayMax", group.respawnDelayMax);
                    if (enableGroupTickData) {
                        spawner.Add("perTickMin", group.numToSpawnPerTickMin);
                        spawner.Add("perTickMax", group.numToSpawnPerTickMax);
                    }
                    if (!spawnGroups.ContainsKey(PrefabCut(monument.name))) spawnGroups.Add(PrefabCut(monument.name), new List<object>());
                    (spawnGroups[PrefabCut(monument.name)] as List<object>).Add(spawner);
                }
            }
            Config["Spawn", "Groups"] = spawnGroups;
            Config.Save();
            Puts($"Created '{spawnGroups.Count()}' spawnGroups");
        }
        void SpawnGroupLoad() {
            if (!enableSpawnGroups) return;
            if (spawnGroups == null || spawnGroups.Count() == 0) {
                SpawnGroupDefaults();
                return;
            }
            bool addedMonument = false;
            bool addedGroup = false;
            bool addedTickData = false;
            List<string> alreadySeenMonuments = new List<string>();
            foreach (var monument in UnityEngine.Object.FindObjectsOfType<MonumentInfo>()) {
                if (alreadySeenMonuments.Contains(monument.name)) continue;
                alreadySeenMonuments.Add(monument.name);
                MethodInfo spawnMethod = null;
                if (!spawnGroups.ContainsKey(PrefabCut(monument.name))) {
                    foreach(var group in monument.gameObject.GetComponentsInChildren<SpawnGroup>()) {
                        if (group.name.StartsWith("door_barricade") || group.name.StartsWith("Barricades") || group.name.StartsWith("Ore")) continue;
                        Dictionary <string, object> spawner = new Dictionary <string, object>();
                        spawner.Add("_refName", group.name);
                        spawner.Add("_refNumber", group.maxPopulation);
                        spawner.Add("delayMin", group.respawnDelayMin);
                        spawner.Add("delayMax", group.respawnDelayMax);
                        if (enableGroupTickData) {
                            spawner.Add("perTickMin", group.numToSpawnPerTickMin);
                            spawner.Add("perTickMax", group.numToSpawnPerTickMax);
                        }
                        if (!spawnGroups.ContainsKey(PrefabCut(monument.name))) {
                            spawnGroups.Add(PrefabCut(monument.name), new List<object>());
                            addedMonument = true;
                        }
                        (spawnGroups[PrefabCut(monument.name)] as List<object>).Add(spawner);
                    }
                    continue;
                }
                List<object> filegroups = (spawnGroups[PrefabCut(monument.name)] as List<object>);
                foreach(var group in monument.gameObject.GetComponentsInChildren<SpawnGroup>()) {
                    if (group.name.StartsWith("door_barricade") || group.name.StartsWith("Barricades") || group.name.StartsWith("Ore")) continue;
                    bool groupMatch = false;
                    foreach (var filegroup in filegroups) {
                        Dictionary<string, object> groupdata = filegroup as Dictionary<string, object>;
                        if ((string)groupdata["_refName"] == group.name && (int)groupdata["_refNumber"] == group.maxPopulation) {
                            group.respawnDelayMin = Convert.ToSingle(groupdata["delayMin"]);
                            group.respawnDelayMax = Convert.ToSingle(groupdata["delayMax"]);
                            if (enableGroupTickData) {
                                if (!groupdata.ContainsKey("perTickMin")) {
                                    groupdata.Add("perTickMin", group.numToSpawnPerTickMin);
                                    addedTickData = true;
                                }
                                if (!groupdata.ContainsKey("perTickMax")) {
                                    groupdata.Add("perTickMax", group.numToSpawnPerTickMax);
                                    addedTickData = true;
                                }
                                group.numToSpawnPerTickMin = (int)groupdata["perTickMin"];
                                group.numToSpawnPerTickMax = (int)groupdata["perTickMax"];
                            }
                            LocalClock spawnClock = (LocalClock)_spawnClock.GetValue(group);
                            if (spawnClock.events != null && spawnClock.events.Count > 0) {
                                Action action = new Action(spawnClock.events.First().action);
                                spawnClock = new LocalClock();
                                spawnClock.Add(group.GetSpawnDelta(), group.GetSpawnVariance(), action);
                                spawnClock.Tick();
                                _spawnClock.SetValue(group, spawnClock);
                            }
                            groupMatch = true;
                        }
                    }
                    if (!groupMatch) {
                        Dictionary <string, object> spawner = new Dictionary <string, object>();
                        spawner.Add("_refName", group.name);
                        spawner.Add("_refNumber", group.maxPopulation);
                        spawner.Add("delayMin", group.respawnDelayMin);
                        spawner.Add("delayMax", group.respawnDelayMax);
                        if (enableGroupTickData) {
                            spawner.Add("perTickMin", group.numToSpawnPerTickMin);
                            spawner.Add("perTickMax", group.numToSpawnPerTickMax);
                        }
                        (spawnGroups[PrefabCut(monument.name)] as List<object>).Add(spawner);
                        addedGroup = true;
                    }
                }
            }
            if (addedMonument || addedGroup || addedTickData) {
                Config["Spawn", "Groups"] = spawnGroups;
                Config.Save();
            }
            Puts($"Loaded '{spawnGroups.Count()}' spawnGroups");
            _Handle.StartSpawnTick();
        }
        void FixBarricades() {
            if (fixBarricadeStacking) return;
            var spawns = Resources.FindObjectsOfTypeAll<BaseEntity>().Where(c => c.isActiveAndEnabled && c.ShortPrefabName.StartsWith("door_barricade")).OrderBy(c => c.transform.position.x).ThenBy(c => c.transform.position.z).ThenBy(c => c.transform.position.z).ToList();
            var count = spawns.Count();
            var racelimit = count * count;
            var antirace = 0;
            var deleted = 0;
            for (var i = 0; i < count; i++) {
                var box = spawns[i];
                var next = i + 1;
                var pos = new Vector2(box.transform.position.x, box.transform.position.z);
                if (++antirace > racelimit) return;
                while (next < count) {
                    var box2 = spawns[next];
                    var pos2 = new Vector2(box2.transform.position.x, box2.transform.position.z);
                    var distance = Vector2.Distance(pos, pos2);
                    if (++antirace > racelimit) return;
                    if (distance < 0.5f) {
                        spawns.RemoveAt(next);
                        count--;
                        (box2 as BaseEntity).Kill();
                        deleted++;
                    }
                    else break;
                }
            }
            if (deleted > 0) Puts($"Removed {deleted} stacked DoorBarricades.");
        }
        void OnEntitySpawned(BaseNetworkable entity) {
            if (!_loaded || !fixBarricadeStacking || entity == null || !(entity as BaseEntity).ShortPrefabName.StartsWith("door_barricade")) return;
            NextTick(()=> {
                if (entity == null) return;
                BaseEntity[] stacked = null;
                try {
                    stacked = Physics.OverlapSphere(entity.transform.position, 0.5f).Where(entry => entry != null && entry.GetComponentInParent<BaseEntity>() != null && entry.GetComponentInParent<BaseEntity>().ShortPrefabName.StartsWith("door_barricade")).Select(entry => entry.GetComponentInParent<BaseEntity>()).Distinct().OrderByDescending(c => c.net.ID).ToArray();
                }
                catch {
                }
                if (stacked != null && stacked.Length > 1) for (int i = 0; i < stacked.Length - 1; i++) stacked[i].Kill();
            }
            );
        }
        [ConsoleCommand("sc.cleardata")]
        void ccmdClearData(ConsoleSystem.Arg arg) {
            if(arg.Connection != null && arg.Connection.authLevel < 2) return;
            string data = string.Empty;
            if (arg.Args == null || arg.Args.Length < 1) {
                SendReply(arg, "You need to provide 'weights', 'population', 'groups' or 'all'");
                return;
            }
            data = arg.Args[0];
            if (data == "weights") {
                foreach (var pop in spawnPopulations) if ((spawnPopulations[pop.Key] as Dictionary <string, object>).ContainsKey("spawnweights")) (spawnPopulations[pop.Key] as Dictionary <string, object>).Remove("spawnweights");
                Config["Spawn", "Population"] = spawnPopulations;
                Config.Save();
                SendReply(arg, "Did reset weights data");
            }
            else if (data == "population") {
                spawnPopulations.Clear();
                Config["Spawn", "Population"] = spawnPopulations;
                Config.Save();
                SendReply(arg, "Did reset population data.");
            }
            else if (data == "groups") {
                spawnGroups.Clear();
                Config["Spawn", "Groups"] = spawnGroups;
                Config.Save();
                SendReply(arg, "Did reset groups data");
            }
            else if (data == "all") {
                spawnGroups.Clear();
                spawnPopulations.Clear();
                Config["Spawn", "Groups"] = spawnGroups;
                Config["Spawn", "Population"] = spawnPopulations;
                Config.Save();
                SendReply(arg, "Did reset all data.Next server boot loads the game defaults");
            }
            else {
                SendReply(arg, "You need to provide 'weights', 'population', 'groups' or 'all'");
                return;
            }
            SendReply(arg, "Next server boot writes the game defaults back into the config.");
        }
        [ConsoleCommand("sc.tickinterval")]
        void ccmdTickInterval(ConsoleSystem.Arg arg) {
            if(arg.Connection != null && arg.Connection.authLevel < 2) return;
            var _handler = _Handle;
            float currTickInterval = _handler.TickInterval;
            if (arg.Args == null) {
                SendReply(arg, $"Current TickInterval is '{currTickInterval}' seconds");
                return;
            }
            if (arg.Args != null && arg.Args.Length >0) {
                float input = 0f;
                if (float.TryParse(arg.Args[0], out input)) {
                    currTickInterval = input;
                    SendReply(arg, $"TickInterval set to '{currTickInterval}' seconds");
                    _handler.TickInterval = currTickInterval;
                    if (currTickInterval != tickInterval) {
                        tickInterval = currTickInterval;
                        Config["Handler", "tickInterval"] = tickInterval;
                        Config.Save();
                    }
                    return;
                }
                else {
                    SendReply(arg, "You need to provide a full number in seconds");
                    return;
                }
            }
        }
        [ConsoleCommand("sc.fill")]
        void ccmdSpawnFill(ConsoleSystem.Arg arg) {
            if(arg.Connection != null && arg.Connection.authLevel < 2) return;
            string populationname = string.Empty;
            bool single = false;
            if (arg.Args != null && arg.Args.Length >0) {
                populationname = arg.Args[0];
                single = true;
            }
            Global.Runner.StartCoroutine(SpawnFill(populationname, single, arg));
        }
        IEnumerator SpawnFill(string populationname, bool single, ConsoleSystem.Arg arg) {
            runningSpawnFill = true;
            yield return new WaitWhile(new System.Func<bool>(() => runningEnforceLimits));
            var allSpawnPopulations = (_AllSpawnPopulations.GetValue(_Handle) as SpawnPopulation[]).ToList().Where(x => x != null).ToArray();
            bool findany = false;
            if (single) {
                bool fullMatch = false;
                SpawnDistribution[] spawndists = (SpawnDistribution[])_SpawnDistributions.GetValue(_Handle);
                for (int i = 0; i < allSpawnPopulations.Length; i++) {
                    if (!(allSpawnPopulations[i] == null)) {
                        if ((allSpawnPopulations[i].name.StartsWith(populationname) || allSpawnPopulations[i].name.EndsWith(populationname)) && !fullMatch) {
                            if (allSpawnPopulations[i].name == populationname) fullMatch = true;
                            int oldCount = _Handle.GetCurrentCount(allSpawnPopulations[i], spawndists[i]);
                            _Handle.SpawnInitial(allSpawnPopulations[i], spawndists[i]);
                            if (arg.Args.Length > 1 && arg.Args[1] == "auto") if (logJobsToConsole) SendReply(arg, $"Timed population of '{allSpawnPopulations[i].name}' | Old: {oldCount} | New: {_Handle.GetCurrentCount(allSpawnPopulations[i], spawndists[i])}");
                            if (arg.Args.Length == 1) SendReply(arg, $"Forced population of '{allSpawnPopulations[i].name}' | Old: {oldCount} | New: {_Handle.GetCurrentCount(allSpawnPopulations[i], spawndists[i])}");
                            findany = true;
                            yield return new WaitForEndOfFrame();
                        }
                    }
                }
                if (!findany) SendReply(arg, $"SpawnPopulation '{populationname}' not found");
            }
            else {
                int oldCount = 0;
                int newCount = 0;
                SendReply(arg, "Filling All SpawnPopulations");
                SpawnDistribution[] spawndists = (SpawnDistribution[])_SpawnDistributions.GetValue(_Handle);
                for (int i = 0; i < allSpawnPopulations.Length; i++) {
                    if (!(allSpawnPopulations[i] == null)) {
                        oldCount += _Handle.GetCurrentCount(allSpawnPopulations[i], spawndists[i]);
                        _Handle.SpawnInitial(allSpawnPopulations[i], spawndists[i]);
                        newCount += _Handle.GetCurrentCount(allSpawnPopulations[i], spawndists[i]);
                        yield return new WaitForEndOfFrame();
                    }
                }
                SendReply(arg, $"Filled SpawnPopulations | Old: {oldCount} | New: {newCount}");
            }
            _Handle.FillGroups();
            runningSpawnFill = false;
            yield return null;
        }
        [ConsoleCommand("sc.raisedensity")]
        void ccmdSpawnRaiseDensity(ConsoleSystem.Arg arg) {
            if(arg.Connection != null && arg.Connection.authLevel < 2) return;
            float percentage = 0f;
            string populationname = string.Empty;
            if (arg.Args == null || arg.Args.Length < 2) {
                SendReply(arg, "You need to provide a number as percantage and a valid SpawnPopulation name");
                return;
            }
            float percent = -1;
            if (float.TryParse(arg.Args[0], out percent)) percentage = percent;
            else {
                SendReply(arg, "You need to provide a number as percentage");
                return;
            }
            if (percentage > 100f) {
                percentage = 100f;
                SendReply(arg, "Percentage was limited to 100% to avoid server freezes");
            }
            populationname = arg.Args[1];
            bool raiseAll = false;
            if (populationname == "all") raiseAll = true;
            SendReply(arg, $"Calling raise of density with '{percentage}' percent for '{populationname}'");
            Global.Runner.StartCoroutine(SpawnRaiseDensity(percentage, populationname, raiseAll, arg));
        }
        IEnumerator SpawnRaiseDensity(float percentage, string populationname, bool raiseAll, ConsoleSystem.Arg arg) {
            runningSpawnRaiseDensity = true;
            var allSpawnPopulations = (_AllSpawnPopulations.GetValue(_Handle) as SpawnPopulation[]).ToList().Where(x => x != null).ToArray();
            var filter = Oxide.Game.Rust.RustExtension.Filter.ToList();
            filter.Add("Failed to create agent because there is no valid NavMesh");
            Oxide.Game.Rust.RustExtension.Filter = filter.ToArray();
            bool findany = false;
            if (!raiseAll) {
                bool fullMatch = false;
                for (int i = 0; i < allSpawnPopulations.Length; i++) {
                    if (!(allSpawnPopulations[i] == null)) {
                        if ((allSpawnPopulations[i].name.StartsWith(populationname) || allSpawnPopulations[i].name.EndsWith(populationname)) && !fullMatch) {
                            if (allSpawnPopulations[i].name == populationname) fullMatch = true;
                            float oldDensity = allSpawnPopulations[i].TargetDensity;
                            float increaseDensity = 0f;
                            if (oldDensity > 0f) increaseDensity = allSpawnPopulations[i].TargetDensity / 100 * percentage;
                            else {
                                object backupDensity = null;
                                if (spawnDefaults.TryGetValue(allSpawnPopulations[i].name, out backupDensity)) increaseDensity = Convert.ToSingle(backupDensity) / 100 * percentage;
                                else increaseDensity = allSpawnPopulations[i].TargetDensity / 100 * percentage;
                            }
                            float newDensity = (float)Math.Round((double)(oldDensity+increaseDensity));
                            _targetDensity.SetValue(allSpawnPopulations[i], newDensity);
                            SetAnimal(allSpawnPopulations[i].name, newDensity);
                            (spawnPopulations[allSpawnPopulations[i].name] as Dictionary<string, object>)["spawndensity"] = allSpawnPopulations[i].TargetDensity;
                            SendReply(arg, $"Raised density of '{allSpawnPopulations[i].name}' | Old: {oldDensity} | New: {newDensity}");
                            findany = true;
                        }
                    }
                }
                if (!findany) SendReply(arg, $"SpawnPopulation '{populationname}' not found");
                else {
                    SendReply(arg, "New raised density's set and saved.");
                    Config["Spawn", "Population"] = spawnPopulations;
                    Config.Save();
                    string type = arg.Args[1];
                    arg.Args = new string[] {
                        type
                    }
                    ;
                    NextTick(() => ccmdSpawnFill(arg));
                }
            }
            else {
                SendReply(arg, $"Raising all SpawnPopulation density's by '{percentage}' percent");
                for (int i = 0; i < allSpawnPopulations.Length; i++) {
                    if (!(allSpawnPopulations[i] == null)) {
                        float oldDensity = allSpawnPopulations[i].TargetDensity;
                        float increaseDensity = allSpawnPopulations[i].TargetDensity / 100 * percentage;
                        float newDensity = (float)Math.Round((double)(oldDensity+increaseDensity));
                        _targetDensity.SetValue(allSpawnPopulations[i], newDensity);
                        SetAnimal(allSpawnPopulations[i].name, newDensity);
                        (spawnPopulations[allSpawnPopulations[i].name] as Dictionary<string, object>)["spawndensity"] = allSpawnPopulations[i].TargetDensity;
                    }
                }
                SendReply(arg, "New raised density's set and saved.");
                Config["Spawn", "Population"] = spawnPopulations;
                Config.Save();
                arg.Args = null;
                NextTick(() => ccmdSpawnFill(arg));
            }
            runningSpawnRaiseDensity = false;
            filter = Oxide.Game.Rust.RustExtension.Filter.ToList();
            filter.Remove("Failed to create agent because there is no valid NavMesh");
            Oxide.Game.Rust.RustExtension.Filter = filter.ToArray();
            yield return null;
        }
        [ConsoleCommand("sc.lowerdensity")]
        void ccmdSpawnLowerDensity(ConsoleSystem.Arg arg) {
            if(arg.Connection != null && arg.Connection.authLevel < 2) return;
            float percentage = 0f;
            string populationname = string.Empty;
            if (arg.Args == null || arg.Args.Length < 2) {
                SendReply(arg, "You need to provide a percentage number and a valid SpawnPopulation name");
                return;
            }
            float percent = -1;
            if (float.TryParse(arg.Args[0], out percent)) percentage = percent;
            else {
                SendReply(arg, "You need to provide a number as percentage");
                return;
            }
            populationname = arg.Args[1];
            bool lowerAll = false;
            if (populationname == "all") lowerAll = true;
            if (percentage > 100f) {
                percentage = 100f;
                SendReply(arg, "Percentage was limited to 100%");
            }
            bool force = false;
            if (arg.Args.Length >= 3 && arg.Args[2] == "force") force = true;
            if (lowerAll && percentage == 100f && !force) {
                SendReply(arg, "Canceled: Lowering all by 100% would set all to zero pop");
                SendReply(arg, "You need to add 'force' as additional argument!");
                return;
            }
            SendReply(arg, $"Calling lower with '{percentage}' percent for '{populationname}'");
            Global.Runner.StartCoroutine(SpawnLowerDensity(percentage, populationname, lowerAll, arg));
        }
        IEnumerator SpawnLowerDensity(float percentage, string populationname, bool lowerAll, ConsoleSystem.Arg arg) {
            runningSpawnLowerDensity = true;
            var allSpawnPopulations = (_AllSpawnPopulations.GetValue(_Handle) as SpawnPopulation[]).ToList().Where(x => x != null).ToArray();
            var filter = Oxide.Game.Rust.RustExtension.Filter.ToList();
            filter.Add("Failed to create agent because there is no valid NavMesh");
            Oxide.Game.Rust.RustExtension.Filter = filter.ToArray();
            bool findany = false;
            if (!lowerAll) {
                bool fullMatch = false;
                for (int i = 0; i < allSpawnPopulations.Length; i++) {
                    if (!(allSpawnPopulations[i] == null)) {
                        if ((allSpawnPopulations[i
// ... [Code preview truncated due to length. Full source in attached file] ...

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