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

FREE Roams : 1.0.2 1.0.2

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

namespace Oxide.Plugins
{
    [Info("Roams", "Strobez", "1.0.2")]
    internal class Roams : RustPlugin
    {

        #region Commands
        [ChatCommand("roams")]
        private async void CmdRoams(BasePlayer? player, string command, string[] args)
        {
            if (player == null)
                return;

            if (_activeRoam == null)
            {
                SendReply(player,
                    "<color=#5557AA>Teleportation</color>\nThere must be an active roam to use this command!");
                return;
            }

            if (_playersInZone.Contains(player.userID))
            {
                SendReply(player, "<color=#5557AA>Teleportation</color>\nYou are already in the roam zone!");
                return;
            }

            if (_cooldowns.TryGetValue(player.userID, out DateTime cooldownTime))
                if (cooldownTime.AddMinutes(2) > DateTime.Now)
                {
                    TimeSpan timeLeft = cooldownTime.AddMinutes(2) - DateTime.Now;
                    SendReply(player,
                        $"You must wait <color=#5557AA>{timeLeft.Minutes:D1} minutes</color> and <color=#5557AA>{timeLeft.Seconds:D1} seconds</color> before you can use this command again!");
                    return;
                }

            KeyValuePair<string, Vector3> roam = _activeRoam.ElementAt(0);

            for (int i = 0; i < 11; i++)
            {
                switch (i)
                {
                    case 10:
                        player.Teleport(roam.Value);
                        player.ChatMessage(
                            $"<color=#5557AA>Teleportation</color>\nYou have been teleported to the <color=#5557AA>{roam.Key}</color>!");
                        break;
                    case 0:
                        player.ChatMessage(
                            $"<color=#5557AA>Teleportation</color>\nYou will be teleported to the <color=#5557AA>{roam.Key}</color> in <color=#5557AA>{10 - i} seconds</color>!");
                        break;
                    default:
                        if (i >= 7)
                            player.ChatMessage(
                                $"<color=#5557AA>Teleportation</color>\nYou will be teleported to the <color=#5557AA>{roam.Key}</color> in <color=#5557AA>{10 - i} seconds</color>!");
                        break;
                }

                await Task.Delay(1000);
            }

            _cooldowns[player.userID] = DateTime.Now;
        }
        #endregion

        #region Defines
        public static readonly Dictionary<string, Vector3> RoamIslands = new();
        public static readonly Dictionary<string?, ClanStatistics> _clanStats = new();
        private const float _safeDuration = 300f;
        public const float RoamInterval = 2700f;
        public const float RoamDuration = 900f;
        private static readonly Dictionary<string, Vector3> _activeRoam = new();
        private static readonly Dictionary<ulong, DateTime> _cooldowns = new();

        [PluginReference] private Plugin Clans;
        private readonly List<ulong> _playersInZone = new();
        private readonly Dictionary<ulong, Timer> _playerUiTimers = new();

        private static Roams _instance = new();
        #endregion

        #region Core
        private void CreateRoam(string roamType, Vector3 position)
        {
            _instance.SendGlobalMessage(
                $"A new roam event has started at <color=#5557AA>{roamType}</color>!\n<size=12>Use <color=#ACFA58>/roams</color> to join!</size>");
            Debug.Log($"[Roams] A new roam event has started at {roamType}| Auto-Generated | Timestamp: {DateTime.Now}");

            GameObject go = new();
            go.AddComponent<ZoneBehaviour>().Position = position;
            go.GetComponent<ZoneBehaviour>().Radius = 250f;
            go.GetComponent<ZoneBehaviour>().Duration = RoamDuration;
        }

        private async void HandleRoamInterval()
        {
            if (RoamIslands.Count == 0)
                return;

            int idx = Random.Range(0, RoamIslands.Count);
            KeyValuePair<string, Vector3> roamIsland = RoamIslands.ElementAt(idx);

            _activeRoam.Add(roamIsland.Key, roamIsland.Value);

            for (int i = 0; i < 10; i++)
            {
                if (i == 9)
                {
                    CreateRoam(roamIsland.Key, roamIsland.Value);
                }
                else
                {
                    _instance.SendGlobalMessage(
                        $"A roam is starting in {FormatTime(_safeDuration - i * 30)}!\n<size=12>Use <color=#ACFA58>/roams</color> to join!</size>");
                    Debug.Log(
                        $"[Roams] A roam is starting in {FormatTime(_safeDuration - i * 30)}| Auto-Generated | Timestamp: {DateTime.Now}");
                }

                await Task.Delay(30000);
            }
        }
        #endregion

