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

FREE ClanTeleport : 1.0.3 1.0.3

Нет прав для скачивания
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using UnityEngine;
using Newtonsoft.Json.Linq;

namespace Oxide.Plugins
{
    [Info("Clan TP", "Nexus Labs", "1.0.3")]
    [Description("Lets clan leaders pull their members to them. Has cooldown, warmup, combat/damage/movement cancels, etc. Compatible with both Oxide and Carbon.")]
    public class ClanTeleport : RustPlugin
    {
        private ConfigData config; // our config stuff

        private class ConfigData
        {
            public float CooldownSeconds = 600f;
            public bool RequireAllOnline = false;
            public float MaxDistance = 150f;
            public bool UseNTeleportation = true;
            public string TeleportPermission = "clanteleport.use";
            public string BypassCooldownPermission = "clanteleport.bypass";
            public bool ShowTeleportEffects = true;
            public bool EnableWarmup = true;
            public float WarmupTime = 8f;
            public bool CancelOnMovement = true;
            public bool CancelOnDamage = true;
            public bool AllowDuringCombat = false;
            public float CombatTime = 45f;
            public int MaxMembers = 25;
            public bool NotifyAllMembers = true;
        }

        [PluginReference] private Plugin Clans, NTeleportation;

        private readonly Dictionary<ulong, DateTime> cooldowns = new();
        private readonly Dictionary<ulong, Timer> warmupTimers = new();
        private readonly Dictionary<ulong, DateTime> lastCombatTime = new();
        private readonly Dictionary<ulong, Vector3> warmupPositions = new();

        #region Oxide Hooks

        protected override void LoadDefaultConfig()
        {
            config = new ConfigData();
            SaveConfig();
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                config = Config.ReadObject<ConfigData>();
                if (config == null) throw new Exception();
            }
            catch
            {
                PrintError("Config corrupted, loading defaults...");
                LoadDefaultConfig();
            }
            SaveConfig();
        }

        protected override void SaveConfig() => Config.WriteObject(config);

        void Init()
        {
            permission.RegisterPermission(config.TeleportPermission, this);
            permission.RegisterPermission(config.BypassCooldownPermission, this);

            AddCovalenceCommand("clantp", "CmdClanTeleport");
            AddCovalenceCommand("clantpcancel", "CmdCancelTeleport");
        }

        void OnServerInitialized()
        {
            if (Clans == null)
            {
                PrintError("Clans plugin missing! Need a compatible Clans plugin (e.g., k1lly0u/Reborn/Chaos). Unloading...");
                Interface.Oxide.UnloadPlugin(Name);
                return;
            }

            if (config.UseNTeleportation && NTeleportation == null)
                PrintWarning("NTeleportation not loaded - falling back to basic teleport.");
        }

        void Unload()
        {
            foreach (var timer in warmupTimers.Values)
                timer?.Destroy();

            warmupTimers.Clear();
            warmupPositions.Clear();
        }

        void OnPlayerDisconnected(BasePlayer player)
        {
            warmupTimers.Remove(player.userID);
            warmupPositions.Remove(player.userID);
        }

        #endregion

        #region Commands

        private void CmdClanTeleport(IPlayer iplayer, string command, string[] args)
        {
            if (!(iplayer.Object is BasePlayer player)) return; // not a player, bail

            if (!permission.UserHasPermission(player.UserIDString, config.TeleportPermission))
            {
                Reply(player, "no_permission");
                return;
            }

            if (!config.AllowDuringCombat && IsInCombat(player))
            {
                Reply(player, "in_combat");
                return;
            }

            string clanTag = GetPlayerClanTag(player);
            if (string.IsNullOrEmpty(clanTag))
            {
                Reply(player, "no_clan");
                return;
            }

            ulong? leaderId = GetClanLeaderId(clanTag);
            if (!leaderId.HasValue || player.userID != leaderId.Value)
            {
                Reply(player, "not_leader");
                return;
            }

            if (!CanUseTeleport(player))
            {
                double remaining = GetCooldownRemaining(player.userID);
                Reply(player, "cooldown", Math.Ceiling(remaining));
                return;
            }

            if (config.EnableWarmup)
                StartWarmup(player, clanTag);
            else
                ExecuteTeleport(player, clanTag);
        }

        private void CmdCancelTeleport(IPlayer iplayer, string command, string[] args)
        {
            if (!(iplayer.Object is BasePlayer player)) return;

            if (warmupTimers.TryGetValue(player.userID, out Timer timer))
            {
                timer.Destroy();
                warmupTimers.Remove(player.userID);
                warmupPositions.Remove(player.userID);
                Reply(player, "cancelled");
            }
            else
            {
                Reply(player, "no_warmup");
            }
        }

        #endregion

        #region Warmup & Teleport Logic

