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

FREE DungeonEvents : 3.5.2 3.5.2

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

namespace Oxide.Plugins
{
    [Info("Dungeon Events", "Marte6", "3.5.2")]
    [Description("Create dungeons populated with NPCs, turrets and loot containers.")]
    public class DungeonEvents : RustPlugin
    {
        [PluginReference]
        private Plugin NpcSpawn = null,
            Friends = null,
            Economics = null,
            ServerRewards = null,
            Notify = null,
            NightVision = null,
            ZoneManager = null,
            Duelist = null,
            RaidableBases = null,
            AbandonedBases = null,
            RestoreUponDeath = null,
            SkillTree = null;
        private static DungeonEvents _instance;
        private Configuration _config;
        private List<ActiveDungeon> _activeDungeons = new List<ActiveDungeon>();
        private List<BasePlayer> _playersBuying = new List<BasePlayer>();
        private Dictionary<ulong, DateTime> _buyCooldowns = new Dictionary<ulong, DateTime>();
        private List<DungeonMarker> _activeDungeonMarkers = new List<DungeonMarker>();
        private Queue<DungeonRequest> _dungeonQueue = new Queue<DungeonRequest>();
        private Queue<DungeonRequest> _dungeonFailedAutoSpawnQueue = new Queue<DungeonRequest>();
        private Queue<DungeonRequest> _dungeonFailedBuyQueue = new Queue<DungeonRequest>();
        private Timer dungeonTimer;
        private bool serverStarted = false;
        private bool isCreatingDungeon = false;
        private const bool ForceDefaultConfig = false;
        private const float TimeTimers = 10f;
        private const string PermissionAdmin = "dungeonevents.admin";
        private const string PermissionBuy = "dungeonevents.buy";
        private const string PermissionEnter = "dungeonevents.enter";
        private const ulong OwnerID = 10203040505;
        private const string UiEventPanel = "yFifW5s1zAY09h5cU0qeIQUNV6GGwevG";
        private const string UiMainPanel = "5cU06GGweeIQ09hyFifW5qvGVsUNAY1z";
        private const string UiCommandClose = "lDM82GJH3biLcI95ic8zzteteOeQx77h";
        private Dictionary<DungeonTierConfig, TierInfo> _tierInfoMap = new Dictionary<DungeonTierConfig, TierInfo>();
        private readonly string[] filesToDelete = new string[] { "Dungeon_01.json", "Dungeon_02.json", "Dungeon_03.json", "Dungeon_001.json", "Dungeon_002.json", "Dungeon_003.json" };
        private static readonly WaitForSeconds SmallDelay = new WaitForSeconds(0.15f);
        private static readonly WaitForSeconds BigDelay = new WaitForSeconds(0.50f);

        private class SpawnedEntitiesInfo
        {
            public List<ulong> EntityIDs { get; set; } = new List<ulong>();
        }

        private void Init()
        {
            _instance = this;
            permission.RegisterPermission(PermissionEnter, this);
            permission.RegisterPermission(PermissionAdmin, this);
            permission.RegisterPermission(PermissionBuy, this);
        }

        private void OnServerInitialized()
        {
            if (BasePlayer.activePlayerList.Count > 0)
            {
                serverStarted = true;
                Start();
            }
        }

        private void Unload()
        {
            dungeonTimer?.Destroy();
            _dungeonQueue.Clear();
            DestroyAllUis();
            RemoveAllDungeons();
        }

        private void OnPlayerConnected(BasePlayer player)
        {
            if (serverStarted)
                return;
            serverStarted = true;
            Start();
        }

        object OnEntityTakeDamage(BuildingBlock block, HitInfo info)
        {
            if (!IsDungeonEntity(block))
                return null;
            info.damageTypes?.ScaleAll(0f);
            return true;
        }

        private object CanDropActiveItem(BasePlayer player)
        {
            if (RestoreUponDeath != null)
            {
                return null;
            }
            if (player == null)
                return null;
            if (GetDungeonForPlayer(player) != null)
            {
                var activeItem = player.GetActiveItem();
                if (activeItem != null)
                    return false;
            }
            return null;
        }

        private object CanPickupEntity(BasePlayer player, BaseEntity entity)
        {
            if (player == null)
                return null;
            if (GetDungeonForPlayer(player) != null)
            {
                return false;
            }
            return null;
        }

        object CanDeployItem(BasePlayer player, Deployer deployer, ulong entityId)
        {
            if (player == null)
                return null;
            var dungeon = GetDungeonForPlayer(player);
            if (dungeon != null)
            {
                return false;
            }
            return null;
        }

        object CanBuild(Planner planner, Construction prefab, Construction.Target target)
        {
            var player = planner?.GetOwnerPlayer();
            if (player == null)
                return null;
            if (GetDungeonForPlayer(player) != null)
                return false;
            Vector3 buildPos = target.position;
            if (buildPos == Vector3.zero && target.socket != null && target.entity != null)
                buildPos = target.GetWorldPosition();
            float r = _config.RadiusSphere;
            float r2 = r * r;
            foreach (var dungeon in _activeDungeons)
            {
                if (dungeon.PortalPosition == Vector3.zero)
                    continue;
                float dx = buildPos.x - dungeon.PortalPosition.x;
                float dz = buildPos.z - dungeon.PortalPosition.z;
                if (dx * dx + dz * dz <= r2)
                    return false;
            }
            return null;
        }