        #region Helpers
        private void SendGlobalMessage(string message)
        {
            foreach (BasePlayer player in BasePlayer.activePlayerList)
            {
                player.ChatMessage($"<size=18><color=#5557AA>Rust Roams</color></size>\n{message}");
            }
        }

        private static string FormatTime(float duration)
        {
            TimeSpan timeSpan = TimeSpan.FromSeconds(duration);
            if (timeSpan.TotalSeconds < 1)
                return "0 seconds";

            string formattedTime = "";
            if (timeSpan.Minutes > 0)
                formattedTime += $"<color=#5557AA>{timeSpan.Minutes} minute{(timeSpan.Minutes > 1 ? "s" : "")}</color> ";

            if (timeSpan.Seconds > 0)
                formattedTime += $"<color=#5557AA>{timeSpan.Seconds} second{(timeSpan.Seconds > 1 ? "s" : "")}</color>";

            return formattedTime.Trim();
        }

        private string GetClanTag(BasePlayer? player)
        {
            return (string) Clans?.Call("GetClanOf", player)!;
        }

        private List<string> GetClanMembers(BasePlayer? player)
        {
            return (List<string>) Clans?.Call("GetClanMembers", player?.UserIDString)!;
        }
        #endregion

        #region Components
        public class ClanStatistics
        {
            public int Deaths;
            public int Kills;
            public List<string>? Members = new();
            public Dictionary<string, IndividualStatistics> MemberStats = new();
        }

        public class IndividualStatistics
        {
            public int Deaths;
            public int Kills;
        }

        private class ZoneBehaviour : FacepunchBehaviour
        {
            public Vector3 Position = Vector3.zero;
            public float Radius = 100f;
            private readonly List<SphereEntity> _innerSpheres = new();
            private MapMarkerGenericRadius? _roamMarker;
            private SphereCollider _sphereCollider;
            public float Duration { get; set; }

            private void Start()
            {
                GameObject go = gameObject;
                go.transform.position = Position;
                _sphereCollider = go.AddComponent<SphereCollider>();
                _sphereCollider.transform.position = Position;
                _sphereCollider.radius = Radius;
                _sphereCollider.isTrigger = true;
                _sphereCollider.gameObject.layer = (int) Layer.Reserved1;

                for (int i = 0; i < 7; i++)
                {
                    SphereEntity sphere =
                        (SphereEntity) GameManager.server.CreateEntity("assets/prefabs/visualization/sphere.prefab",
                            Position);
                    sphere.currentRadius = Radius * 2;
                    sphere.lerpSpeed = 0;
                    sphere.enableSaving = false;
                    sphere.Spawn();
                    _innerSpheres.Add(sphere);
                }

                Rigidbody innerRb = _innerSpheres[0].gameObject.AddComponent<Rigidbody>();
                innerRb.useGravity = false;
                innerRb.isKinematic = true;

                _roamMarker =
                    GameManager.server.CreateEntity("assets/prefabs/tools/map/genericradiusmarker.prefab", Position) as
                        MapMarkerGenericRadius;
                if (_roamMarker != null)
                {
                    _roamMarker.alpha = 0.33f;
                    _roamMarker.color1 = Color.magenta;
                    _roamMarker.color2 = Color.black;
                    _roamMarker.radius = Radius / 75;
                    _roamMarker.Spawn();
                    _roamMarker.SendUpdate();
                }
            }