        private void StartWarmup(BasePlayer leader, string clanTag)
        {
            if (warmupTimers.TryGetValue(leader.userID, out Timer existingTimer))
                existingTimer.Destroy(); // kill old timer if any

            warmupPositions[leader.userID] = leader.transform.position;

            Reply(leader, "warmup_start", config.WarmupTime);
            Reply(leader, "warmup_cancel_hint");

            var members = GetClanMembers(clanTag);

            if (config.NotifyAllMembers)
            {
                foreach (var member in members.Where(m => m != leader && m.IsConnected))
                {
                    Reply(member, "notify_member", leader.displayName, config.WarmupTime);
                }
            }

            warmupTimers[leader.userID] = timer.Once(config.WarmupTime, () =>
            {
                warmupTimers.Remove(leader.userID);
                warmupPositions.Remove(leader.userID);

                if (!leader.IsConnected || leader.IsDead() || leader.IsSleeping())
                    return; // leader gone, abort

                ExecuteTeleport(leader, clanTag);
            });
        }

        private void ExecuteTeleport(BasePlayer leader, string clanTag)
        {
            var members = GetClanMembers(clanTag);

            if (config.RequireAllOnline && members.Any(m => !m.IsConnected && m != leader))
            {
                Reply(leader, "require_all_online");
                return;
            }

            if (members.Count > config.MaxMembers)
            {
                Reply(leader, "too_many_members", config.MaxMembers);
                return;
            }

            int teleportedCount = 0;

            foreach (var member in members)
            {
                if (member == null || !member.IsConnected || member == leader || member.IsDead() || member.IsSleeping())
                    continue;

                if (config.MaxDistance > 0 && Vector3.Distance(member.transform.position, leader.transform.position) > config.MaxDistance)
                {
                    Reply(leader, "member_too_far", member.displayName);
                    continue;
                }

                if (!config.AllowDuringCombat && IsInCombat(member))
                {
                    Reply(leader, "member_in_combat", member.displayName);
                    continue;
                }

                TeleportMember(leader, member);
                teleportedCount++;

                if (config.NotifyAllMembers)
                    Reply(member, "teleported_success", leader.displayName);
            }

            ApplyCooldown(leader);
            Reply(leader, "teleport_complete", teleportedCount);
        }

        private void TeleportMember(BasePlayer leader, BasePlayer member)
        {
            // Slight random spread to avoid stacking issues
            Vector3 offset = UnityEngine.Random.insideUnitSphere * 1.5f;
            offset.y = 0;
            Vector3 targetPos = leader.transform.position + leader.transform.forward * 1.5f + offset;

            if (config.UseNTeleportation && NTeleportation != null)
            {
                // Updated to use "Teleport" based on some old code examples, hope it works
                NTeleportation.Call("Teleport", member, targetPos);
            }
            else
            {
                member.Teleport(targetPos);
                member.SendNetworkUpdate(); // make sure client updates
            }

            if (config.ShowTeleportEffects)
            {
                Effect.server.Run("assets/prefabs/tools/teleporter/effects/teleport_beam.prefab", member.transform.position);
                Effect.server.Run("assets/prefabs/tools/teleporter/effects/teleport_beam.prefab", targetPos);
            }
        }

        #endregion

        #region Helpers

        private string GetPlayerClanTag(BasePlayer player)
        {
            // For k1lly0u's Clans, use GetClanOf with string ID
            return Clans?.Call<string>("GetClanOf", player.UserIDString);
        }

        private ulong? GetClanLeaderId(string clanTag)
        {
            // Get the clan object
            object clanObj = Clans?.Call("GetClan", clanTag);
            if (clanObj is JObject jClan)
            {
                string ownerStr = jClan["owner"]?.ToString();
                if (!string.IsNullOrEmpty(ownerStr) && ulong.TryParse(ownerStr, out ulong ownerId))
                    return ownerId;

                // Fallback if it's "leader" in some plugins
                string leaderStr = jClan["leader"]?.ToString();
                if (!string.IsNullOrEmpty(leaderStr) && ulong.TryParse(leaderStr, out ulong leaderId))
                    return leaderId;
            }

            return null;
        }

        private List<BasePlayer> GetClanMembers(string clanTag)
        {
            var members = new List<BasePlayer>();

            // For k1lly0u, get clan and extract members
            object clanObj = Clans?.Call("GetClan", clanTag);
            if (clanObj is JObject jClan)
            {
                var membersArray = jClan["members"] as JArray;
                if (membersArray != null)
                {
                    foreach (var idToken in membersArray)
                    {
                        if (ulong.TryParse(idToken.ToString(), out ulong userId))
                        {
                            var player = BasePlayer.FindAwakeOrSleeping(userId.ToString()); // Use string for Find
                            if (player != null) members.Add(player);
                        }
                    }
                }
            }

            return members;
        }

        private bool CanUseTeleport(BasePlayer player)
        {
            if (permission.UserHasPermission(player.UserIDString, config.BypassCooldownPermission))
                return true;

            if (!cooldowns.TryGetValue(player.userID, out DateTime lastUse))
                return true;

            return (DateTime.UtcNow - lastUse).TotalSeconds >= config.CooldownSeconds;
        }