        private object OnPlayerCommand(BasePlayer player, string command, string[] args)
        {
            if (player == null)
                return null;
            if (GetDungeonForPlayer(player) == null)
                return null;
            if (_config.BlockCommands.Contains("/" + command.ToLower()))
            {
                NotifyPlayer(player, "BlockedCommands", 0);
                return true;
            }
            return null;
        }

        private object OnServerCommand(ConsoleSystem.Arg arg)
        {
            if (arg == null || arg.cmd == null)
                return null;
            BasePlayer player = arg.Player();
            if (player != null && (GetDungeonForPlayer(player) != null))
            {
                if (_config.BlockCommands.Contains(arg.cmd.Name.ToLower()) || _config.BlockCommands.Contains(arg.cmd.FullName.ToLower()))
                {
                    NotifyPlayer(player, "BlockedCommands", 0);
                    return true;
                }
            }
            return null;
        }

        private object OnEntityTakeDamage(ScientistNPC scientistNPC, HitInfo info)
        {
            if (scientistNPC == null || info?.Initiator == null)
                return null;
            if (info.Initiator is AutoTurret turret && IsDungeonEntity(turret))
            {
                info.damageTypes?.ScaleAll(0f);
            }
            return null;
        }

        private object CanEntityTakeDamage(BasePlayer victim, HitInfo info)
        {
            if (info?.Initiator == null || info.Initiator.net == null || !IsPlayer(victim))
                return null;
            if (info.Initiator is ScientistNPC && IsDungeonEntity(info.Initiator))
                return true;
            if (info.Initiator is AutoTurret && IsDungeonEntity(info.Initiator))
                return true;
            return null;
        }

        private object CanEntityTakeDamage(AutoTurret autoTurret, HitInfo hitinfo)
        {
            if (autoTurret == null || hitinfo == null)
                return null;
            if (!IsDungeonEntity(autoTurret))
                return null;
            if (hitinfo.InitiatorPlayer == null || !IsPlayer(hitinfo.Initiator as BasePlayer))
                return false;
            return true;
        }

        private object CanEntityTakeDamage(StorageContainer storageContainer, HitInfo hitinfo)
        {
            if (storageContainer == null || hitinfo == null)
                return null;
            if (!IsDungeonEntity(storageContainer))
                return null;
            if (hitinfo.InitiatorPlayer == null || !IsPlayer(hitinfo.Initiator as BasePlayer))
                return false;
            return true;
        }

        private object CanEntityTakeDamage(Door victim, HitInfo hitinfo)
        {
            if (victim == null || hitinfo == null)
                return null;
            if (!IsDungeonEntity(victim))
                return null;
            if (hitinfo.InitiatorPlayer == null || !IsPlayer(hitinfo.Initiator as BasePlayer))
                return false;
            return true;
        }

        private object OnCustomNpcTarget(ScientistNPC scientistNPC, BasePlayer player)
        {
            if (scientistNPC == null || !IsDungeonEntity(scientistNPC))
                return null;
            if (player == null || !player.userID.IsSteamId())
                return false;
            return null;
        }

        private object CanEntityBeTargeted(BasePlayer player, AutoTurret turret)
        {
            if (turret == null || !IsDungeonEntity(turret))
                return null;
            if (player == null || !player.userID.IsSteamId())
                return false;
            return true;
        }

        private object OnEntityEnter(TargetTrigger trigger, ScientistNPC scientistNPC)
        {
            if (trigger == null || scientistNPC == null || scientistNPC.net == null || scientistNPC.userID.IsSteamId())
                return null;
            AutoTurret autoTurret = trigger.GetComponentInParent<AutoTurret>();
            if (autoTurret == null || autoTurret.net == null)
                return null;
            if (IsDungeonEntity(autoTurret))
                return true;
            return null;
        }

        private object OnPortalUse(BasePlayer player, BasePortal portal)
        {
            var activeDungeon = GetActiveDungeonByPortal(portal);
            if (activeDungeon == null)
                return null;
            if (!activeDungeon.Spawned)
            {
                NotifyPlayer(player, "DungeonStillSpawningMessage", 0);
                return false;
            }
            if (_config.LockDungeonToPlayer && !CanEnter(player, activeDungeon))
            {
                NotifyPlayer(player, "NoAccess", 0);
                return false;
            }
            return null;
        }

        public class CorpseLootData : MonoBehaviour
        {
            public bool IsBoss;
            public NpcConfig LootConfig;
        }

