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

FREE BetterChat : 3.7.1 3.7.1

Нет прав для скачивания
C#:
using System.Text.RegularExpressions;
using System.Collections.Generic;
using Oxide.Game.Rust.Libraries;
using Oxide.Core.Plugins;
using System.Linq;
using Oxide.Core;
using System;
using System.Text;
using UnityEngine;
using System.Diagnostics;
using Oxide.Core.Libraries.Covalence;
using ConVar;
using Facepunch;
using Facepunch.Math;
using System.Globalization;
using CompanionServer;
using Pool = Facepunch.Pool;
namespace Oxide.Plugins {
    [Info("Better Chat", "Shady", "3.7.1", ResourceId = 1520)]
    // Significant changes, so much so as to effectively make it its own plugin, were made.[Description("Customize chat colors, formatting, prefix and more.")]
    internal class BetterChat : RustPlugin {
        private readonly HashSet<string> _forbiddenTags = new HashSet<string> {
            "</color>", "</size>", "<b>", "</b>", "<i>", "</i>"
        }
        ;
        private readonly Regex _colorRegex = new Regex("(<color=.+?>)", RegexOptions.Compiled);
        private readonly Regex _sizeRegex = new Regex("(<size=.+?>)", RegexOptions.Compiled);
        private readonly Regex _ipPattern = new Regex(@"(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[1-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])){3}", RegexOptions.Compiled);
        private readonly Regex _emojiPattern = new Regex(@":[\w\.]+:", RegexOptions.Compiled);
        //new Regex(@":\w+:", RegexOptions.Compiled);
        private const int DISCORD_SOURCE_ID = -744;
        private const int RED_SOURCE_ID = 1;
        private const int BLUE_SOURCE_ID = 2;
        //originally LaserHydra's plugin, but so extremely modified by me that it was basically rewritten in 80% of places
        private readonly Command commands = Interface.Oxide.GetLibrary<Command>();
        private List<string> muted = new List<string>();
        [PluginReference]
        private readonly Plugin Ignore;
        [PluginReference]
        private readonly Plugin Clans;
        [PluginReference]
        private readonly Plugin ShadowBan;
        [PluginReference]
        private readonly Plugin Compilation;
        private const string RustbergWarning = "<color=green>Did you know?</color> <color=red>Rustberg is NOTORIOUS for FAKING their player count.Don't just take our word for it, ask for video proof on our Discord here:</color> <color=yellow>discord.gg/DUCnZhZ</color>";
        private string RemoveRepeatingCharacters(string str) {
            if (string.IsNullOrEmpty(str)) return str;
            var sb = new StringBuilder();
            for (int i = 0; i < str.Length; i++) {
                var chr = str[i];
                if ((i + 1 < str.Length) && str[i + 1] == chr) continue;
                sb.Append(chr.ToString());
            }
            return sb.ToString();
        }
        private void Loaded() {
            LoadData();
            LoadConfig();
            LoadMessages();
            RegisterPerm("mute");
            RegisterPerm("formatting");
            permission.RegisterPermission("betterchat.noavatar", this);
            foreach (var kvp in Config) {
                string group = kvp.Key;
                if (group == "Mute" || group == "WordFilter" || group == "AntiSpam") continue;
                RegisterPerm(GetConfig(group, group, "Permission"));
                //BroadcastChat($"--> <color=red>Registered permission '{PermissionPrefix}.{GetConfig(group, group, "Permission")}'</color>");
                if (!permission.GroupExists(group)) {
                    permission.CreateGroup(group, GetConfig("[Player]", group, "Title"), GetConfig(1, group, "Rank"));
                    //BroadcastChat($"--> <color=red>Created group '{group}' as it did not exist</color>");
                }
                permission.GrantGroupPermission(group, $"{PermissionPrefix}.{GetConfig(group, group, "Permission")}", this);
                //BroadcastChat($"--> <color=red>Granted permission '{PermissionPrefix}.{GetConfig(group, group, "Permission")}' to group '{group}'</color>");
            }
            if (GetConfig(true, "Mute", "Enabled")) {
                commands.AddChatCommand("mute", this, "cmdMute");
                commands.AddChatCommand("unmute", this, "cmdUnmute");
            }
            //    ignoreAPI = plugins.Find("Ignore");
            if (!plugins.Exists("Ignore")) {
                PrintWarning("Failed to load IgnoreAPI");
            }
            // if (ignoreAPI != null)
            // {
            //   Puts("Loaded Ignore API successfully");
            // }
            //   else PrintWarning("failed to load ignore api");
            timer.Every(120f, () => {
                ipSpamCount?.Clear();
            }
            );
        }
        private void LoadData() {
            muted = Interface.Oxide.DataFileSystem.ReadObject<List<string>>("BetterChat_Muted");
        }
        private void SaveData() {
            Interface.Oxide.DataFileSystem.WriteObject("BetterChat_Muted", muted);
        }
        private void LoadMessages() {
            lang.RegisterMessages(new Dictionary<string, string> {
                {
                    "No Permission", "You don't have permission to use this command."
                }
                , {
                    "Muted Broadcast", "{player} was muted!"
                }
                , {
                    "Unmuted Broadcast", "{player} was unmuted!"
                }
                , {
                    "Muted", "You are muted."
                }
                ,
            }
            , this);
        }
        private void LoadConfig() {
            SetConfig("WordFilter", "Enabled", false);
            SetConfig("WordFilter", "FilterList", new List<string> {
                "fuck", "bitch", "faggot"
            }
            );
            SetConfig("WordFilter", "UseCustomReplacement", false);
            SetConfig("WordFilter", "CustomReplacement", "Unicorn");
            SetConfig("AntiSpam", "Enabled", false);
            SetConfig("AntiSpam", "MaxCharacters", 85);
            SetConfig("Mute", "Enabled", true);
            SetConfig("player", new Dictionary<string, object> {
                {
                    "Formatting", "{Title} {Name}<color={TextColor}>:</color> {Message}"
                }
                , {
                    "ConsoleFormatting", "{Title} {Name}: {Message}"
                }
                , {
                    "Permission", "player"
                }
                , {
                    "Title", "[Player]"
                }
                , {
                    "TitleColor", "#C4FF00"
                }
                , {
                    "NameColor", "#DCFF66"
                }
                , {
                    "TextColor", "white"
                }
                , {
                    "Rank", 1
                }
            }
            );
            SetConfig("moderator", new Dictionary<string, object> {
                {
                    "Formatting", "{Title} {Name}<color={TextColor}>:</color> {Message}"
                }
                , {
                    "ConsoleFormatting", "{Title} {Name}: {Message}"
                }
                , {
                    "Permission", "moderator"
                }
                , {
                    "Title", "[Mod]"
                }
                , {
                    "TitleColor", "yellow"
                }
                , {
                    "NameColor", "#DCFF66"
                }
                , {
                    "TextColor", "white"
                }
                , {
                    "Rank", 2
                }
            }
            );
            SetConfig("admin", new Dictionary<string, object> {
                {
                    "Formatting", "{Title} {Name}<color={TextColor}>:</color> {Message}"
                }
                , {
                    "ConsoleFormatting", "{Title} {Name}: {Message}"
                }
                , {
                    "Permission", "admin"
                }
                , {
                    "Title", "[Admin]"
                }
                , {
                    "TitleColor", "red"
                }
                , {
                    "NameColor", "#DCFF66"
                }
                , {
                    "TextColor", "white"
                }
                , {
                    "Rank", 3
                }
            }
            );
            SaveConfig();
        }
        protected override void LoadDefaultConfig() {
            PrintWarning("Generating new config file...");
        }
        ////////////////////////////////////////
        ///  BetterChat API
        ////////////////////////////////////////
        private Dictionary<string, object> GetPlayerFormatting(string UserIDString) {
            string uid = UserIDString;
            Dictionary<string, object> playerData = new Dictionary<string, object>();
            playerData["GroupRank"] = 0;
            playerData["Formatting"] = GetConfig("{Title} {Name}<color={TextColor}>:</color> {Message}", "player", "Formatting");
            playerData["ConsoleFormatting"] = GetConfig("{Title} {Name}: {Message}", "player", "ConsoleFormatting");
            playerData["GroupRank"] = GetConfig(1, "player", "Rank");
            playerData["TitleColor"] = GetConfig("#C4FF00", "player", "TitleColor");
            playerData["NameColor"] = GetConfig("#DCFF66", "player", "NameColor");
            playerData["TextColor"] = GetConfig("white", "player", "TextColor");
            Dictionary<string, string> titles = new Dictionary<string, string>();
            titles.Add(GetConfig("[Player]", "player", "Title"), GetConfig("#C4FF00", "player", "TitleColor"));
            foreach (var group in Config) {
                //BroadcastChat($"--> <color=red>Current group '{group.Key}'</color>");
                string groupName = group.Key;
                if (groupName == "Mute" || groupName == "WordFilter" || groupName == "AntiSpam") continue;
                if (HasPerm(UserIDString, GetConfig(groupName, groupName, "Permission"))) {
                    //BroadcastChat($"--> <color=red>Has permission for group '{group.Key}'</color>");
                    if (Convert.ToInt32(Config[groupName, "Rank"].ToString()) > Convert.ToInt32(playerData["GroupRank"].ToString()) || groupName == "vip") {
                        playerData["Formatting"] = GetConfig("{Title} {Name}<color={TextColor}>:</color> {Message}", groupName, "Formatting");
                        playerData["ConsoleFormatting"] = GetConfig("{Title} {Name}: {Message}", groupName, "ConsoleFormatting");
                        playerData["GroupRank"] = GetConfig(1, groupName, "Rank");
                        playerData["TitleColor"] = GetConfig("#C4FF00", groupName, "TitleColor");
                        playerData["NameColor"] = GetConfig("#DCFF66", groupName, "NameColor");
                        playerData["TextColor"] = GetConfig("white", groupName, "TextColor");
                    }
                    string outTitle;
                    if (!titles.TryGetValue(GetConfig("[Player]", groupName, "Title"), out outTitle)) titles[GetConfig("[Player]", groupName, "Title")] = GetConfig("#C4FF00", groupName, "TitleColor");
                }
            }
            if (titles.Count > 1 && titles.ContainsKey(GetConfig("[Player]", "player", "Title"))) titles.Remove(GetConfig("[Player]", "player", "Title"));
            playerData["Titles"] = titles;
            return playerData;
        }
        private string GetPermissionByTitle(string titleName) {
            if (string.IsNullOrEmpty(titleName)) return string.Empty;
            Dictionary<string, object> goodDict = null;
            foreach (var kvp in Config) {
                if (kvp.Value is Dictionary<string, object>) {
                    var valDict = kvp.Value as Dictionary<string, object>;
                    object getVal = null;
                    foreach (var kvp2 in valDict) {
                        if (kvp2.Key == "Title") {
                            getVal = kvp2.Value;
                            break;
                        }
                    }
                    // var getVal = valDict?.Where(p => p.Key == "Title")?.FirstOrDefault().Value;
                    if (getVal == null) continue;
                    if (getVal.ToString() == titleName) {
                        goodDict = valDict;
                        break;
                    }
                    //         else PrintWarning("Not equal: " + getVal.ToString() + ", " + titleName);
                    //    PrintWarning("getVal: " + getVal?.GetType() + ", " + getVal);
                }
            }
            if (goodDict == null || goodDict.Count < 1) {
                PrintWarning("Good dict is not good: " + titleName);
                return null;
            }
            object perm;
            if (goodDict.TryGetValue("Permission", out perm)) return perm.ToString();
            else {
                PrintWarning("No get perm from gooddict, " + titleName);
                return string.Empty;
            }
        }
        private List<string> GetGroups() {
            List<string> groups = new List<string>();
            foreach (var group in Config) {
                groups.Add(group.Key);
            }
            return groups;
        }
        private Dictionary<string, object> GetGroup(string name) {
            Dictionary<string, object> group = new Dictionary<string, object>();
            GetConfig(new Dictionary<string, object> {
                {
                    "Formatting", "{Title} {Name}<color={TextColor}>:</color> {Message}"
                }
                , {
                    "ConsoleFormatting", "{Title} {Name}: {Message}"
                }
                , {
                    "Permission", "player"
                }
                , {
                    "Title", "[Player]"
                }
                , {
                    "TitleColor", "#C4FF00"
                }
                , {
                    "NameColor", "#C4FF00"
                }
                , {
                    "TextColor", "white"
                }
                , {
                    "Rank", 1
                }
            }
            , name);
            return group;
        }
        private List<string> GetPlayersGroups(BasePlayer player) {
            List<string> groups = new List<string>();
            foreach (var group in Config) {
                if (HasPerm(player.UserIDString, GetConfig("player", group.Key, "Permission"))) groups.Add(group.Key);
            }
            return null;
        }
        private bool GroupExists(string name) {
            if (Config[name] == null) return false;
            else return true;
        }
        private bool AddPlayerToGroup(BasePlayer player, string name) {
            if (GetConfig("player", name, "Permission") != null && !HasPerm(player.UserIDString, GetConfig("player", name, "Permission"))) {
                permission.GrantUserPermission(player.UserIDString, GetConfig("player", name, "Permission"), this);
                return true;
            }
            return false;
        }
        private bool RemovePlayerFromGroup(BasePlayer player, string name) {
            if (GetConfig("player", name, "Permission") != null && HasPerm(player.UserIDString, GetConfig("player", name, "Permission"))) {
                permission.RevokeUserPermission(player.UserIDString, GetConfig("player", name, "Permission"));
                return true;
            }
            return false;
        }
        private bool PlayerInGroup(BasePlayer player, string name) {
            if (GetPlayersGroups(player).Contains(name)) return true;
            return false;
        }
        private bool AddGroup(string name, Dictionary<string, object> group) {
            try {
                if (!group.ContainsKey("ConsoleFormatting")) group["ConsoleFormatting"] = "{Title} {Name}: {Message}";
                if (!group.ContainsKey("Formatting")) group["Formatting"] = "{Title} {Name}<color={TextColor}>:</color> {Message}";
                if (!group.ContainsKey("NameColor")) group["NameColor"] = "#DCFF66";
                if (!group.ContainsKey("Permission")) group["Permission"] = "color_none";
                if (!group.ContainsKey("Rank")) group["Rank"] = 1;
                if (!group.ContainsKey("TextColor")) group["TextColor"] = "white";
                if (!group.ContainsKey("Title")) group["Title"] = "[None]";
                if (!group.ContainsKey("TitleColor")) group["TitleColor"] = "#C4FF00";
                if (Config[name] == null) Config[name] = group;
                else return false;
                SaveConfig();
                return true;
            }
            catch (Exception ex) {
                PrintError(ex.ToString());
            }
            return false;
        }
        ////////////////////////////////////////
        ///  Chat Related
        ////////////////////////////////////////
        private string GetFilteredMesssage(string msg) {
            if (string.IsNullOrEmpty(msg)) return msg;
            var wordList = Config["WorldFilter", "FilterList"] as List<object>;
            var newmsgSB = new StringBuilder(msg);
            for (int i = 0; i < wordList.Count; i++) {
                var word = wordList[i];
                MatchCollection matches = new Regex($@"((?:\S+)?{word}(?:\S+)?)").Matches(msg);
                for (int j = 0; j < matches.Count; j++) {
                    var match = matches[j];
                    if (match.Success) {
                        string found = match.Groups[1].ToString();
                        var replacedSB = new StringBuilder();
                        //     string replaced = "";
                        if (GetConfig(false, "WordFilter", "UseCustomReplacement")) newmsgSB.Replace(found, GetConfig("Unicorn", "WordFilter", "CustomReplacement"));
                        else {
                            for (int k = 0; k < found.Length; k++) replacedSB.Append("*");
                            newmsgSB.Replace(found, replacedSB.ToString());
                        }
                    }
                    else break;
                }
            }
            return newmsgSB.ToString();
        }
        private string RemoveTags(string phrase) {
            if (string.IsNullOrEmpty(phrase)) return phrase;
            //	Replace Color Tags
            phrase = _colorRegex.Replace(phrase, string.Empty);
            //	Replace Size Tags
            phrase = _sizeRegex.Replace(phrase, string.Empty);
            var phraseSB = Pool.Get<StringBuilder>();
            try {
                phraseSB.Clear().Append(phrase);
                foreach (var tag in _forbiddenTags) phraseSB.Replace(tag, string.Empty);
                return phraseSB.ToString();
            }
            finally {
                Pool.Free(ref phraseSB);
            }
        }
        private void MutePlayer(BasePlayer player) {
            if (!muted.Contains(player.UserIDString)) muted.Add(player.UserIDString);
            SaveData();
        }
        private void UnmutePlayer(BasePlayer player) {
            if (muted.Contains(player.UserIDString)) muted.Remove(player.UserIDString);
            SaveData();
        }
        private bool IsMuted(BasePlayer player) {
            if (muted.Contains(player.UserIDString) && GetConfig(true, "Mute", "Enabled")) return true;
            var ChatMute = plugins.Find("chatmute");
            if (ChatMute != null) {
                bool isMuted = (bool)ChatMute.Call("IsMuted", player);
                if (isMuted) return true;
            }
            if (player.HasPlayerFlag(BasePlayer.PlayerFlags.ChatMute)) return true;
            return false;
        }
        private bool HasIP(string value) {
            return _ipPattern.IsMatch(value);
        }
        //change to check matches
        [ChatCommand("colors")]
        private void ColorList(BasePlayer player) {
            List<string> colorList = new List<string> {
                "aqua", "black", "blue", "brown", "darkblue", "green", "grey", "lightblue", "lime", "magenta", "maroon", "navy", "olive", "orange", "purple", "red", "silver", "teal", "white", "yellow"
            }
            ;
            colorList = (from color in colorList select $"<color={color}>{color.ToUpper()}</color>").ToList();
            SendChatMessage(player, "<b><size=20>Available colors:</size></b><size=15>\n " + ListToString(colorList, 0, ", ") + "</size>");
        }
        [ChatCommand("bchooktest")]
        private void BCHookTest(BasePlayer player) {
            Interface.Oxide.CallHook("OnBetterChat", player.UserIDString, "this is a test");
            Interface.Oxide.CallHook("OnBetterChatClean", player.UserIDString, "this is a clean test");
        }
        [ChatCommand("coltest")]
        private void cmdPoss(BasePlayer player, string command, string[] args) {
            if (!player.IsAdmin) return;
            if (args.Length < 2) {
                return;
            }
            var findPlayer = FindPlayerByPartialName(args[0]);
            if (findPlayer == null) return;
            var getPerm = GetPermissionByTitle(args[1]);
            PrintWarning(getPerm);
        }
        //public string ValidCharacters = @"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-=[]{}\|\',./`*!@#$%^&*()_+<>? "; //extra space at end is to allow space as a valid character
        public const string VALID_CHARACTERS = @"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-=[]{}\|\'\"",./`*!@#$%^&*()_+<>?~;: ";
        //extra space at end is to allow space as a valid character
        public string[] GetValidCharactersString() {
            var length = VALID_CHARACTERS.Length;
            var array = new string[length];
            for (int i = 0; i < length; i++) array[i] = VALID_CHARACTERS[i].ToString();
            return array;
        }
        public char[] GetValidCharacters() {
            return VALID_CHARACTERS.ToCharArray();
        }
        private int Fitness(string individual, string target) {
            var count = 0;
            var range = Enumerable.Range(0, Math.Min(individual.Length, target.Length));
            foreach (var i in range) {
                if (individual[i] == target[i]) count++;
            }
            return count;
            //return Enumerable.Range(0, Math.Min(individual.Length, target.Length)).Count(i => individual[i] == target[i]);
        }
        private int ExactMatch(string comp1, string comp2, StringComparison options = StringComparison.CurrentCulture) {
            if (string.IsNullOrEmpty(comp1) || string.IsNullOrEmpty(comp2)) return 0;
            var val = 0;
            if (comp1.Length > 0 && comp2.Length > 0) {
                for (int i = 0; i < comp1.Length; i++) {
                    if ((comp2.Length - 1) >= i) {
                        if (comp2[i].ToString().Equals(comp1[i].ToString(), options)) val++;
                    }
                }
            }
            return val;
        }
        private string CleanPlayerName(string str) {
            if (string.IsNullOrEmpty(str)) throw new ArgumentNullException(nameof(str));
            var strSB = new StringBuilder();
            var valid = GetValidCharactersString();
            for (int i = 0; i < str.Length; i++) {
                var chrStr = str[i].ToString();
                var skip = true;
                for (int j = 0; j < valid.Length; j++) {
                    var v = valid[j];
                    if (v.Equals(chrStr, StringComparison.OrdinalIgnoreCase)) {
                        skip = false;
                        break;
                    }
                }
                if (!skip) strSB.Append(chrStr);
            }
            return strSB.ToString().TrimStart().TrimEnd();
        }
        /// <summary>
        /// Finds a player using their entire or partial name.Entire names take top priority & will be returned over a partial match./// </summary>
        /// <exception cref="ArgumentNullException"></exception>
        /// <param name="name"></param>
        /// <param name="sleepers"></param>
        /// <returns></returns>
        private BasePlayer FindPlayerByPartialName(string name, bool sleepers = false) {
            if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));
            BasePlayer player = null;
            var matches = Pool.GetList<BasePlayer>();
            try {
                for (int i = 0; i < BasePlayer.activePlayerList.Count; i++) {
                    var p = BasePlayer.activePlayerList[i];
                    if (p == null) continue;
                    var pName = p?.displayName ?? string.Empty;
                    var cleanName = CleanPlayerName(pName);
                    if (!string.IsNullOrEmpty(cleanName)) pName = cleanName;
                    if (string.Equals(pName, name, StringComparison.OrdinalIgnoreCase)) {
                        if (player != null) return null;
                        player = p;
                        return player;
                    }
                }
                if (sleepers) {
                    for (int i = 0; i < BasePlayer.sleepingPlayerList.Count; i++) {
                        var p = BasePlayer.sleepingPlayerList[i];
                        if (p == null) continue;
                        var pName = p?.displayName ?? string.Empty;
                        var cleanName = CleanPlayerName(pName);
                        if (!string.IsNullOrEmpty(cleanName)) pName = cleanName;
                        if (string.Equals(pName, name, StringComparison.OrdinalIgnoreCase)) {
                            if (player != null) return null;
                            player = p;
                            return player;
                        }
                    }
                }
                for (int i = 0; i < BasePlayer.activePlayerList.Count; i++) {
                    var p = BasePlayer.activePlayerList[i];
                    if (p == null) continue;
                    var pName = p?.displayName ?? string.Empty;
                    var cleanName = CleanPlayerName(pName);
                    if (!string.IsNullOrEmpty(cleanName)) pName = cleanName;
                    if (pName.IndexOf(name, StringComparison.OrdinalIgnoreCase) >= 0) {
                        matches.Add(p);
                    }
                }
                if (sleepers) {
                    for (int i = 0; i < BasePlayer.sleepingPlayerList.Count; i++) {
                        var p = BasePlayer.sleepingPlayerList[i];
                        if (p == null) continue;
                        var pName = p?.displayName ?? string.Empty;
                        var cleanName = CleanPlayerName(pName);
                        if (!string.IsNullOrEmpty(cleanName)) pName = cleanName;
                        if (pName.IndexOf(name, StringComparison.OrdinalIgnoreCase) >= 0) {
                            matches.Add(p);
                        }
                    }
                }
                var topMatch = matches?.OrderByDescending(p => ExactMatch(CleanPlayerName(p?.displayName) ?? p?.displayName, name, StringComparison.OrdinalIgnoreCase)) ?? null;
                if (topMatch != null && topMatch.Any()) {
                    var exactMatches = matches?.Select(p => ExactMatch(CleanPlayerName(p?.displayName) ?? p?.displayName, name, StringComparison.OrdinalIgnoreCase))?.OrderByDescending(p => p) ?? null;
                    if (exactMatches.All(p => p == 0)) {
                        topMatch = matches?.OrderByDescending(p => Fitness(CleanPlayerName(p?.displayName) ?? p?.displayName, name)) ?? null;
                    }
                }
                player = topMatch?.FirstOrDefault() ?? null;
            }
            catch (Exception ex) {
                PrintError(ex.ToString());
            }
            Pool.FreeList(ref matches);
            return player;
        }
        /// <summary>
        /// Finds a player using their entire or partial name.Entire names take top priority & will be returned over a partial match./// </summary>
        /// <exception cref="ArgumentNullException"></exception>
        /// <param name="name"></param>
        /// <param name="sleepers"></param>
        /// <returns></returns>
        private BasePlayer FindPlayerByPartialName(string name, bool sleepers = false, params BasePlayer[] ignore) {
            if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));
            BasePlayer player = null;
            var matches = Pool.GetList<BasePlayer>();
            try {
                for (int i = 0; i < BasePlayer.activePlayerList.Count; i++) {
                    var p = BasePlayer.activePlayerList[i];
                    if (p == null || (ignore != null && ignore.Length > 0 && ignore.Contains(p))) continue;
                    var pName = p?.displayName ?? string.Empty;
                    var cleanName = CleanPlayerName(pName);
                    if (!string.IsNullOrEmpty(cleanName)) pName = cleanName;
                    if (string.Equals(pName, name, StringComparison.OrdinalIgnoreCase)) {
                        if (player != null) return null;
                        player = p;
                        return player;
                    }
                }
                if (sleepers) {
                    for (int i = 0; i < BasePlayer.sleepingPlayerList.Count; i++) {
                        var p = BasePlayer.sleepingPlayerList[i];
                        if (p == null || (ignore != null && ignore.Length > 0 && ignore.Contains(p))) continue;
                        var pName = p?.displayName ?? string.Empty;
                        var cleanName = CleanPlayerName(pName);
                        if (!string.IsNullOrEmpty(cleanName)) pName = cleanName;
                        if (string.Equals(pName, name, StringComparison.OrdinalIgnoreCase)) {
                            if (player != null) return null;
                            player = p;
                            return player;
                        }
                    }
                }
                for (int i = 0; i < BasePlayer.activePlayerList.Count; i++) {
                    var p = BasePlayer.activePlayerList[i];
                    if (p == null || ignore.Contains(p)) continue;
                    var pName = p?.displayName ?? string.Empty;
                    var cleanName = CleanPlayerName(pName);
                    if (!string.IsNullOrEmpty(cleanName)) pName = cleanName;
                    if (pName.IndexOf(name, StringComparison.OrdinalIgnoreCase) >= 0) {
                        matches.Add(p);
                    }
                }
                if (sleepers) {
                    for (int i = 0; i < BasePlayer.sleepingPlayerList.Count; i++) {
                        var p = BasePlayer.sleepingPlayerList[i];
                        if (p == null || ignore.Contains(p)) continue;
                        var pName = p?.displayName ?? string.Empty;
                        var cleanName = CleanPlayerName(pName);
                        if (!string.IsNullOrEmpty(cleanName)) pName = cleanName;
                        if (pName.IndexOf(name, StringComparison.OrdinalIgnoreCase) >= 0) {
                            matches.Add(p);
                        }
                    }
                }
                var topMatch = matches?.OrderByDescending(p => ExactMatch(CleanPlayerName(p?.displayName) ?? p?.displayName, name)) ?? null;
                if (topMatch != null && topMatch.Any()) {
                    var exactMatches = matches?.Select(p => ExactMatch(CleanPlayerName(p?.displayName) ?? p?.displayName, name))?.OrderByDescending(p => p) ?? null;
                    if (exactMatches.All(p => p == 0)) {
                        topMatch = matches?.OrderByDescending(p => Fitness(CleanPlayerName(p?.displayName) ?? p?.displayName, name)) ?? null;
                    }
                }
                player = topMatch?.FirstOrDefault() ?? null;
            }
            catch (Exception ex) {
                PrintError(ex.ToString());
            }
            Pool.FreeList(ref matches);
            return player;
        }
        private Dictionary<string, string> GetPlayerTitles(string userId) {
            if (string.IsNullOrEmpty(userId)) return null;
            object outObj;
            var data = GetPlayerFormatting(userId);
            if (data == null || data.Count < 1) return null;
            if (data.TryGetValue("Titles", out outObj) && outObj != null) return (outObj as Dictionary<string, string>);
            return null;
        }
        private readonly Dictionary<string, float> lastMessage = new Dictionary<string, float>();
        private readonly Dictionary<string, int> ipSpamCount = new Dictionary<string, int>();
        private static string ReplaceCaseInsensitive(string input, string search, string replacement) {
            string result = Regex.Replace(input, Regex.Escape(search), replacement.Replace("$", "$$"), RegexOptions.IgnoreCase );
            return result;
        }
        private void SendReply(IPlayer player, string msg, bool keepTagsConsole = false) {
            if (player == null) return;
            msg = !player.IsServer ? msg : (keepTagsConsole) ? msg : RemoveTags(msg);
            if (player.IsServer) ConsoleSystem.CurrentArgs.ReplyWith(msg);
            else player.Reply(msg);
        }
        private void SendChatID(string userId, string message, bool callFinalHook = true, int source = 0) {
            var ply = covalence.Players?.FindPlayerById(userId) ?? null;
            if (ply != null) SendChat(ply, message, callFinalHook);
        }
        private float GetMessageCooldownTime(IPlayer player) {
            if (player == null) return -1f;
            if (player.IsServer || player.IsAdmin) return 0f;
            var val = 1.2f;
            int spamCount;
            if (repeatedSpamCount.TryGetValue(player.Id, out spamCount)) {
                val += (spamCount * 0.725f);
            }
            return val;
        }
        private readonly Dictionary<string, int> repeatedSpamCount = new Dictionary<string, int>();
        private readonly Dictionary<string, string> lastMessageContent = new Dictionary<string, string>();
        private bool HasAdvertisingOrSpam(string message) {
            if (string.IsNullOrEmpty(message)) return false;
            if (HasIP(message) && !message.Equals(covalence.Server.Address.ToString(), StringComparison.OrdinalIgnoreCase)) {
                PrintWarning("message detected as having IP that isn't ours: " + message);
                return true;
            }
            var spaceSplit = message.Split(' ');
            for (int i = 0; i < spaceSplit.Length; i++) {
                var split = spaceSplit[i];
                if (!HasIP(split) || split.Equals(covalence.Server.Address.ToString(), StringComparison.OrdinalIgnoreCase)) continue;
                PrintWarning("message detected as having IP that isn't ours (2): " + message);
                return true;
            }
            var lowerMsg = message.ToLower();
            var noSpaceNoRepeat = RemoveRepeatingCharacters(lowerMsg.Replace(" ", string.Empty).Replace(".", string.Empty).Replace("-", string.Empty));
            var noSpace = lowerMsg.Replace(" ", string.Empty);
            if (!noSpaceNoRepeat.Contains("kngsgaming") && !noSpaceNoRepeat.Contains("rust.kn") && !noSpaceNoRepeat.Contains("prism")) {
                if ((noSpaceNoRepeat.Contains("connect") && noSpaceNoRepeat.Contains(":280")) || noSpaceNoRepeat.Contains("28015") || lowerMsg.Contains("client.connect") || noSpaceNoRepeat.Contains("rusticaland") || noSpaceNoRepeat.Contains("rustica") || noSpaceNoRepeat.Contains("rustland") || lowerMsg.Contains("rustberg") || lowerMsg.Contains("rustburg") || lowerMsg.Contains("rusticaland") || lowerMsg.Contains("rusticland") || noSpace.Contains("28015") || noSpace.Contains("client.connect") || noSpace.Contains("rusticaland") || noSpaceNoRepeat.Contains("rustica") || noSpaceNoRepeat.Contains("rustland") || noSpaceNoRepeat.Contains("rustlands") || noSpaceNoRepeat.Contains("rusticland") || noSpaceNoRepeat.Contains("virginrust")) {
                    return true;
                }
            }
            return false;
        }
        private readonly StringBuilder _stringBuilder = new StringBuilder();
        private void SendChatByNameAndId(string userId, string displayName, string message, bool callFinalHook = true, int source = 0) {
            if (string.IsNullOrWhiteSpace(userId)) throw new ArgumentNullException(nameof(userId));
            if (string.IsNullOrWhiteSpace(message)) return;
            //  if (source != 0)
            //        PrintWarning(nameof(SendChatByNameAndId) + " : " + userId + " : " + message + " : " + callFinalHook + " " + source);
            var watch = Pool.Get<Stopwatch>();
            try {
                watch.Restart();
                //we really have to be careful with these pooled watches - i keep writing them without restarting them after grabbing pooled
                //player is often going to be null, because most players will have only ever connected to ONE server, this method is used by both in cross chat
                var player = covalence?.Players?.FindPlayerById(userId);
                if (string.IsNullOrWhiteSpace(displayName)) {
                    displayName = player?.Name ?? userId;
                    if (string.IsNullOrWhiteSpace(displayName)) PrintError("covalence name is null after initial displayName was null!!!!, userId: " + userId);
                }
                //commenting out as i think the SB below handles this fine
                //message = message.TrimStart(null).TrimEnd(null);
                _stringBuilder.Clear();
                var validChr = GetValidCharacters();
                for (int i = 0; i < message.Length; i++) {
                    var chr = message[i];
                    if (char.IsLetterOrDigit(chr) || validChr.Contains(char.ToUpperInvariant(chr))) _stringBuilder.Append(chr);
                }
                if (_stringBuilder.Length < 1) return;
                //  if (source != 0)
                //    PrintWarning("stringbuilder length after message length check: " + _stringBuilder.Length + " vs message length: " + message.Length);
                message = _stringBuilder.ToString();
                //    if (source != 0)
                //    PrintWarning("new message: " + message);
                _stringBuilder.Clear();
                var isConnected = player?.IsConnected ?? false;
                //handle &, ! and ? as if it were / (command)
                if (isConnected && message.Length > 1 && message[1] != ' ' && (message.StartsWith("&", StringComparison.OrdinalIgnoreCase) || message.StartsWith("?", StringComparison.OrdinalIgnoreCase) || message.StartsWith("!", StringComparison.OrdinalIgnoreCase)) && message[1] != message[0]) {
                    var newSB = _stringBuilder.Clear().Append("/");
                    var first = true;
                    for (int i = 0; i < message.Length; i++) {
                        var c = message[i];
                        if (first) first = false;
                        else newSB.Append(c);
                    }
                    if (newSB.Length < 1) PrintError("newSB length <1?!");
                    var pObj = player?.Object as BasePlayer;
                    if (pObj != null) Interface.CallHook("IOnPlayerCommand", pObj, newSB.ToString());
                    return;
                }
                float lastTime;
                if (!lastMessage.TryGetValue(userId, out lastTime)) lastTime = 0f;
                var msgTimeDiff = lastTime > 0 ? UnityEngine.Time.realtimeSinceStartup - lastTime : -1;
                string lastMsgTxt;
                var spamCount = 0;
                if (lastTime > 0 && msgTimeDiff < 25 && lastMessageContent.TryGetValue(userId, out lastMsgTxt) && message.Equals(lastMsgTxt, StringComparison.OrdinalIgnoreCase)) {
                    if (!repeatedSpamCount.TryGetValue(userId, out spamCount)) repeatedSpamCount[userId] = 1;
                    else repeatedSpamCount[userId] += 1;
                }
                if (spamCount > 2 && message.Contains("server", CompareOptions.OrdinalIgnoreCase)) {
                    covalence.Server.Command("ban \"" + userId + "\" \"Advertising (automatic)\"");
                    return;
                }
                if (player != null && lastTime > 0 && msgTimeDiff < GetMessageCooldownTime(player)) {
                    if (isConnected) SendReply(player, "You are chatting too fast!");
                    return;
                }
                var lowerMsg = message.ToLower(CultureInfo.CurrentCulture);
                var pName = RemoveTags(displayName);
                var clanName = Clans?.Call<string>("GetClanOf", userId) ?? string.Empty;
                if (!string.IsNullOrEmpty(clanName)) pName = _stringBuilder.Clear().Append("[").Append(clanName).Append("] ").Append(pName).ToString();
                var capsCount = 0;
                if (message.Length >= 10) {
                    for (int i = 0; i < message.Length; i++) {
                        var chr = message[i];
                        if (!char.IsNumber(chr) && char.IsUpper(chr)) capsCount++;
                    }
                }
                if (capsCount > 0 && capsCount > (message.Length * 0.67)) message = lowerMsg;
                message = RemoveTags(message);
                //	Getting Data
                var playerData = GetPlayerFormatting(userId);
                if (playerData == null || playerData.Count < 1) {
                    PrintError("Bad playerData!! player: " + userId);
                    return;
                }
                var titles = playerData["Titles"] as Dictionary<string, string>;
                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                ///		Chat Output
                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                playerData["FormattedOutput"] = playerData["Formatting"];
                var bestGroup = Compilation?.Call<string>("GetBestGroup", userId) ?? string.Empty;
                var getTag = Compilation?.Call<string>("GetTagColor", userId, bestGroup) ?? string.Empty;
                var titleColor = !string.IsNullOrEmpty(getTag) ? getTag : (playerData["TitleColor"]).ToString();
                var nameColor = !string.IsNullOrEmpty(getTag) ? getTag : (playerData["NameColor"]).ToString();
                var formatNameSb = _stringBuilder.Clear().Append("<color=").Append(nameColor).Append(">").Append(pName).Append("</color>");
                if (source != 0) {
                    var tag = source switch {
                        DISCORD_SOURCE_ID => "<color=#5662F6>via /Discord</color></size> ]</size>", RED_SOURCE_ID => "<color=#cc0000><i>RED</i></color></size> ]</size>", BLUE_SOURCE_ID => "<color=#33ccff><i>BLUE</i></color></size> ]</size>", _ => string.Empty,
                    }
                    ;
                    if (!string.IsNullOrWhiteSpace(tag)) formatNameSb.Append(" <size=11>[ <size=10>").Append(tag);
                }
                var formattedName = formatNameSb.ToString();
                var textColor = isConnected ? playerData["TextColor"].ToString() : "#b3b3b3";
                //grey for Discord, cross-chat messages
                var playerFormatStr = string.Empty;
                var playerFormatSB = Pool.Get<StringBuilder>();
                try {
                    playerFormatSB.Clear().Append(playerData["FormattedOutput"].ToString());
                    playerFormatSB.Replace("{Rank}", playerData["GroupRank"].ToString());
                    playerFormatSB.Replace("{TitleColor}", ((titleColor == getTag) ? string.Empty : titleColor));
                    playerFormatSB.Replace("{NameColor}", playerData["NameColor"].ToString());
                    playerFormatSB.Replace("{TextColor}", textColor);
                    playerFormatSB.Replace("{Name}", formattedName);
                    playerFormatSB.Replace("{ID}", userId);
                    playerFormatSB.Replace("{Message}", _stringBuilder.Clear().Append("<color=").Append(textColor).Append(">").Append(message).Append("</color>").ToString());
                    playerFormatSB.Replace("{Time}", string.Empty);
                    if (message.StartsWith(">") || (message.Length > 1 && message[1] == '>'))  //that isn't a blank space
                    {
                        playerFormatSB.Replace("<color=white>", "<color=#789922>");
                    }
                    if (playerFormatSB.Length < 1) PrintError(nameof(playerFormatSB) + " Length < 1?!?!");
                    playerFormatStr = playerFormatSB.ToString();
                }
                finally {
                    Pool.Free(ref playerFormatSB);
                }
                playerData["FormattedOutput"] = playerFormatStr;
                var chatTitleSB = Pool.Get<StringBuilder>();
                var customColor = string.Empty;
                try {
                    chatTitleSB.Clear();
                    if (isConnected) {
                        foreach (var kvp in titles) {
                            var perm = GetPermissionByTitle(kvp.Key);
                            if (string.IsNullOrEmpty(perm)) continue;
                            var color = kvp.Value;
                            if (!string.IsNullOrEmpty(perm)) {
                                var getColor = Compilation?.Call<string>("GetTagColor", userId, perm);
                                if (!string.IsNullOrEmpty(getColor)) color = getColor;
                            }
                            if (string.IsNullOrEmpty(color)) {
                                PrintWarning("null or empty color: " + kvp.Key);
                                continue;
                            }
                            customColor = color;
                            chatTitleSB.Append("<color=").Append(color).Append(">").Append(kvp.Key).Append("</color>");
                            //break;
                        }
                    }
                    var chatTitle = chatTitleSB.Length < 1 ? string.Empty : chatTitleSB.ToString().TrimEnd(' ');
                    var titleHookVal = Interface.Oxide.CallHook("OnBetterChatGetTitle", userId, chatTitle);
                    if (titleHookVal != null) chatTitle = titleHookVal.ToString();
                    playerData["FormattedOutput"] = playerFormatStr.Replace("{Title}", chatTitle);
                }
                finally {
                    Pool.Free(ref chatTitleSB);
                }
                //////////////////
// ... [Code preview truncated due to length. Full source in attached file] ...

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