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

FREE RaidableBases : 3.0.2 3.0.2

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Facepunch;
using Facepunch.Extend;
using Network;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust;
using Oxide.Game.Rust.Cui;
using Rust;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.SceneManagement;
using static Oxide.Plugins.RaidableBasesExtensionMethods.ExtensionMethods;
namespace Oxide.Plugins {
    [Info("Raidable Bases", "nivex", "3.0.2")]
    [Description("Create fully automated raidable bases with npcs.")]
    public class RaidableBases : RustPlugin {
        [PluginReference]
        Plugin AbandonedBases, DangerousTreasures, ZoneManager, BankSystem, IQEconomic, Economics, ServerRewards, GUIAnnouncements, AdvancedAlerts, Archery, Space, Sputnik, PocketDimensions, FauxAdmin, IQDronePatrol, Friends, Clans, Kits, TruePVE, SimplePVE, NightLantern, Wizardry, NextGenPVE, Imperium, Backpacks, BaseRepair, Notify, SkillTree, ShoppyStock, XPerience, XLevels;
        private new const string Name = "RaidableBases";
        private const int targetMask = 8454145;
        private const int visibleMask = 10551553;
        private const int targetMask2 = 10551313;
        private const int manualMask = 1084293393;
        private const int blockLayers = 2228480;
        private const int queueLayers = 2294528;
        private const int gridLayers = 327936;
        private const float M_RADIUS = 25f;
        private const float CELL_SIZE = 12.5f;
        private float OceanLevel;
        private bool wiped;
        private bool IsUnloading;
        private bool IsShuttingDown;
        private bool bypassRestarting;
        private bool DebugMode;
        private int despawnLimit = 10;
        private SkinSettingsImportedWorkshop ImportedWorkshopSkins = new();
        private ProtectionProperties _elevatorProtection;
        private ProtectionProperties _turretProtection;
        private AutomatedController Automated;
        private StoredData data = new();
        public BuildingTables Buildings = new();
        public QueueController Queues;
        private SkinsPlugin skinsPlugin = new();
        private Coroutine setupCopyPasteObstructionRadius;
        private List<Coroutine> loadCoroutines = new();
        public List<RaidableBase> Raids = new();
        public Dictionary<ulong, DelaySettings> PvpDelay = new();
        public Dictionary<string, SkinInfo> Skins = new();
        private Dictionary<string, PasteData> _pasteData = new();
        private Dictionary<ulong, HumanoidBrain> HumanoidBrains = new();
        private Dictionary<NetworkableId, BMGELEVATOR> _elevators = new();
        private Dictionary<string, ItemDefinition> DeployableItems = new();
        private Dictionary<ItemDefinition, string> ItemDefinitions = new();
        private Dictionary<string, ItemDefinition> _itemModEntity = new();
        private Dictionary<ItemDefinition, ItemModConsume> _itemModConsume = new();
        private readonly List<string> ExcludedMounts = new() {
            "beachchair", "boogieboard", "cardtable", "chair", "chippyarcademachine", "computerstation", "drumkit", "microphonestand", "piano", "secretlabchair", "slotmachine", "sofa", "xylophone"
        }
        ;
        private readonly List<string> Blocks = new() {
            "wall.frame.cell", "wall.doorway", "wall", "wall.frame", "wall.half", "wall.low", "wall.window", "foundation.triangle", "foundation", "wall.external.high.wood", "wall.external.high.stone", "wall.external.high.ice", "floor.triangle.frame", "floor.triangle", "floor.frame"
        }
        ;
        private readonly List<string> TrueDamage = new() {
            "spikes.floor", "barricade.metal", "barricade.woodwire", "barricade.wood", "wall.external.high.wood", "wall.external.high.stone", "wall.external.high.ice"
        }
        ;
        private readonly List<string> arguments = new() {
            "add", "remove", "list", "clean", "enable_dome_marker", "toggle", "stability", "maintained", "scheduled", "noexplosivecosts"
        }
        ;
        private readonly List<uint> CupboardPrefabIDs = new() {
            2476970476, 785685130, 3932172323
        }
        ;
        private readonly IPlayer _consolePlayer = new Game.Rust.Libraries.Covalence.RustConsolePlayer();
        private readonly List<BaseEntity.Slot> _checkSlots = new() {
            BaseEntity.Slot.Lock, BaseEntity.Slot.UpperModifier, BaseEntity.Slot.MiddleModifier, BaseEntity.Slot.LowerModifier
        }
        ;
        public class PasteData {
            public bool valid;
            public float radius;
            public List<Vector3> foundations;
            public List<string> invalid;
            public PasteData() {
            }
        }
        public static class RaidableMode {
            public const string Normal = "Normal", Random = "Random", Points = "Points", Disabled = "Disabled";
        }
        public struct DamageMultiplier {
            public DamageType index;
            public float amount;
        }
        public enum DamageResult {
            None, Allowed, Blocked
        }
        public enum RaidableType {
            None, Manual, Scheduled, Maintained, Grid
        }
        public enum AlliedType {
            All, Clan, Friend, Team
        }
        public enum CacheType {
            Close, Delete, Generic, Temporary, Privilege, Submerged
        }
        public enum ConstructionType {
            Barricade, Ladder, Any
        }
        public class StoredData {
            public RotationCycle Cycle = new();
            public Dictionary<string, PlayerInfo> Players = new();
            public DateTime RaidTime = DateTime.MinValue;
            public int TotalEvents;
            public int protocol = -1;
            public StoredData() {
            }
        }
        public class RandomBase {
            public float heightAdj, typeDistance, protectionRadius, safeRadius, ignoreRadius, buildRadius, baseHeight;
            public bool autoHeight, stability, checkTerrain, Sorted, Save;
            public string BaseName, username, id;
            public int attempts, errors;
            public ulong userid;
            public Vector3 Position;
            public IPlayer user;
            public RaidableType type;
            public BasePlayer owner;
            public PasteData pasteData;
            public BaseProfile Profile;
            public RaidableSpawns spawns;
            public RaidableBases Instance;
            public RaidableBase raid;
            public HashSet<ulong> members = new();
            public BuildingOptions options => Profile.Options;
            public bool HasSpawns() => spawns.Spawns.Count > 0;
        }
        public class BackpackData : Pool.IPooled {
            public BackpackData() {
            }
            public void EnterPool() {
                Pool.FreeUnmanaged(ref containers);
                _player = null;
                userid = 0uL;
            }
            public void LeavePool() => containers = Pool.Get<List<DroppedItemContainer>>();
            public List<DroppedItemContainer> containers;
            public BasePlayer _player;
            public ulong userid;
            public bool IsEmpty => containers.Count == 0 || containers.All(x => x.IsKilled());
            public BasePlayer player {
                get {
                    if (_player == null) {
                        _player = RustCore.FindPlayerById(userid);
                    }
                    return _player;
                }
            }
        }
        public class DelaySettings {
            public RaidableBase raid;
            public string mode;
            public Timer Timer;
            public float time;
            public void Destroy() {
                if (Timer != null && !Timer.Destroyed) {
                    Timer.Callback();
                    Timer.Destroy();
                }
            }
        }
        public class SkinInfo {
            public List<ulong> skins = new(), workshopSkins = new(), importedWorkshopSkins = new(), allSkins = new();
        }
        public class RankedRecord {
            public string Permission = string.Empty;
            public string Group = string.Empty;
            public string Mode = string.Empty;
            internal bool IsValid => !string.IsNullOrWhiteSpace(Permission) && !string.IsNullOrWhiteSpace(Group) && !string.IsNullOrWhiteSpace(Mode);
            public RankedRecord(string permission, string group, string mode) {
                (Permission, Group, Mode) = (permission, group, mode);
            }
            public RankedRecord() {
            }
        }
        public class RaidableSpawnLocation : IEquatable<RaidableSpawnLocation> {
            public List<Vector3> Surroundings = new();
            public Vector3 Location;
            public MinMax LandLevel;
            public float WaterHeight;
            public float TerrainHeight;
            public float SpawnHeight;
            public float Radius;
            public float RailRadius;
            public bool AutoHeight;
            public RaidableSpawnLocation(Vector3 location) {
                Location = location;
            }
            public bool Equals(RaidableSpawnLocation other) => Location.Equals(other.Location);
            public override bool Equals(object obj) => obj is RaidableSpawnLocation other && Equals(other);
            public override int GetHashCode() => base.GetHashCode();
        }
        public class ZoneInfo {
            internal string ZoneId;
            internal Vector3 Position;
            internal Vector3 Size;
            internal Vector3 extents;
            internal float Distance;
            internal bool IsBlocked;
            public ZoneInfo(string zoneID, Vector3 position, object radius, object size, bool isBlocked, float dist) {
                (IsBlocked, ZoneId, Position) = (isBlocked, zoneID, position);
                dist = Mathf.Max(dist, 100f);
                if (radius is float r) {
                    Distance = r + M_RADIUS + dist;
                }
                if (size is Vector3 v && v != Vector3.zero) {
                    Size = v + new Vector3(dist, Position.y + 100f, dist);
                    extents = Size * 0.5f;
                }
            }
            public bool IsPositionInZone(Vector3 a) {
                if (Size != Vector3.zero) {
                    Vector3 v = Quaternion.Inverse(Quaternion.identity) * (a - Position);
                    return v.x <= extents.x && v.x > -extents.x && v.y <= extents.y && v.y > -extents.y && v.z <= extents.z && v.z > -extents.z;
                }
                return InRange2D(Position, a, Distance);
            }
        }
        public class BaseProfile {
            public BuildingOptions Options = new();
            public string ProfileName;
            private Dictionary<string, BaseProfile> Clones = new();
            public RaidableBases Instance;
            public BaseProfile(RaidableBases instance) {
                Instance = instance;
                Options.AdditionalBases = new();
            }
            public BaseProfile(RaidableBases instance, BuildingOptions options, string name) {
                Instance = instance;
                Options = options;
                ProfileName = name;
            }
            public static BaseProfile Clone(BaseProfile profile, string name) {
                if (profile.Clones.TryGetValue(name, out var clone)) {
                    return clone;
                }
                profile.Clones[name] = clone = new(profile.Instance) {
                    Options = profile.Options.Clone(), ProfileName = name,
                }
                ;
                return clone;
            }
        }
        public class BuildingTables {
            public Dictionary<string, List<LootItem>> DifficultyLootLists = new(StringComparer.OrdinalIgnoreCase);
            public Dictionary<DayOfWeek, List<LootItem>> WeekdayLootLists = new();
            public Dictionary<string, BaseProfile> Profiles = new(StringComparer.OrdinalIgnoreCase);
            public List<string> Removed = new();
            public bool IsConfigured(string baseName) {
                foreach (var m in Profiles) {
                    if (m.Key == baseName || m.Value.Options.AdditionalBases.ContainsKey(baseName)) {
                        return true;
                    }
                }
                return false;
            }
            public bool TryGetValue(string baseName, out BaseProfile profile) {
                profile = Profiles.FirstOrDefault(m => m.Key == baseName || m.Value.Options.AdditionalBases.ContainsKey(baseName)).Value;
                return profile != null;
            }
            public void Remove(string baseName) {
                if (Profiles.Remove(baseName) || Profiles.Values.Exists(m => m.Options.AdditionalBases.Remove(baseName))) {
                    Removed.Add(baseName);
                }
            }
        }
        public GridControllerManager GridController = new();
        public class GridControllerManager {
            internal RaidableBases Instance;
            internal Dictionary<RaidableType, RaidableSpawns> Spawns = new();
            internal Coroutine gridCoroutine;
            internal Coroutine fileCoroutine;
            internal float gridTime;
            public SpawnsControllerManager SpawnsController => Instance.SpawnsController;
            public StoredData data => Instance.data;
            public Configuration config => Instance.config;
            public double GetRaidTime() => data.RaidTime.Subtract(DateTime.Now).TotalSeconds;
            public void StartAutomation() {
                if (Instance.Automated.IsScheduledEnabled) {
                    if (data.RaidTime != DateTime.MinValue && GetRaidTime() > config.Settings.Schedule.IntervalMax) {
                        data.RaidTime = DateTime.MinValue;
                    }
                    Instance.Automated.StartCoroutine(RaidableType.Scheduled);
                }
                if (Instance.Automated.IsMaintainedEnabled) {
                    Instance.Automated.StartCoroutine(RaidableType.Maintained);
                }
            }
            private IEnumerator LoadFiles() {
                Instance.Buildings = new();
                using var sb = DisposableBuilder.Get();
                yield return Instance.LoadProfiles(sb);
                yield return Instance.LoadTables(sb);
                if (Instance.Buildings.Profiles.Count == 0) {
                    CriticalError();
                    yield break;
                }
                yield return CoroutineEx.waitForSeconds(5f);
                Instance.IsSpawnerBusy = false;
                StartAutomation();
                if (!Instance.IsCopyPasteLoaded(out var error)) Puts(error);
            }
            public void SetupGrid() {
                if (Spawns.Count >= 5) {
                    fileCoroutine = ServerMgr.Instance.StartCoroutine(LoadFiles());
                    return;
                }
                StopCoroutine();
                gridCoroutine = ServerMgr.Instance.StartCoroutine(GenerateGrid());
            }
            public void StopCoroutine() {
                if (gridCoroutine != null) {
                    ServerMgr.Instance.StopCoroutine(gridCoroutine);
                    gridCoroutine = null;
                }
                if (fileCoroutine != null) {
                    ServerMgr.Instance.StopCoroutine(fileCoroutine);
                    fileCoroutine = null;
                }
            }
            private void CriticalError(string text = "No valid profiles exist!") {
                if (Instance.profileErrors.Count > 0) {
                    Puts("Json errors found in:");
                    Instance.profileErrors.ForEach(str => Puts(str));
                }
                Puts("ERROR: Grid has failed initialization.{0} {1}", text, Instance.Buildings.Profiles.Count);
                Interface.Oxide.NextTick(() => gridCoroutine = null);
            }
            public bool BadFrameRate;
            private IEnumerator GenerateGrid() {
                yield return CoroutineEx.waitForSeconds(0.1f);
                while (Performance.report.frameRate < 15 && ConVar.FPS.limit > 15) {
                    BadFrameRate = true;
                    yield return CoroutineEx.waitForSeconds(1f);
                }
                BadFrameRate = false;
                var gridStopwatch = System.Diagnostics.Stopwatch.StartNew();
                RaidableSpawns spawns = Spawns[RaidableType.Grid] = new(Instance);
                gridTime = Time.realtimeSinceStartup;
                Instance.Buildings = new();
                using var sb = DisposableBuilder.Get();
                yield return Instance.LoadProfiles(sb);
                yield return Instance.LoadTables(sb);
                yield return SpawnsController.SetupMonuments();
                if (Instance.Buildings.Profiles.Count == 0) {
                    gridStopwatch.Stop();
                    CriticalError();
                    yield break;
                }
                var spawnOnSeabed = false;
                var minPos = (int)(World.Size / -2f) + 100;
                var maxPos = (int)(World.Size / 2f) - 100;
                var maxProtectionRadius = -10000f;
                var minProtectionRadius = 10000f;
                var maxAutoRadius = 0f;
                var maxWaterDepth = 0f;
                var landLevel = 0.5f;
                var checks = 0;
                foreach (var profile in Instance.Buildings.Profiles.Values) {
                    maxAutoRadius = Mathf.Min(profile.Options.ProtectionRadius(RaidableType.None), maxAutoRadius);
                    maxProtectionRadius = Mathf.Max(profile.Options.ProtectionRadii.Max(), maxProtectionRadius);
                    minProtectionRadius = Mathf.Min(profile.Options.ProtectionRadii.Min(), minProtectionRadius);
                    maxWaterDepth = Mathf.Max(maxWaterDepth, profile.Options.Water.WaterDepth);
                    landLevel = Mathf.Max(profile.Options.GetLandLevel, landLevel);
                }
                if (!config.Settings.Management.AllowOnBeach && !config.Settings.Management.AllowInland && !spawnOnSeabed) {
                    gridStopwatch.Stop();
                    CriticalError("Spawn options for beach, inland and seabed are disabled!");
                    yield break;
                }
                using var blockedPositions = config.Settings.Management.BlockedPositions.ToPooledList();
                using var blockedMapPrefabs = DisposableList<(Vector3, float)>();
                using var custom = DisposableList<(string, int)>();
                var zero = blockedPositions.Find(x => x.position == Vector3.zero);
                if (zero == null) {
                    blockedPositions.Add(zero = new(Vector3.zero, 200f));
                }
                if (zero.radius < 200f) {
                    zero.radius = 200f;
                }
                var wtObj = Interface.Oxide.CallHook("GetGridWaitTime");
                var waitTime = CoroutineEx.waitForSeconds(wtObj is float w ? w : 0.0035f);
                var threshold = Interface.Oxide.CallHook("GetGridWaitThreshold") is int th ? th : 25;
                var prefabs = config.Settings.Management.BlockedPrefabs.ToDictionary(pair => pair.Key, pair => pair.Value);
                prefabs.Remove("test_prefab");
                prefabs.Remove("test_prefab_2");
                foreach (var prefab in World.Serialization.world.prefabs) {
                    if (!StringPool.toString.TryGetValue(prefab.id, out var fullname)) {
                        continue;
                    }
                    Vector3 v = new(prefab.position.x, prefab.position.y, prefab.position.z);
                    if (prefabs.Count > 0 && prefabs.TryGetValue(GetFileNameWithoutExtension(fullname), out var dist)) {
                        blockedMapPrefabs.Add((v, dist));
                    }
                }
                float railRadius = Mathf.Max(M_RADIUS * 2f, maxAutoRadius);
                bool hasBlockedMapPrefabs = blockedMapPrefabs.Count > 0;
                bool hasBlockedPositions = blockedPositions.Count > 0;
                double totalPoints = Math.Pow((maxPos - minPos) / CELL_SIZE, 2);
                double step = totalPoints / 4.0;
                int stepCounter = 0;
                int progress = 0;
                for (float x = minPos; x < maxPos; x += CELL_SIZE)  // Credits to Jake_Rich for helping me with this!
                {
                    for (float z = minPos; z < maxPos; z += CELL_SIZE) {
                        progress++;
                        if (++stepCounter >= step) {
                            Puts($"{Math.Round((progress / totalPoints) * 100.0)}% loaded ({spawns.Spawns.Count} potential points)");
                            stepCounter = 0;
                        }
                        var position = new Vector3(x, 0f, z);
                        if (hasBlockedPositions && blockedPositions.Exists(a => InRange2D(position, a.position, a.radius))) {
                            continue;
                        }
                        position.y = SpawnsController.GetSpawnHeight(position);
                        if (hasBlockedMapPrefabs && SpawnsController.IsBlockedByMapPrefab(blockedMapPrefabs, position)) {
                            continue;
                        }
                        SpawnsController.ExtractLocation(spawns, position, landLevel, minProtectionRadius, maxProtectionRadius, railRadius, maxWaterDepth);
                        if (++checks >= threshold) {
                            checks = 0;
                            yield return waitTime;
                        }
                    }
                }
                Instance.IsSpawnerBusy = false;
                Instance.GridController.StartAutomation();
                Instance.Queues.Messages.Clear();
                gridStopwatch.Stop();
                Puts(Instance.mx("Initialized Grid", null, Math.Floor(gridStopwatch.Elapsed.TotalSeconds), gridStopwatch.Elapsed.Milliseconds, World.Size, spawns.Spawns.Count));
                foreach (var (type, amount) in custom) Puts($"Loaded {amount} custom spawns from {type}");
                if (!Instance.IsCopyPasteLoaded(out var error)) Puts(error);
                gridCoroutine = null;
            }
            public void LoadSpawns() {
                Spawns = new();
                Spawns.Add(RaidableType.Grid, new(Instance));
                LoadSpawnsForType(RaidableType.Manual, config.Settings.Manual.SpawnsFile, "LoadedManual");
                LoadSpawnsForType(RaidableType.Scheduled, config.Settings.Schedule.SpawnsFile, "LoadedScheduled");
                LoadSpawnsForType(RaidableType.Maintained, config.Settings.Maintained.SpawnsFile, "LoadedMaintained");
            }
            public bool BlockAtSpawnsDatabase(Vector3 a) {
                foreach (var (type, rs) in Spawns) {
                    if (rs.IsCustomSpawn && rs.Spawns.Count > 0) {
                        foreach (var rsl in rs.Spawns) {
                            if (rsl.Location.Distance(a) <= rsl.Radius) {
                                return true;
                            }
                        }
                    }
                }
                return false;
            }
            private void LoadSpawnsForType(RaidableType type, string spawnsFile, string key) {
                if (SpawnsFileValid(spawnsFile)) {
                    var spawns = GetSpawnsLocations(spawnsFile);
                    if (spawns.Count > 0) {
                        Puts(Instance.mx(key, null, spawns.Count));
                        Spawns[type] = new(Instance, spawns);
                    }
                }
            }
            public bool SpawnsFileValid(string spawnsFile) {
                if (string.IsNullOrWhiteSpace(spawnsFile) || spawnsFile.Equals("none", StringComparison.OrdinalIgnoreCase)) {
                    return false;
                }
                return Instance.FileExists($"SpawnsDatabase{Path.DirectorySeparatorChar}{spawnsFile}");
            }
            public HashSet<RaidableSpawnLocation> GetSpawnsLocations(string spawnsFile) {
                try {
                    return new(Interface.Oxide.DataFileSystem.ReadObject<Spawnfile>($"SpawnsDatabase{Path.DirectorySeparatorChar}{spawnsFile}").spawnPoints.Values.Select(value => new RaidableSpawnLocation(value.ToString().ToVector3())));
                }
                catch {
                    Puts("Invalid spawns file: {0}", spawnsFile);
                    return new();
                }
            }
        }
        private class Spawnfile {
            public Dictionary<string, object> spawnPoints = new();
        }
        public class QueueController {
            internal YieldInstruction instruction0, instruction1;
            internal Queue<RandomBase> queue = new();
            internal DebugMessages Messages = new();
            internal Coroutine _coroutine;
            internal int spawnChecks;
            internal bool Paused;
            internal RaidableBases Instance;
            internal const float REMOVE_RADIUS = 15f;
            internal Configuration config => Instance.config;
            internal SpawnsControllerManager SpawnsController => Instance.SpawnsController;
            internal bool Any => queue.Count > 0;
            private void Message(BasePlayer player, string key, params object[] args) => Instance.Message(player, key, args);
            private string mx(string key, string id = null, params object[] args) => Instance.mx(key, id, args);
            public class DebugMessages {
                internal Dictionary<string, Info> _elements = new();
                internal RaidableBases _instance;
                internal bool _logToFile;
                internal IPlayer _user;
                public class Info {
                    public int Amount = 1;
                    public List<string> Values = new();
                    public override string ToString() => Values.Count > 0 ? $": {string.Join(", ", Values)}" : string.Empty;
                }
                public string Add(string element, object obj = null) {
                    if (string.IsNullOrWhiteSpace(element)) {
                        return null;
                    }
                    if (!_elements.TryGetValue(element, out var info)) {
                        if (_elements.Count >= 20) {
                            _elements.Remove(_elements.ElementAt(0).Key);
                        }
                        _elements[element] = info = new();
                    }
                    else info.Amount++;
                    if (obj == null) {
                        return element;
                    }
                    string value = obj.ToString().Replace("(", "").Replace(")", "").Replace(",", "");
                    if (!info.Values.Contains(value)) {
                        if (info.Values.Count >= 5) {
                            info.Values.RemoveAt(0);
                        }
                        info.Values.Add(value);
                    }
                    return $"{element}: {value}";
                }
                public void Clear() {
                    _elements.Clear();
                }
                public bool Any() {
                    return _elements.Count > 0;
                }
                public void PrintAll(IPlayer user = null) {
                    if (_elements.Count > 0 && _instance.DebugMode) {
                        foreach (var (key, info) in _elements) {
                            PrintInternal(user, $"{info.Amount}x - {key}{info}");
                        }
                        Clear();
                    }
                }
                private bool PrintInternal(IPlayer user, string message) {
                    if (!string.IsNullOrWhiteSpace(message) && _instance.DebugMode) {
                        if (_logToFile) {
                            _instance.LogToFile("debug", message, _instance, true);
                        }
                        if (user == null || user.IsServer) {
                            Puts("DEBUG: {0}", message);
                        }
                        else user.Reply($"DEBUG: {message}");
                        return true;
                    }
                    return false;
                }
                public void Log(string baseName, string message) {
                    _instance?.Buildings?.Remove(baseName);
                    _instance.IsSpawnerBusy = false;
                    Print(message);
                    Puts(message);
                }
                public bool Print(string message) {
                    Print(_user, message, null);
                    return false;
                }
                public void Print(string message, object obj) {
                    Print(_user, message, obj);
                }
                public void Print(IPlayer user, string message, object obj) {
                    if (!PrintInternal(user, obj == null ? message : $"{message}: {obj}")) {
                        Add(message, obj);
                    }
                }
                public void PrintLast(string id = null) {
                    if (_elements.Count > 0 && _instance.DebugMode) {
                        PrintInternal(_user, GetLast(id));
                    }
                }
                public string GetLast(string id = null) {
                    if (_elements.Count == 0) {
                        return _instance.m("CannotFindPosition", id);
                    }
                    var (key, info) = _elements.ElementAt(_elements.Count - 1);
                    _elements.Remove(key);
                    return $"{info.Amount}x - {key}{info}";
                }
            }
            public QueueController(RaidableBases instance) {
                Messages._instance = Instance = instance;
                Messages._logToFile = instance.config.LogToFile;
                spawnChecks = Mathf.Clamp(instance.config.Settings.Management.SpawnChecks, 1, 500);
                instruction0 = CoroutineEx.waitForSeconds(0.1f);
                instruction1 = CoroutineEx.waitForSeconds(1f);
            }
            public void RestartCoroutine() {
                StopCoroutine();
                _coroutine = ServerMgr.Instance.StartCoroutine(FindEventPosition());
            }
            public void StopCoroutine() {
                if (_coroutine != null) {
                    ServerMgr.Instance.StopCoroutine(_coroutine);
                    _coroutine = null;
                }
                queue.Clear();
            }
            public void Add(RandomBase rb) {
                if (!queue.Contains(rb)) {
                    queue.Enqueue(rb);
                }
            }
            private void Spawn(RandomBase rb, Vector3 position) {
                if (!Instance.IsUnloading) {
                    rb.Position = position;
                    if (Instance.PasteBuilding(rb)) {
                        Instance.IsSpawnerBusy = true;
                    }
                }
            }
            private bool CanBypassPause(RandomBase rb) {
                if (rb.type == RaidableType.Manual) {
                    return rb.user != null;
                }
                return false;
            }
            private IEnumerator FindEventPosition() {
                int checks = 0;
                while (!Instance.IsUnloading) {
                    if (++checks >= spawnChecks) {
                        yield return instruction0;
                        checks = 0;
                    }
                    if (!queue.TryPeek(out var spq)) {
                        yield return instruction1;
                        continue;
                    }
                    if (Instance.Buildings.Removed.Contains(spq.BaseName)) {
                        if (spq.type == RaidableType.Scheduled) {
                            Instance.data.RaidTime = DateTime.Now.AddSeconds(1f);
                        }
                        queue.Dequeue();
                        continue;
                    }
                    if (spq.Position != Vector3.zero) {
                        queue.Dequeue();
                        Spawn(spq, spq.Position);
                        yield return instruction1;
                        continue;
                    }
                    if (Instance.ZoneManager != null) {
                        SpawnsController.SetupZones(Instance.ZoneManager, false);
                    }
                    spq.spawns.Check();
                    while (spq.HasSpawns()) {
                        if (++checks >= spawnChecks) {
                            checks = 0;
                            yield return instruction0;
                        }
                        if (Instance.IsSpawnerBusy || Paused && !CanBypassPause(spq)) {
                            yield return instruction1;
                            continue;
                        }
                        spq.attempts++;
                        var rsl = spq.spawns.GetRandom(spq.options.Water);
                        if (rsl == null) {
                            Messages.Add("RSL is null");
                            break;
                        }
                        var v = rsl.Location;
                        if (!TopologyChecks(spq, v, rsl.RailRadius)) {
                            continue;
                        }
                        v.y = GetAdjustedHeight(spq, v);
                        if (IsTooClose(spq, v)) {
                            continue;
                        }
                        if (IsAreaManuallyBlocked(spq, v)) {
                            continue;
                        }
                        if (CanSpawnCustom(spq, RaidableType.Maintained, v, config.Settings.Maintained.Ignore, config.Settings.Maintained.SafeRadius)) {
                            yield return instruction1;
                            break;
                        }
                        if (CanSpawnCustom(spq, RaidableType.Scheduled, v, config.Settings.Schedule.Ignore, config.Settings.Schedule.SafeRadius)) {
                            yield return instruction1;
                            break;
                        }
                        if (IsSubmerged(spq, rsl, v)) {
                            continue;
                        }
                        if (!IsAreaSafe(spq, rsl, v)) {
                            continue;
                        }
                        if (!spq.pasteData.valid) {
                            yield return SetupCopyPasteRadius(spq);
                        }
                        if (spq.pasteData.foundations.IsNullOrEmpty()) {
                            Instance.Buildings.Remove(spq.BaseName);
                            break;
                        }
                        if (IsObstructed(spq, v) || !spq.spawns.IsCustomSpawn && SpawnsController.IsZoneBlocked(v)) {
                            continue;
                        }
                        Spawn(spq, v);
                        yield return instruction1;
                        break;
                    }
                    if (Instance.IsGridLoading() && !Instance.IsSpawnerBusy) {
                        yield return instruction1;
                        continue;
                    }
                    queue.Dequeue();
                    CheckSpawner(spq);
                }
                _coroutine = null;
            }
            private void CheckSpawner(RandomBase spq) {
                if (!Instance.IsSpawnerBusy) {
                    if (spq.type == RaidableType.Manual) {
                        if (spq.user == null || spq.user.IsServer) {
                            Puts(mx("CannotFindPosition"));
                        }
                        else {
                            Message(spq.user.Player(), Instance.Queues.Messages.GetLast(spq.user.Id));
                        }
                    }
                    spq.spawns.TryAddRange();
                    Messages.PrintAll();
                    Instance.data.Cycle.Add(spq.type, spq.BaseName, spq.owner);
                }
            }
            internal bool IsObstructed(RandomBase spq, Vector3 v) {
                if (!spq.spawns.IsCustomSpawn && SpawnsController.IsObstructed(v, spq.pasteData.radius, spq.options.GetLandLevel, spq.options.Setup.ForcedHeight)) {
                    Messages.Add("Area is obstructed", v);
                    spq.spawns.RemoveNear(v, REMOVE_RADIUS, CacheType.Temporary, spq.type);
                    return true;
                }
                return false;
            }
            private IEnumerator SetupCopyPasteRadius(RandomBase spq) {
                yield return Instance.SetupCopyPasteObstructionRadius(spq.BaseName, spq.options.ProtectionRadii.Obstruction == -1 ? 0f : GetObstructionRadius(spq.options.ProtectionRadii, RaidableType.None));
            }
            internal bool IsAreaSafe(RandomBase spq, RaidableSpawnLocation rsl, Vector3 v) {
                if (!SpawnsController.IsAreaSafe(rsl.Location, spq.ignoreRadius, spq.safeRadius, spq.buildRadius, spq.pasteData.radius, queueLayers, spq.spawns.IsCustomSpawn, out var cacheType, spq.type)) {
                    if (cacheType == CacheType.Delete) spq.spawns.Remove(rsl, cacheType);
                    else if (cacheType == CacheType.Privilege) spq.spawns.RemoveNear(rsl.Location, REMOVE_RADIUS, cacheType, spq.type);
                    else spq.spawns.RemoveNear(rsl.Location, REMOVE_RADIUS, cacheType, spq.type);
                    return false;
                }
                return true;
            }
            internal bool IsSubmerged(RandomBase spq, RaidableSpawnLocation rsl, Vector3 v) {
                if (!spq.spawns.IsCustomSpawn && spq.options.Setup.ForcedHeight == -1 && SpawnsController.IsSubmerged(spq.options.Water, rsl)) {
                    Messages.Add("Area is submerged", v);
                    return true;
                }
                return false;
            }
            private bool CanSpawnCustom(RandomBase spq, RaidableType type, Vector3 v, bool ignore, float radius) {
                if (spq.type == type && spq.spawns.IsCustomSpawn && (ignore || radius > 0f)) {
                    if (radius <= 0f) {
                        Messages.Add($"Ignored checks for {spq.type} event", v);
                        Spawn(spq, v);
                        return true;
                    }
                    else spq.ignoreRadius = radius;
                }
                return false;
            }
            private bool IsTooClose(RandomBase spq, Vector3 v) {
                if (spq.typeDistance > 0 && Instance.IsTooClose(v, spq.typeDistance)) {
                    spq.spawns.RemoveNear(v, REMOVE_RADIUS, CacheType.Close, spq.type);
                    Messages.Add("Too close (Spawn Bases X Distance Apart)", v);
                    return true;
                }
                return false;
            }
            internal bool IsAreaManuallyBlocked(RandomBase spq, Vector3 v) {
                if (!spq.spawns.IsCustomSpawn && config.Settings.Management.BlockedPositions.Exists(x => InRange2D(v, x.position, x.radius))) {
                    spq.spawns.RemoveNear(v, REMOVE_RADIUS, CacheType.Close, spq.type);
                    Messages.Add("Block Spawns At Positions", v);
                    return true;
                }
                return false;
            }
            private float GetAdjustedHeight(RandomBase spq, Vector3 v) {
                if (spq.options.Setup.ForcedHeight != -1) {
                    return spq.options.Setup.PasteHeightAdjustment + spq.options.Setup.ForcedHeight;
                }
                return v.y + spq.options.Setup.PasteHeightAdjustment;
            }
            private bool TopologyChecks(RandomBase spq, Vector3 v, float railRadius) {
                if (!spq.spawns.IsCustomSpawn && !SpawnsController.TopologyChecks(v, spq.protectionRadius, railRadius, out var topology)) {
                    spq.spawns.RemoveNear(v, REMOVE_RADIUS, CacheType.Delete, spq.type);
                    Messages.Add($"Blocked on {topology} topology", v);
                    return false;
                }
                return true;
            }
        }
        public class AutomatedController {
            internal YieldInstruction instruction0, instruction1, instruction5, instruction15;
            internal Coroutine _maintainedCoroutine, _scheduledCoroutine;
            internal bool IsMaintainedEnabled, IsScheduledEnabled;
            internal RaidableBases Instance;
            internal int _maxOnce;
            internal StoredData data => Instance.data;
            internal Configuration config => Instance.config;
            public AutomatedController(RaidableBases instance, bool a, bool b) {
                instruction0 = CoroutineEx.waitForSeconds(0.0025f);
                instruction1 = CoroutineEx.waitForSeconds(1f);
                instruction5 = CoroutineEx.waitForSeconds(5f);
                instruction15 = CoroutineEx.waitForSeconds(15f);
                Instance = instance;
                IsMaintainedEnabled = a;
                IsScheduledEnabled = b;
            }
            public void DestroyMe() {
                StopCoroutine(RaidableType.Scheduled);
                StopCoroutine(RaidableType.Maintained);
            }
            public void StopCoroutine(RaidableType type, IPlayer user = null) {
                if (type == RaidableType.Scheduled && _scheduledCoroutine != null) {
                    ServerMgr.Instance.StopCoroutine(_scheduledCoroutine);
                    Instance.Message(user, "ReloadScheduleCo");
                    _scheduledCoroutine = null;
                }
                else if (type == RaidableType.Maintained && _maintainedCoroutine != null) {
                    ServerMgr.Instance.StopCoroutine(_maintainedCoroutine);
                    Instance.Message(user, "ReloadMaintainCo");
                    _maintainedCoroutine = null;
                }
            }
            public void StartCoroutine(RaidableType type, IPlayer user = null) {
                StopCoroutine(type, user);
                if (type == RaidableType.Scheduled ? !IsScheduledEnabled || config.Settings.Schedule.Max <= 0 : !IsMaintainedEnabled || config.Settings.Maintained.Max <= 0) {
                    return;
                }
                if (Instance.IsGridLoading() || !Instance.CanContinueAutomation()) {
                    Instance.timer.Once(1f, () => StartCoroutine(type));
                    return;
                }
                if (type == RaidableType.Scheduled && data.RaidTime == DateTime.MinValue) {
                    ScheduleNextAutomatedEvent();
                }
                if (type == RaidableType.Scheduled) {
                    Instance.timer.Once(0.2f, () => _scheduledCoroutine = ServerMgr.Instance.StartCoroutine(ScheduleCoroutine()));
                }
                else Instance.timer.Once(0.2f, () => _maintainedCoroutine = ServerMgr.Instance.StartCoroutine(MaintainCoroutine()));
            }
            private IEnumerator MaintainCoroutine() {
                float timeBetweenSpawns = Mathf.Max(1f, config.Settings.Maintained.Time);
                while (!Instance.IsUnloading) {
                    if (!CanSpawn(RaidableType.Maintained, config.Settings.Maintained.GetPlayerCount(), config.Settings.Maintained.PlayerLimitMin, config.Settings.Maintained.PlayerLimitMax, config.Settings.Maintained.Max, false)) {
                        yield return instruction5;
                    }
                    else if (!Instance.Queues.Any) {
                        yield return ProcessEvent(RaidableType.Maintained, timeBetweenSpawns);
                    }
                    else if (Instance.Queues.Messages.Any()) {
                        Instance.Queues.Messages.PrintLast();
                    }
                    yield return instruction5;
                }
                _maintainedCoroutine = null;
            }
            private IEnumerator ScheduleCoroutine() {
                float timeBetweenSpawns = Mathf.Max(1f, config.Settings.Schedule.Time);
                while (!Instance.IsUnloading) {
                    if (CanSpawn(RaidableType.Scheduled, config.Settings.Schedule.GetPlayerCount(), config.Settings.Schedule.PlayerLimitMin, config.Settings.Schedule.PlayerLimitMax, config.Settings.Schedule.Max, true)) {
                        while (Instance.Get(RaidableType.Scheduled) < config.Settings.Schedule.Max && MaxOnce()) {
                            if (SaveRestore.IsSaving) {
                                Instance.Queues.Messages.Print("Scheduled: Server saving");
                                yield return instruction15;
                            }
                            else if (!Instance.Queues.Any) {
                                yield return ProcessEvent(RaidableType.Scheduled, timeBetweenSpawns);
                            }
                            else if (Instance.Queues.Messages.Any()) {
                                Instance.Queues.Messages.PrintLast();
                            }
                            yield return instruction1;
                        }
                        yield return CoroutineEx.waitForSeconds(ScheduleNextAutomatedEvent());
                    }
                    yield return instruction5;
                }
                _scheduledCoroutine = null;
            }
            private IEnumerator ProcessEvent(RaidableType type, float timeBetweenSpawns) {
                Instance.SpawnRandomBase(type);
                yield return instruction1;
                //yield return new WaitWhile(() => Instance.Queues.Any);
                if (!Instance.IsSpawnerBusy) {
                    yield break;
                }
                if (type == RaidableType.Scheduled) {
                    _maxOnce++;
                }
                Instance.Queues.Messages.Print($"{type}: Waiting for base to be setup", Instance.IsBusy(out var pastedLocation) ? pastedLocation : (object)null);
                yield return new WaitWhile(() => Instance.IsSpawnerBusy);
                Instance.Queues.Messages.Print($"{type}: Waiting {timeBetweenSpawns} seconds");
                yield return CoroutineEx.waitForSeconds(timeBet
// ... [Code preview truncated due to length. Full source in attached file] ...

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