        private void OnCorpsePopulate(ScientistNPC npc, NPCPlayerCorpse corpse)
        {
            if (npc == null || corpse == null)
                return;
            if (!IsDungeonEntity(npc))
                return;
            var activeDungeon = GetActiveDungeonByEntity(npc);
            if (activeDungeon == null)
                return;
            bool isBoss = npc.GetComponent<BossMonoBehaviour>() != null;
            var lootConfig = isBoss ? activeDungeon.TierConfig?.BossNpcConfig : activeDungeon.TierConfig?.NpcConfig;
            var corpseData = corpse.gameObject.AddComponent<CorpseLootData>();
            corpseData.IsBoss = isBoss;
            corpseData.LootConfig = lootConfig;
            NextTick(() =>
            {
                if (corpse == null)
                    return;
                var storedData = corpse.GetComponent<CorpseLootData>();
                if (storedData == null || storedData.LootConfig == null)
                    return;
                Effect.server.Run("assets/prefabs/weapons/flashbang/effects/fx-flashbang-boom.prefab", corpse.transform.position);
                var container = corpse.containers[0];
                container.Clear();
                var items = storedData.LootConfig.LootDropConfig?.Items;
                if (items != null && items.Count > 0)
                {
                    var lootItems = items.OrderBy(_ => Random.value).ToList();
                    foreach (var itemCfg in lootItems)
                    {
                        if (Random.value * 100f <= itemCfg.InclusionChancePercentage)
                        {
                            var def = ItemManager.FindItemDefinition(itemCfg.ShortName);
                            if (def == null)
                                continue;
                            int amount = Random.Range(itemCfg.MinimumAmount, itemCfg.MaximumAmount + 1);
                            if (container.itemList.Count >= container.capacity)
                                break;
                            var item = ItemManager.Create(def, amount, itemCfg.SkinID);
                            if (!string.IsNullOrEmpty(itemCfg.CustomName))
                                item.name = itemCfg.CustomName;
                            item.MoveToContainer(container);
                        }
                    }
                }
            });
        }

        private void OnPlayerDeath(BasePlayer player, HitInfo info)
        {
            if (player == null || !player.userID.IsSteamId())
                return;
            ActiveDungeon dungeon;
            try
            {
                dungeon = GetDungeonForPlayer(player);
            }
            catch (Exception)
            {
                return;
            }
            if (dungeon == null)
                return;
            var basePortal = dungeon.BasePortal;
            var insidePortal = dungeon.InsidePortal;
            if (basePortal == null || insidePortal == null)
                return;
            if (basePortal.transform == null || insidePortal.transform == null)
                return;
            try
            {
                TeleportPlayerToOutsidePortal(player, dungeon);
            }
            catch (Exception) { }
            if (dungeon.Entities == null)
                return;
            Vector3 exitPos;
            try
            {
                exitPos = insidePortal.transform.position;
            }
            catch
            {
                return;
            }
            foreach (var door in dungeon.Entities.OfType<Door>())
            {
                if (door == null || door.IsDestroyed || door.transform == null)
                    continue;
                try
                {
                    if (Vector3.Distance(door.transform.position, exitPos) <= 3f)
                    {
                        door.SetOpen(false);
                        door.SendNetworkUpdate();
                    }
                }
                catch (Exception) { }
            }
        }

        object CanRaidBlock(BasePlayer player)
        {
            var dungeon = GetDungeonForPlayer(player);
            if (dungeon != null)
                return false;
            return null;
        }

        private void OnEntityDeath(BaseCombatEntity entity, HitInfo info)
        {
            if (entity == null || info?.InitiatorPlayer == null)
                return;
            ActiveDungeon dungeon = GetActiveDungeonByEntity(entity);
            if (dungeon == null || !dungeon.Spawned)
                return;
            bool isNpc = entity is ScientistNPC;
            bool isTurret = entity is AutoTurret;
            bool isBox = entity is StorageContainer;
            if (!isNpc && !isTurret && !isBox)
                return;
            RewardConfig r = dungeon.TierConfig?.RewardConfig;
            if (r == null)
                return;
            int econ =
                isNpc ? r.NpcEconomicsReward
                : isTurret ? r.TurretEconomicsReward
                : r.BoxEconomicsReward;
            int sr =
                isNpc ? r.NpcServerRewards
                : isTurret ? r.TurretServerRewards
                : r.BoxServerRewards;
            BasePlayer attacker = info.InitiatorPlayer;
            if (econ > 0 && Economics != null)
            {
                Economics.Call("Deposit", attacker.userID, (double)econ);
                attacker.ChatMessage(Msg(attacker.UserIDString, "EconRewardMessage", econ));
            }
            if (sr > 0 && ServerRewards != null)
            {
                ServerRewards.Call("AddPoints", attacker.userID, sr);
                attacker.ChatMessage(Msg(attacker.UserIDString, "ServerRewardMessage", sr));
            }
        }

        private void SaveDungeonEntities(string dungeonId, List<ulong> entityIds)
        {
            var file = Interface.Oxide.DataFileSystem.GetFile($"{Name}/{dungeonId}");
            file.WriteObject(entityIds);
        }

        private List<ulong> LoadDungeonEntities(string dungeonId)
        {
            var file = Interface.Oxide.DataFileSystem.GetFile($"{Name}/{dungeonId}");
            return file.ReadObject<List<ulong>>() ?? new List<ulong>();
        }

        private void DeleteDungeonEntitiesFile(string dungeonId)
        {
            string folder = Path.Combine(Interface.Oxide.DataFileSystem.Directory, Name);
            if (!Directory.Exists(folder))
                return;
            string filePath = Path.Combine(folder, $"{dungeonId}.json");
            if (File.Exists(filePath))
            {
                try
                {
                    File.Delete(filePath);
                }
                catch (Exception ex)
                {
                    PrintError("Error deleting dungeon file: " + ex.Message);
                }
            }
        }

        private void RegisterSpawnedEntityForDungeon(BaseEntity entity, string dungeonId)
        {
            if (entity != null && entity.net != null)
            {
                List<ulong> ids = LoadDungeonEntities(dungeonId);
                ids.Add(entity.net.ID.Value);
                SaveDungeonEntities(dungeonId, ids);
            }
        }