            private void Update()
            {
                if (Duration > 0)
                {
                    Duration -= Time.deltaTime;
                }
                else
                {
                    KeyValuePair<string?, ClanStatistics> winningClan = _clanStats.Count > 0
                        ? _clanStats.Aggregate((x, y) => x.Value.Kills > y.Value.Kills ? x : y)
                        : default;

                    if (winningClan.Value.Kills > 0)
                    {
                        StringBuilder message = new();
                        message.AppendLine(
                            $"<color=#5557AA>{winningClan.Key}</color> has won the Roam event with {winningClan.Value.Kills} kills!");
                        message.AppendLine();
                        message.AppendLine($"<color=#5557AA>Members</color> ({winningClan.Value.Members!.Count})");

                        foreach (string userId in winningClan.Value.Members)
                        {
                            IndividualStatistics memberStats = winningClan.Value.MemberStats[userId];
                            BasePlayer? player = BasePlayer.FindAwakeOrSleeping(userId);

                            message.Append(player == null
                                ? $"Unknown Player - K: {memberStats.Kills}, D: {memberStats.Deaths}\n"
                                : $"{player.displayName} - K: {memberStats.Kills}, D: {memberStats.Deaths}\n");
                        }

                        _instance.SendGlobalMessage(message.ToString());
                        Debug.Log($"[Roams] {message}");
                        _clanStats.Clear();
                        _activeRoam.Clear();
                        DestroyImmediate(gameObject);
                        return;
                    }

                    _instance.SendGlobalMessage("There were 0 clans that participated in the Roam event!");
                    Debug.Log("[Roams] There were 0 clans that participated in the Roam event!");
                    _activeRoam.Clear();
                    DestroyImmediate(gameObject);
                }
            }

            private void OnDestroy()
            {
                List<ulong>? list = Pool.GetList<ulong>();
                list.AddRange(_instance._playersInZone);

                foreach (ulong userId in list)
                {
                    BasePlayer? player = BasePlayer.Find(userId.ToString());
                    if (player == null)
                        continue;

                    Timer uiTimer;
                    if (_instance._playerUiTimers.TryGetValue(player.userID, out uiTimer)) uiTimer.Destroy();

                    _instance._playerUiTimers.Remove(player.userID);
                    CuiHelper.DestroyUi(player, "RoamHeaderText");
                    CuiHelper.DestroyUi(player, "TimeRemaining");
                }

                Pool.FreeList(ref list);

                foreach (SphereEntity sphere in _innerSpheres)
                {
                    sphere?.Kill();
                }

                _instance._playersInZone.Clear();

                Destroy(_sphereCollider);
                _roamMarker?.Kill();
            }

            private void OnTriggerEnter(Collider collider)
            {
                if (collider == null)
                    return;

                BasePlayer? player = collider.gameObject.GetComponent<BasePlayer>();
                if (player == null)
                    return;

                _instance._playersInZone.Add(player.userID);

                _instance.RoamUi(player);
                _instance.RoamTimer(player, Duration);
                _instance._playerUiTimers.Add(player.userID,
                    _instance.timer.Every(1f, () => { _instance.RoamTimer(player, Duration); }));
            }

            private void OnTriggerExit(Collider collider)
            {
                if (collider == null)
                    return;

                BasePlayer? player = collider.gameObject.GetComponent<BasePlayer>();
                if (player == null)
                    return;

                _instance._playersInZone.Remove(player.userID);

                Timer uiTimer;
                if (_instance._playerUiTimers.TryGetValue(player.userID, out uiTimer)) uiTimer.Destroy();

                _instance._playerUiTimers.Remove(player.userID);
                CuiHelper.DestroyUi(player, "RoamHeaderText");
                CuiHelper.DestroyUi(player, "TimeRemaining");
            }
        }
        #endregion

        #region UI
        private void RoamUi(BasePlayer player)
        {
            CuiHelper.DestroyUi(player, "RoamHeaderText");
            CuiElementContainer container = new()
            {
                new CuiElement
                {
                    Name = "RoamHeaderText",
                    Parent = "Overlay",
                    Components =
                    {
                        new CuiTextComponent
                        {
                            Text = "<color=#5557AA>RUST</color> ROAMS",
                            Font = "robotocondensed-bold.ttf",
                            FontSize = 28,
                            Align = TextAnchor.MiddleCenter,
                            Color = "1 1 1 1"
                        },
                        new CuiOutlineComponent {Color = "0 0 0 0.5", Distance = "1 -1"},
                        new CuiRectTransformComponent
                        {
                            AnchorMin = "0.5 1",
                            AnchorMax = "0.5 1",
                            OffsetMin = "-183.827 -104.972",
                            OffsetMax = "183.827 -65.97"
                        }
                    }
                }
            };

            CuiHelper.AddUi(player, container);
        }