        private double GetCooldownRemaining(ulong userId)
        {
            if (!cooldowns.TryGetValue(userId, out DateTime lastUse))
                return 0;

            double remaining = config.CooldownSeconds - (DateTime.UtcNow - lastUse).TotalSeconds;
            return Math.Max(0, remaining);
        }

        private void ApplyCooldown(BasePlayer player)
        {
            if (!permission.UserHasPermission(player.UserIDString, config.BypassCooldownPermission))
            {
                cooldowns[player.userID] = DateTime.UtcNow;
            }
        }

        private bool IsInCombat(BasePlayer player)
        {
            if (!lastCombatTime.TryGetValue(player.userID, out DateTime time))
                return false;

            return (DateTime.UtcNow - time).TotalSeconds < config.CombatTime;
        }

        private void Reply(BasePlayer player, string key, params object[] args)
        {
            string message = lang.GetMessage(key, this, player.UserIDString);
            if (args.Length > 0) message = string.Format(message, args);
            player.ChatMessage(message);
        }

        #endregion

        #region Combat / Movement Detection

        void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
        {
            if (entity is BasePlayer player && info?.InitiatorPlayer != null)
            {
                lastCombatTime[player.userID] = DateTime.UtcNow;

                if (config.CancelOnDamage && warmupTimers.ContainsKey(player.userID))
                    CancelWarmup(player, "damage_cancel");
            }
        }

        void OnPlayerAttack(BasePlayer attacker, HitInfo info)
        {
            if (attacker != null && info?.HitEntity is BaseCombatEntity)
            {
                lastCombatTime[attacker.userID] = DateTime.UtcNow;
            }
        }

        void OnPlayerInput(BasePlayer player, InputState input)
        {
            if (!config.CancelOnMovement || !warmupTimers.ContainsKey(player.userID))
                return;

            if (!warmupPositions.TryGetValue(player.userID, out Vector3 startPos))
                return;

            float moveThreshold = 2.5f;  
            bool moved = Vector3.Distance(player.transform.position, startPos) > moveThreshold;
            bool jumpedOrSprinted = input.WasJustPressed(BUTTON.JUMP) || input.WasJustPressed(BUTTON.SPRINT);

            if (moved || jumpedOrSprinted)
            {
                CancelWarmup(player, "movement_cancel");
            }
        }

        private void CancelWarmup(BasePlayer player, string reasonKey)
        {
            if (warmupTimers.TryGetValue(player.userID, out Timer timer))
            {
                timer.Destroy();
                warmupTimers.Remove(player.userID);
                warmupPositions.Remove(player.userID);
                Reply(player, reasonKey);
            }
        }

        #endregion

        #region Lang

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["no_permission"] = "<color=#ff4444>You don't have permission to use this.</color>",
                ["no_clan"] = "<color=#ff4444>You're not in a clan!</color>",
                ["not_leader"] = "<color=#ff4444>Only the clan leader can call the squad.</color>",
                ["in_combat"] = "<color=#ff4444>Can't TP while in combat.</color>",
                ["cooldown"] = "<color=#ff4444>Wait {0} seconds before calling again.</color>",
                ["warmup_start"] = "<color=#ffff44>Clan pull starting in {0} seconds - hold still!</color>",
                ["warmup_cancel_hint"] = "<color=#aaaa44>Use /clantpcancel if you need to abort.</color>",
                ["cancelled"] = "<color=#ffff44>Pull cancelled.</color>",
                ["no_warmup"] = "<color=#ffff44>Nothing to cancel.</color>",
                ["notify_member"] = "<color=#ffff44>Your leader {0} is pulling the clan in {1} seconds!</color>",
                ["require_all_online"] = "<color=#ff4444>Everyone needs to be online for this.</color>",
                ["too_many_members"] = "<color=#ff4444>Too many members (limit {0}).</color>",
                ["member_too_far"] = "<color=#ffff44>{0} is too far away to pull.</color>",
                ["member_in_combat"] = "<color=#ffff44>{0} is in combat.</color>",
                ["teleport_complete"] = "<color=#44ff44>Pulled {0} members to you!</color>",
                ["teleported_success"] = "<color=#44ff44>{0} pulled you in!</color>",
                ["damage_cancel"] = "<color=#ff4444>Pull cancelled - you got hit!</color>",
                ["movement_cancel"] = "<color=#ff4444>Pull cancelled - you moved!</color>"
            }, this);
        }

        #endregion

        #region Console Command(s)

        [ConsoleCommand("clanteleport.resetcooldown")]
        private void CmdResetCooldown(ConsoleSystem.Arg arg)
        {
            if (!arg.IsAdmin) return;

            cooldowns.Clear();
            Puts("All clan TP cooldowns reset by admin."); // log it
            arg.ReplyWith("Cooldowns cleared.");
        }

        #endregion
    }
}

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