        private void RemoveEntitiesForDungeon(string dungeonId)
        {
            List<ulong> ids = LoadDungeonEntities(dungeonId);
            foreach (ulong id in ids)
            {
                BaseEntity entity = BaseNetworkable.serverEntities.Find(new NetworkableId(id)) as BaseEntity;
                if (entity != null && !entity.IsDestroyed)
                    entity.Kill();
            }
            DeleteDungeonEntitiesFile(dungeonId);
        }

        private void RemoveLeftoverDungeonFiles()
        {
            string folder = Path.Combine(Interface.Oxide.DataFileSystem.Directory, Name);
            if (!Directory.Exists(folder))
                return;
            foreach (var file in Directory.GetFiles(folder, "*.json"))
            {
                try
                {
                    string fileName = Path.GetFileNameWithoutExtension(file);
                    RemoveEntitiesForDungeon(fileName);
                }
                catch (Exception ex)
                {
                    PrintError("Error removing leftover dungeon file: " + ex.Message);
                }
            }
            ServerMgr.Instance.StartCoroutine(CleanupExistingEntities());
        }

        private void DeleteDungeonFiles()
        {
            string pluginDataFolder = Path.Combine(Interface.Oxide.DataDirectory, Name);
            if (!Directory.Exists(pluginDataFolder))
            {
                return;
            }
            foreach (var fileName in filesToDelete)
            {
                string filePath = Path.Combine(pluginDataFolder, fileName);
                if (File.Exists(filePath))
                {
                    try
                    {
                        File.Delete(filePath);
                    }
                    catch (Exception) { }
                }
            }
        }

        private Vector3 GetCenterFoundationPositionNearPlayer(BasePlayer player, float portalHeight)
        {
            const float searchRadius = 8f;
            const float minDistance = 2f;
            const float playerClearance = 1.5f;
            Vector3 selected = Vector3.zero;
            float bestDist = float.MaxValue;
            List<BuildingBlock> blocks = Pool.GetList<BuildingBlock>();
            Vis.Entities(player.transform.position, searchRadius, blocks, Layers.Mask.Construction);
            foreach (var block in blocks)
            {
                if (block == null)
                    continue;
                if (!block.PrefabName.Contains("foundation"))
                    continue;
                float dist = Vector3.Distance(block.transform.position, player.transform.position);
                if (dist < minDistance)
                    continue;
                List<BasePlayer> nearPlayers = Pool.GetList<BasePlayer>();
                Vis.Entities(block.transform.position, playerClearance, nearPlayers, Layers.Mask.Player_Server);
                bool hasPlayer = nearPlayers.Count > 0;
                Pool.FreeList(ref nearPlayers);
                if (hasPlayer)
                    continue;
                if (dist < bestDist)
                {
                    bestDist = dist;
                    selected = block.transform.position;
                }
            }
            if (selected == Vector3.zero)
            {
                foreach (var block in blocks)
                {
                    if (block == null)
                        continue;
                    if (!block.PrefabName.Contains("foundation"))
                        continue;
                    List<BasePlayer> nearPlayers = Pool.GetList<BasePlayer>();
                    Vis.Entities(block.transform.position, playerClearance, nearPlayers, Layers.Mask.Player_Server);
                    bool hasPlayer = nearPlayers.Count > 0;
                    Pool.FreeList(ref nearPlayers);
                    if (hasPlayer)
                        continue;
                    float dist = Vector3.Distance(block.transform.position, player.transform.position);
                    if (dist < bestDist)
                    {
                        bestDist = dist;
                        selected = block.transform.position;
                    }
                }
            }
            Pool.FreeList(ref blocks);
            if (selected == Vector3.zero)
                return Vector3.zero;
            return new Vector3(selected.x, portalHeight, selected.z);
        }