        private void RoamTimer(BasePlayer player, float time)
        {
            CuiHelper.DestroyUi(player, "TimeRemaining");
            CuiElementContainer container = new();

            TimeSpan duration = TimeSpan.FromSeconds(time);
            container.Add(new CuiElement
            {
                Name = "TimeRemaining",
                Parent = "Overlay",
                Components =
                {
                    new CuiTextComponent
                    {
                        Text = $"Time Remaining: <color=#5557AA>{duration.Minutes:D1} minutes</color>",
                        Font = "robotocondensed-bold.ttf",
                        FontSize = 18,
                        Align = TextAnchor.MiddleCenter,
                        Color = "1 1 1 1"
                    },
                    new CuiOutlineComponent {Color = "0 0 0 0.5", Distance = "1 -1"},
                    new CuiRectTransformComponent
                    {
                        AnchorMin = "0.5 1",
                        AnchorMax = "0.5 1",
                        OffsetMin = "-183.827 -137.937",
                        OffsetMax = "184.243 -99.463"
                    }
                }
            });

            CuiHelper.AddUi(player, container);
        }
        #endregion

        #region Hooks
        private void Loaded()
        {
            _instance = this;

            if (Clans == null) Debug.LogError("Clans is not installed! This plugin will not work without it!");
        }

        private void OnServerInitialized()
        {
            foreach (PrefabData prefab in World.Serialization.world.prefabs)
            {
                if (RoamIslands.Count == 2) break;

                if (prefab.category == "Desert Roams" && !RoamIslands.ContainsKey("Desert Roams"))
                    RoamIslands.Add(prefab.category, prefab.position);
                else if (prefab.category == "Snow Roams" && !RoamIslands.ContainsKey("Snow Roams"))
                    RoamIslands.Add(prefab.category, prefab.position);
            }

            timer.Every(RoamInterval, HandleRoamInterval);
        }

        private object OnEntityTakeDamage(BasePlayer victim, HitInfo info)
        {
            BasePlayer? attacker = info?.InitiatorPlayer;
            if (attacker == null) return null;

            if (!_playersInZone.Contains(victim.userID) || !_playersInZone.Contains(attacker.userID)) return null;

            string? attackerClan = GetClanTag(attacker);
            if (string.IsNullOrEmpty(attackerClan)) return null;

            if (!_clanStats.TryGetValue(attackerClan, out ClanStatistics? attackerClanStats))
            {
                List<string>? members = GetClanMembers(attacker);
                if (members.Contains(victim.UserIDString)) return null;

                attackerClanStats = new ClanStatistics
                {
                    Members = members,
                    MemberStats = new Dictionary<string, IndividualStatistics>
                    {
                        [attacker.UserIDString] = new() {Kills = 0, Deaths = 0}
                    },
                    Kills = 0,
                    Deaths = 0
                };

                _clanStats.Add(attackerClan, attackerClanStats);
            }
            else if (attackerClanStats.Members.Contains(victim.UserIDString))
            {
                return null;
            }

            return null;
        }

        private void OnEntityDeath(BasePlayer? victim, HitInfo? info)
        {
            BasePlayer? attacker = info?.InitiatorPlayer;
            if (attacker == null || !attacker.userID.IsSteamId()) return;

            if (!_playersInZone.Contains(victim.userID) || !_playersInZone.Contains(attacker.userID)) return;

            string attackerClan = GetClanTag(attacker);
            if (!string.IsNullOrEmpty(attackerClan))
                if (_clanStats.TryGetValue(attackerClan, out ClanStatistics? attackerClanStats))
                {
                    if (!attackerClanStats.Members.Contains(victim.UserIDString))
                    {
                        attackerClanStats.Kills += 1;
                        attackerClanStats.MemberStats[attacker.UserIDString].Kills += 1;
                    }
                    else
                    {
                        return;
                    }
                }

            string victimClan = GetClanTag(victim);
            if (!string.IsNullOrEmpty(victimClan))
            {
                if (_clanStats.TryGetValue(victimClan, out ClanStatistics? victimClanStats))
                {
                    victimClanStats.Deaths += 1;
                    victimClanStats.MemberStats[victim.UserIDString].Deaths += 1;
                }
                else
                {
                    List<string>? members = GetClanMembers(victim);

                    _clanStats.Add(victimClan,
                        new ClanStatistics
                        {
                            Members = members,
                            MemberStats = new Dictionary<string, IndividualStatistics>
                            {
                                [victim.UserIDString] = new() {Kills = 0, Deaths = 1}
                            },
                            Kills = 0,
                            Deaths = 1
                        });
                }
            }
        }
        #endregion

    }
}

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