        private void RewardDungeonClear(ActiveDungeon dungeon)
        {
            int econReward = dungeon.TierConfig.RewardConfig.DungeonClearEconomicsReward;
            int srReward = dungeon.TierConfig.RewardConfig.DungeonClearServerRewards;
            double xpReward = dungeon.TierConfig.RewardConfig.DungeonClearXpReward;
            bool rewarded = false;
            if (dungeon.OwnerID != 0UL)
            {
                var owner = BasePlayer.FindByID(dungeon.OwnerID);
                if (owner != null && owner.IsConnected)
                {
                    try
                    {
                        if (econReward > 0 && Economics != null)
                        {
                            Economics.Call("Deposit", owner.userID, (double)econReward);
                            owner.ChatMessage(Msg(owner.UserIDString, "DungeonClearEconomyReward", econReward));
                        }
                        if (srReward > 0 && ServerRewards != null)
                        {
                            ServerRewards.Call("AddPoints", owner.userID, srReward);
                            owner.ChatMessage(Msg(owner.UserIDString, "DungeonClearServerReward", srReward));
                        }
                        if (xpReward > 0.0 && SkillTree != null)
                        {
                            SkillTree.Call("AwardXP", owner.userID, xpReward, "DungeonEvents", false);
                            owner.ChatMessage(Msg(owner.UserIDString, "DungeonClearXpReward", xpReward));
                        }
                        _buyCooldowns[owner.userID] = DateTime.UtcNow.AddSeconds(_config.DungeonSpawn.BuyCooldown);
                        rewarded = true;
                    }
                    catch
                    {
                        rewarded = false;
                    }
                }
            }
            if (!rewarded)
            {
                foreach (ulong uid in dungeon.PlayersInside.ToList())
                {
                    var participant = BasePlayer.FindByID(uid);
                    if (participant != null && participant.IsConnected)
                    {
                        try
                        {
                            if (econReward > 0 && Economics != null)
                            {
                                Economics.Call("Deposit", participant.userID, (double)econReward);
                                participant.ChatMessage(Msg(participant.UserIDString, "DungeonClearEconomyReward", econReward));
                            }
                            if (srReward > 0 && ServerRewards != null)
                            {
                                ServerRewards.Call("AddPoints", participant.userID, srReward);
                                participant.ChatMessage(Msg(participant.UserIDString, "DungeonClearServerReward", srReward));
                            }
                            if (xpReward > 0.0 && SkillTree != null)
                            {
                                SkillTree.Call("AwardXP", participant.userID, xpReward, "DungeonEvents", false);
                                participant.ChatMessage(Msg(participant.UserIDString, "DungeonClearXpReward", xpReward));
                            }
                            _buyCooldowns[participant.userID] = DateTime.UtcNow.AddSeconds(_config.DungeonSpawn.BuyCooldown);
                            break;
                        }
                        catch { }
                    }
                }
            }
            string redLightPrefab = "assets/bundled/prefabs/modding/cinematic/cinelights/cinelight_point_red.prefab";
            string greenLightPrefab = "assets/bundled/prefabs/modding/cinematic/cinelights/cinelight_point_green.prefab";
            foreach (var entity in dungeon.Entities.ToList())
            {
                if (entity != null && entity.PrefabName == redLightPrefab)
                {
                    Vector3 pos = entity.transform.position;
                    Quaternion rot = entity.transform.rotation;
                    entity.Kill();
                    var newLight = GameManager.server.CreateEntity(greenLightPrefab, pos, rot);
                    if (newLight != null)
                    {
                        newLight.Spawn();
                        dungeon.Entities.Add(newLight);
                        RegisterSpawnedEntityForDungeon(newLight, dungeon.UniqueId);
                    }
                }
            }
            foreach (var entity in dungeon.Entities.ToList())
            {
                if (entity == null)
                    continue;
                if (entity is Door || entity.PrefabName.Contains("door"))
                {
                    entity.Kill();
                    dungeon.Entities.Remove(entity);
                }
            }
            dungeon.HasBeenCleared = true;
            dungeon.DestructionDelay = _config.DungeonSpawn.DungeonRemoval.RemovalAfterDestroyedTimer;
            dungeon.DestructionCountdownStart = DateTime.UtcNow;
            if (dungeon.InsidePortal != null && !dungeon.InsidePortal.IsDestroyed)
            {
                BasePlayer targetPlayer = null;
                foreach (ulong uid in dungeon.PlayersInside)
                {
                    var p = BasePlayer.FindByID(uid);
                    if (p != null && p.IsConnected)
                    {
                        targetPlayer = p;
                        break;
                    }
                }
                if (targetPlayer == null && dungeon.OwnerID != 0UL)
                    targetPlayer = BasePlayer.FindByID(dungeon.OwnerID);
                if (targetPlayer != null)
                {
                    Vector3 centerPos = GetCenterFoundationPositionNearPlayer(targetPlayer, dungeon.InsidePortal.transform.position.y);
                    if (centerPos == Vector3.zero)
                    {
                        Vector3 fallback = targetPlayer.transform.position + targetPlayer.transform.right * 2f;
                        fallback.y = dungeon.InsidePortal.transform.position.y;
                        dungeon.InsidePortal.transform.position = fallback;
                    }
                    else
                    {
                        dungeon.InsidePortal.transform.position = centerPos;
                    }
                    dungeon.InsidePortal.SendNetworkUpdateImmediate();
                }
            }
        }

        private void TeleportPlayersAndDestroyDungeon(ActiveDungeon dungeon)
        {
            foreach (ulong userID in dungeon.PlayersInside.ToList())
            {
                BasePlayer player = BasePlayer.FindByID(userID);
                TeleportPlayerToOutsidePortal(player, dungeon);
                player.ChatMessage(Msg(player?.UserIDString, "Dungeonclosed"));
            }
            DestroyDungeon(dungeon);
        }

        private void TeleportPlayerToOutsidePortal(BasePlayer player, ActiveDungeon dungeon)
        {
            if (player == null || !player.IsConnected)
                return;
            Vector3 exitPos = (dungeon.BasePortal != null && dungeon.BasePortal.transform != null) ? dungeon.BasePortal.transform.position : dungeon.PortalPosition;
            List<ulong> playersInside = dungeon.PlayersInside.ToList();
            playersInside.Sort();
            int count = playersInside.Count;
            int index = playersInside.IndexOf(player.userID);
            if (index < 0)
                index = 0;
            float angleIncrement = 360f / Mathf.Max(count, 1);
            float angle = angleIncrement * index;
            float rad = angle * Mathf.Deg2Rad;
            float distance = 10f;
            Vector3 horizontalOffset = new Vector3(Mathf.Cos(rad), 0f, Mathf.Sin(rad)) * distance;
            Vector3 verticalOffset = Vector3.up * 5f;
            Vector3 newPos = exitPos + horizontalOffset + verticalOffset;
            player.Teleport(newPos);
            dungeon.PlayersInside.Remove(player.userID);
            UpdateTime(player, -1);
            DestroyEventUi(player);
            player.limitNetworking = false;
            player.SendNetworkUpdateImmediate();
        }

        [ConsoleCommand("buydungeon")]
        private void BuyDungeonConsoleCommand(ConsoleSystem.Arg arg)
        {
            if (arg == null || !arg.HasArgs(2))
            {
                LogDebug("Usage: buydungeon <tierName> <playerID>", 1);
                return;
            }
            string tierName = arg.GetString(0);
            string playerId = arg.GetString(1);
            if (string.IsNullOrEmpty(tierName) || string.IsNullOrEmpty(playerId))
                return;
            BasePlayer player = BasePlayer.FindAwakeOrSleeping(playerId);
            if (player == null)
            {
                LogDebug($"Player with ID '{playerId}' not found.", 1);
                return;
            }
            ProcessBuyDungeon(player, tierName);
        }

        [ConsoleCommand(UiCommandClose)]
        private void CloseCommandUi(ConsoleSystem.Arg arg)
        {
            var player = arg.Player();
            if (player != null)
                DestroyUi(player);
        }

        [ChatCommand("buydungeon")]
        private void BuyDungeonChatCommandUi(BasePlayer player, string command, string[] args)
        {
            if (player == null)
                return;
            if (!permission.UserHasPermission(player.UserIDString, PermissionBuy))
            {
                NotifyPlayer(player, "NoAccess", 0);
                return;
            }
            if (args != null && args.Length > 0)
            {
                ProcessBuyDungeon(player, args[0]);
                return;
            }
            if (!_config.EnablePurchases)
            {
                NotifyPlayer(player, "PurchasesDisabled", 0);
                return;
            }
            OpenBuyDungeonGUI(player);
        }

        [ChatCommand("createdungeon")]
        private void CreateDungeonCommand(BasePlayer player, string command, string[] args)
        {
            if (!IsAdmin(player))
                return;
            if (args.Length == 0)
            {
                NotifyPlayer(player, "UsageCreateMessage", 0);
                return;
            }
            string tierName = args[0].ToLower();
            var prop = _config.Tiers.GetType().GetProperties().FirstOrDefault(p => p.Name.Equals(tierName, StringComparison.OrdinalIgnoreCase));
            var tier = prop?.GetValue(_config.Tiers) as DungeonTierConfig;
            if (tier == null)
            {
                NotifyPlayer(player, "InvalidTierMessage", 0, tierName, GetAvailableTiers());
                return;
            }
            if (!tier.Enabled)
            {
                NotifyPlayer(player, "ThisTierDisabled", 0);
                return;
            }
            LogDebug("Received dungeon creation request.", 1);
            EnqueueDungeonRequest(player, tier, false);
        }

        [ChatCommand("de.reloadconfig")]
        private void ReloadConfigCommand(BasePlayer player, string command, string[] args)
        {
            if (!IsAdmin(player))
                return;
            LoadConfig();
            dungeonTimer?.Destroy();
            dungeonTimer = timer.Every(TimeTimers, HandleDungeonTimers);
            UpdateMarkers();
            _dungeonQueue.Clear();
            NotifyPlayer(player, "ConfigReloaded", 0);
        }

        [ChatCommand("de.toggle")]
        private void TogglePurchasesCommand(BasePlayer player, string command, string[] args)
        {
            if (!IsAdmin(player))
                return;
            _config.EnablePurchases = !_config.EnablePurchases;
            if (_config.EnablePurchases)
                NotifyPlayer(player, "PurchasesEnabled", 0);
            else
                NotifyPlayer(player, "PurchasesDisabled", 0);
        }

        [ChatCommand("removeinactivedungeons")]
        private void RemoveInactiveDungeonsCommand(BasePlayer player, string command, string[] args)
        {
            if (!IsAdmin(player))
                return;
            var removedDungeons = RemoveInactiveDungeons();
            NotifyPlayerOnRemoval(player, removedDungeons);
        }

        [ChatCommand("removealldungeons")]
        private void RemoveAllDungeonsCommand(BasePlayer player, string command, string[] args)
        {
            if (!IsAdmin(player))
                return;
            var removed = RemoveAllDungeons();
            NotifyPlayerOnRemoval(player, removed);
        }

        [ChatCommand("de.removenearest")]
        private void RemoveNearestDungeonCommand(BasePlayer player, string command, string[] args)
        {
            if (!IsAdmin(player))
                return;
            if (_activeDungeons.Count == 0)
            {
                NotifyPlayer(player, "NoDungeonsToRemove", 0);
                return;
            }
            ActiveDungeon nearest = null;
            float minDist = float.MaxValue;
            foreach (var dungeon in _activeDungeons)
            {
                float d1 = Vector3.Distance(player.transform.position, dungeon.PortalPosition);
                float d2 = Vector3.Distance(player.transform.position, dungeon.DungeonPosition);
                float d = Mathf.Min(d1, d2);
                if (d < minDist)
                {
                    minDist = d;
                    nearest = dungeon;
                }
            }
            if (nearest == null || minDist > 10f)
            {
                NotifyPlayer(player, "TooFarToRemove", 0);
                return;
            }
            DestroyDungeon(nearest);
            NotifyPlayer(player, "DungeonRemovedDetail", 0, nearest.TierName, nearest.Grid);
        }

        [ChatCommand("removedungeon")]
        private void RemoveOwnDungeonCommand(BasePlayer player, string command, string[] args)
        {
            if (player == null)
                return;
            var owned = _activeDungeons.FirstOrDefault(d => d.OwnerID == player.userID);
            if (owned == null)
            {
                NotifyPlayer(player, "NotDungeonOwner", 0);
                return;
            }
            DestroyDungeon(owned);
            NotifyPlayer(player, "DungeonRemovedDetail", 0, owned.TierName, owned.Grid);
        }

        [ChatCommand("forceremovealldungeons")]
        private void ForceRemoveAllDungeonsCommand(BasePlayer player, string command, string[] args)
        {
            if (!IsAdmin(player))
                return;
            CleanupExistingEntities();
            NotifyPlayer(player, "CleanedUp", 0);
        }

        [ChatCommand("spawdungeonnentity")]
        private void SpawnDungeonEntityCommand(BasePlayer player, string command, string[] args)
        {
            if (!IsAdmin(player))
            {
                NotifyPlayer(player, "NoAccess", 0);
                return;
            }
            if (args.Length < 2)
            {
                player.ChatMessage("Correct Usage: /spawdungeonnentity <npc|boss|turret> <easy|normal|medium|hard|nightmare>");
                return;
            }
            var entityType = args[0].ToLower();
            var difficultyName = args[1].ToLower();
            DungeonTierConfig tierConfig = null;
            var allTiersProps = _config.Tiers.GetType().GetProperties();
            var foundTierProp = allTiersProps.FirstOrDefault(p => p.Name.Equals(difficultyName, StringComparison.OrdinalIgnoreCase));
            if (foundTierProp == null)
            {
                player.ChatMessage("Invalid difficulty.Try: easy, normal, medium, hard, nightmare.");
                return;
            }
            tierConfig = foundTierProp.GetValue(_config.Tiers) as DungeonTierConfig;
            if (tierConfig == null)
            {
                player.ChatMessage("Failed to retrieve difficulty settings.");
                return;
            }
            var spawnPos = player.transform.position + (player.eyes.BodyForward() * 2f);
            var spawnRot = Quaternion.Euler(0f, player.eyes.rotation.eulerAngles.y, 0f);
            var dummyDungeon = new ActiveDungeon
            {
                Entities = new List<BaseEntity>(),
                Npcs = new List<BaseEntity>(),
                TierConfig = tierConfig,
            };
            switch (entityType)
            {
                case "npc":
                    SpawnNpc(spawnPos, dummyDungeon, boss: false);
                    player.ChatMessage($"NPC ({difficultyName}) spawned in front of you!");
                    break;
                case "boss":
                    SpawnNpc(spawnPos, dummyDungeon, boss: true);
                    player.ChatMessage($"Boss ({difficultyName}) spawned in front of you!");
                    break;
                case "turret":
                    SpawnTurret(spawnPos, spawnRot, dummyDungeon.TierConfig.AutoTurretConfig, dummyDungeon);
                    player.ChatMessage($"Turret ({difficultyName}) spawned in front of you!");
                    break;
                default:
                    player.ChatMessage("Invalid type! Use /spawdungeonnentity <npc|boss|turret> <easy|normal|medium|hard|nightmare>");
                    break;
            }
        }

        [ConsoleCommand("spawnrandomdungeon")]
        private void SpawnRandomDungeonConsoleCommand(ConsoleSystem.Arg arg)
        {
            if (arg.Player() != null && !IsAdmin(arg.Player()))
            {
                arg.ReplyWith("You do not have permission to run this command.");
                return;
            }
            var tier = GetDifficultyWithLeastActiveDungeons();
            EnqueueDungeonRequest(null, tier, false);
            arg.ReplyWith($"Enqueued random dungeon spawn of tier: {_tierInfoMap[tier].Name} (no owner).");
        }

        [ConsoleCommand("spawnfixeddungeon")]
        private void SpawnFixedDungeonConsoleCommand(ConsoleSystem.Arg arg)
        {
            if (arg.Player() != null && !IsAdmin(arg.Player()))
            {
                arg.ReplyWith("You do not have permission to run this command.");
                return;
            }
            if (!arg.HasArgs(1))
            {
                arg.ReplyWith("Usage: spawnfixeddungeon <tierName>");
                return;
            }
            var tierName = arg.GetString(0).ToLower();
            var tier = _config.Tiers.GetType().GetProperties().FirstOrDefault(prop => prop.Name.ToLower() == tierName)?.GetValue(_config.Tiers) as DungeonTierConfig;
            if (tier == null)
            {
                arg.ReplyWith($"Invalid tier '{tierName}'.Available tiers: {GetAvailableTiers()}");
                return;
            }
            if (!_tierInfoMap.ContainsKey(tier))
            {
                arg.ReplyWith("This tier is disabled.");
                return;
            }
            EnqueueDungeonRequest(null, tier, false);
            arg.ReplyWith($"Enqueued dungeon spawn of tier: {_tierInfoMap[tier].Name} (no owner).");
        }

        public class DungeonRequest
        {
            public BasePlayer Player { get; set; }
            public DungeonTierConfig Tier { get; set; }
            public bool LockToPlayer { get; set; }
            public DungeonOrigin Origin { get; set; }
            public Vector3 PortalPosition { get; set; }
            public Vector3 DungeonPosition { get; set; }
        }

        private IEnumerator CreateDungeon(DungeonRequest request)
        {
            yield return null;
            isCreatingDungeon = true;
            var tierConfig = request.Tier;
            var player = request.Player;
            bool lockDungeonToPlayer = request.LockToPlayer;
            var origin = request.Origin;
            if (NpcSpawn == null)
            {
                LogDebug("NpcSpawn plugin is not loaded.", 2);
                player?.ChatMessage(Msg(player?.UserIDString, "NpcSpawnNotLoaded"));
                _playersBuying.Remove(player);
                isCreatingDungeon = false;
                yield break;
            }
            Vector3 portalPosition = Vector3.zero;
            Vector3 dungeonPosition = Vector3.zero;
            LogDebug("Generating portal spawn point.", 1);
            var configPortal = new GeneratorConfig
            {
                Origin = player != null ? player.transform.position : Vector2.zero,
                ClosestToOrigin = player != null,
                YOffset = 0f,
                minDist = player != null ? 10 : 200,
                blocked = _activeDungeons.Select(d => d.PortalPosition).ToList(),
                AvoidTerrainTopology = true,
                AvoidedTopology =
                    TerrainTopology.Enum.Building
                    | TerrainTopology.Enum.Cliff
                    | TerrainTopology.Enum.Clutter
                    | TerrainTopology.Enum.Monument
                    | TerrainTopology.Enum.Ocean
                    | TerrainTopology.Enum.Rail
                    | TerrainTopology.Enum.Road,
                AboveWater = true,
                MaxSlopeDegrees = 30f,
                CheckSphereRadius = 3f,
                CheckSphereMask =
                    Layers.Mask.AI
                    | Layers.Mask.Bush
                    | Layers.Mask.Clutter
                    | Layers.Mask.Construction
                    | Layers.Mask.Default
                    | Layers.Mask.Deployed
                    | Layers.Mask.Harvestable
                    | Layers.Mask.Physics_Debris
                    | Layers.Mask.Player_Server
                    | Layers.Mask.Prevent_Building
                    | Layers.Mask.Prevent_Movement
                    | Layers.Mask.Tree
                    | Layers.Mask.Trigger
                    | Layers.Mask.Vehicle_Detailed
                    | Layers.Mask.Vehicle_Large
                    | Layers.Mask.Vehicle_World
                    | Layers.Mask.Water
                    | Layers.Mask.World
                    | Layers.Server.Deployed,
                MaxAttempts = 1000,
                UseSlopeCheck = true,
                CheckSafeZones = true,
                ZoneManager = true,
                TerrainMask = Layers.Mask.Terrain | Layers.Mask.World | Layers.Mask.Construction,
                CheckRocks = true,
                RockCheck = RockKeywords,
            };
            yield return TryFindPosition(configPortal, request, true);
            portalPosition = request.PortalPosition;
            LogDebug("Generating dungeon spawn point.", 1);
            var configDungeon = new GeneratorConfig
            {
                Origin = Vector2.zero,
                ClosestToOrigin = false,
                YOffset = 800f,
                minDist = 200,
                blocked = _activeDungeons.Select(d => d.DungeonPosition).ToList(),
                AvoidTerrainTopology = true,
                AvoidedTopology = TerrainTopology.Enum.Monument,
                AboveWater = true,
                MaxSlopeDegrees = 30f,
                CheckSphereRadius = 100f,
                CheckSphereMask =
                    Layers.Mask.AI
                    | Layers.Mask.Bush
                    | Layers.Mask.Clutter
                    | Layers.Mask.Construction
                    | Layers.Mask.Default
                    | Layers.Mask.Deployed
                    | Layers.Mask.Harvestable
                    | Layers.Mask.Physics_Debris
                    | Layers.Mask.Player_Server
                    | Layers.Mask.Prevent_Building
                    | Layers.Mask.Prevent_Movement
                    | Layers.Mask.Tree
                    | Layers.Mask.Trigger
                    | Layers.Mask.Vehicle_Detailed
                    | Layers.Mask.Vehicle_Large
                    | Layers.Mask.Vehicle_World
                    | Layers.Mask.Water
                    | Layers.Mask.World
                    | Layers.Server.Deployed,
                MaxAttempts = 1000,
                UseSlopeCheck = true,
                CheckSafeZones = true,
                ZoneManager = true,
                TerrainMask = Layers.Mask.Terrain | Layers.Mask.World | Layers.Mask.Construction,
                CheckRocks = true,
                RockCheck = RockKeywords,
            };
            yield return TryFindPosition(configDungeon, request, false);
            dungeonPosition = request.DungeonPosition;
            if (portalPosition == Vector3.zero || dungeonPosition == Vector3.zero)
            {
                Requeue(request, origin);
                LogDebug("Failed to find spawn points.Requeuing...", 1);
                isCreatingDungeon = false;
                yield break;
            }
            LogDebug("Dungeon spawn point found.");
// ... [Code preview truncated due to length. Full source in attached file] ...

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