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

FREE AutomatedMessages : 2.2.1 2.2.1

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using ConVar;
using Newtonsoft.Json;
using System.Globalization;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Text;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Core;
using Oxide.Game.Rust.Cui;
using UnityEngine;
using UnityEngine.UI;
using Oxide.Core.Libraries;
using Oxide.Plugins.AutomatedMessagesMethods;
/*2.2.1
 * ArgumentException fix
 */
/*2.2.0
 * Added Settings section in admin ui
 * Fix for replies not sent to eligible players if trigger owner was not eligible
 * Fix for broadcast to all replies not always showing same message for all players
 * Added "Use trigger owner chat icon" to actions
 * Added "Custom chat icon (Steam Id)" to actions
 * Added reply specific custom chat icon prefix (customicon:{steamid})
 * Added "Game tip color (true = blue - false = red)" to actions
 * Starts fetching country earlier + webrequest exception handling
 * Get grid using MapHelper.PositionToString
 * Code cleanup
*/
namespace Oxide.Plugins {
    [Info("AutomatedMessages", "beee", "2.2.1")]
    [Description("Automated chat messages based on triggers or repeating interval.")]
    class AutomatedMessages : RustPlugin {
#region Fields
        private static AutomatedMessages _plugin;
        private PluginConfig _config;
        private List<Timer> _timers;
        private const string PREFIX_SHORT = "am";
        private const string PREFIX_LONG = "automatedmessages";
        private const string PERM_ADMIN = $"{PREFIX_LONG}.admin";
        private Dictionary<Regex, PluginConfig.ConfigAction> _autoReplyPatterns;
        [PluginReference]
        private Plugin PlaceholderAPI;
#endregion
#region Load/Unload Hooks
        private void Init() {
            UnsubscribeHooks();
        }
        private void OnServerInitialized() {
            pData = PlayersData.Load();
            ProcessConfig();
            RegisterPermissions();
            InitTimers();
            InitAutoReply();
            SubscribeHooks();
            RegisterConfigCommands();
            SetUnsetCountries();
            RegisterCommand($"{PREFIX_SHORT}.ui.texteditor", nameof(LongInputCMD));
        }
        private void Loaded() {
            _plugin = this;
            _timers = new();
        }
        private void Unload() {
            DestroyTimers();
            SaveData();
            foreach (var player in BasePlayer.activePlayerList) {
                CuiHelper.DestroyUi(player, uimodal);
                CuiHelper.DestroyUi(player, chatpreview);
                CuiHelper.DestroyUi(player, gametippreview);
            }
            _plugin = null;
            _timers = null;
        }
#endregion
#region Functions
        private void RegisterPermissions() {
            permission.RegisterPermission(PERM_ADMIN, this);
        }
        private void InitTimers() {
            DestroyTimers();
            _timers = new();
            int count = 0;
            foreach (var action in _config.Actions.FindAll(s => s.IsEnabled() && s.Type == "Timed")) {
                Lang_Action defaultLangAction = action.CachedLangActions[_config.DefaultLang];
                if (defaultLangAction.Replies == null || defaultLangAction.Replies.Count == 0) continue;
                if (action.Interval <= 0) continue;
                var repeatTimer = _plugin.timer.Repeat(action.Interval * 60, 0, () => ProcessReply(action, defaultLangAction : defaultLangAction));
                _timers.Add(repeatTimer);
                count++;
            }
            PrintWarning($"Started {count} chat timer{(count == 1 ? "" : "s")}.");
        }
        private void InitAutoReply() {
            _autoReplyPatterns = new();
            int count = 0;
            foreach (var message in _config.Actions.FindAll(s => s.IsEnabled() && s.Type == "AutoReply")) {
                Lang_Action defaultLangAction = message.CachedLangActions[_config.DefaultLang];
                if (defaultLangAction.Replies == null || defaultLangAction.Replies.Count == 0) continue;
                if (string.IsNullOrEmpty(message.Target)) continue;
                foreach (var set in message.Target.Split('|')) {
                    string regexPattern = "";
                    foreach (var keyword in set.Split(',')) regexPattern += $@"(?=.*{(keyword.StartsWith("!") ? "^!" : "")}\b{keyword.TrimStart('!').Trim()}\b)";
                    if (regexPattern == "") continue;
                    regexPattern = $"^{regexPattern}.*$";
                    _autoReplyPatterns.Add(new (regexPattern, RegexOptions.IgnoreCase), message);
                    count++;
                }
            }
            PrintWarning($"Cached {count} auto reply keyword pattern{(count == 1 ? "" : "s")}.");
        }
        List<string> _registeredConfigCommands;
        private void RegisterConfigCommands() {
            _registeredConfigCommands = new();
            RegisterCommand(_config.ToggleCommand, nameof(TipsToggleChatCMD));
            _registeredConfigCommands.Add(_config.ToggleCommand);
            int count = 0;
            foreach (var message in _config.Actions.FindAll(s => s.IsEnabled() && s.Type == "ChatCommand")) {
                Lang_Action defaultLangAction = message.CachedLangActions[_config.DefaultLang];
                if (defaultLangAction.Replies == null || defaultLangAction.Replies.Count == 0) continue;
                if (string.IsNullOrEmpty(message.Target)) continue;
                string command = message.Target.Replace("/", "").Trim().ToLower();
                foreach (string com in command.Split(',').Select(s => s.Trim())) {
                    if (string.IsNullOrEmpty(com)) continue;
                    RegisterCommand(com, nameof(CustomChatCMD));
                    _registeredConfigCommands.Add(com);
                    count++;
                }
            }
            PrintWarning($"Registered {count} chat command{(count == 1 ? "" : "s")}.");
        }
        private void UnregisterCachedCommands() {
            if (_registeredConfigCommands == null) return;
            var library = GetLibrary<Covalence>();
            foreach (var command in _registeredConfigCommands) library.UnregisterCommand(command, this);
            _registeredConfigCommands.Clear();
        }
        private void RegisterCommand(string command, string callback, string perm = null) {
            if (!string.IsNullOrEmpty(command) && !command.Equals("null", StringComparison.OrdinalIgnoreCase)) {
                if (string.IsNullOrEmpty(perm)) AddCovalenceCommand(command, callback);
                else AddCovalenceCommand(command, callback, perm);
            }
        }
        private void SetUnsetCountries() {
            foreach (var player in BasePlayer.activePlayerList) {
                if (!pData.Players.TryGetValue(player.userID, out var pinfo)) pData.Players.Add(player.userID, pinfo = new PlayerInfo {
                    TipsActive = true, isNew = true
                }
                );
                if (string.IsNullOrEmpty(pinfo.Country)) FetchConnectionCountry(player.Connection, pinfo);
            }
        }
        private void DestroyTimers() {
            foreach (var repeatTimer in _timers) repeatTimer?.Destroy();
        }
        private void ProcessReplies(BasePlayer player, List<string> triggersToProcess, string argument = "", bool onlySendToTeam = false) {
            if (!player.userID.IsSteamId()) return;
            //add player if not in data, and in that case set isNew to true to recognize for NewPlayerJoined trigger
            if(!pData.Players.TryGetValue(player.userID, out var pinfo)) pData.Players.Add(player.userID, pinfo = new PlayerInfo() {
                TipsActive = true, isNew = true
            }
            );
            //loop enabled actions with trigger in triggersToProcess
            foreach (var action in _config.Actions.FindAll(s => s.IsEnabled() && triggersToProcess.Contains(s.Type))) {
                Lang_Action defaultLangAction = action.CachedLangActions[_config.DefaultLang];
                //skip if default lang for this action does not have replies
                if (defaultLangAction.Replies == null || defaultLangAction.Replies.Count == 0) continue;
                bool canSend = false;
                if(TriggerDefinitions.TryGetValue(action.Type, out TriggerDefinition triggerDefinition)) {
                    if (triggerDefinition.RequiresTarget) {
                        //skip action if it's trigger requires a target but target parameter is null/empty
                        if (string.IsNullOrEmpty(argument)) continue;
                        //trigger based conditions
                        switch (triggerDefinition.Key) {
                            case "ChatCommand" : if (action.Target.Replace("/", "").ToLower().Split(',').Any(x => x.Trim() == argument)) canSend = true;
                            break;
                            default : if(action.Target == argument) canSend = true;
                            break;
                        }
                    }
                    else {
                        //trigger based conditions
                        switch (triggerDefinition.Key) {
                            case "NewPlayerJoined" : if (pinfo.isNew) canSend = true;
                            break;
                            case "PlayerConnected" : if (pinfo.justJoined) canSend = true;
                            break;
                            case "PlayerDead" : if (pinfo.wasDead && ((argument == "" && !action.IsGlobalBroadcast) || (argument == "FromEntityDeath" && action.IsGlobalBroadcast))) {
                                pinfo.wasDead = false;
                                canSend = true;
                            }
                            break;
                            default : canSend = true;
                            break;
                        }
                    }
                    //skip if action is on cooldown
                    if (triggerDefinition.UsesGenericCooldown && action.OnCooldownAll) continue;
                    //skip if trigger owner is on cooldown for this action
                    if (triggerDefinition.UsesPlayerCooldown && action.OnCooldown != null && action.OnCooldown.Contains(player.userID)) continue;
                }
                if (canSend) {
                    if (action.IsGlobalBroadcast)  //sends to all eligible players
                    ProcessReply(action, defaultLangAction, player, onlySendToTeam);
                    else  //sends to trigger owner
                    {
                        //check if player is eligible or has tips enabled
                        if ((action.PlayerCanDisable && !pinfo.TipsActive) || !MessageIsEligible(action, player.UserIDString)) continue;
                        string playerLanguage = lang.GetLanguage(player.UserIDString);
                        //look for reply based on player language, if not use defaut server language
                        if (!Lang_TryGetAction(player, action.Type, action.Id, playerLanguage, out Lang_Action langAction) || langAction.Replies.Count == 0) langAction = defaultLangAction;
                        //double check to avoid index out of range (might be unnecessary)
                        if (langAction.ReplyIndex >= langAction.Replies.Count) langAction.ReplyIndex = 0;
                        string reply = langAction.Replies[langAction.ReplyIndex];
                        IncrementReplyIndex(ref langAction);
                        //increment reply index
                        //define variables/placeholders
                        reply = DefineVariables(player, reply, triggerDefinition);
                        //Log($"{action.Type} | ({player.displayName} | {player.UserIDString}) | {playerLanguage} | index({langAction.ReplyIndex}) | {reply}");
                        //get icon steam id - reply custom icon > action custom icon > general settings custom icon
                        ulong iconSteamId = GetActionIcon(action, player, _config.IconSteamId);
                        timer.Once(0.5f, () => SendMessage(player, reply, action.SendInChat, iconSteamId, action.SendAsGameTip, action.IsBlueGameTip));
                    }
                    //start cooldowns
                    switch(action.Type) {
                        case "AutoReply" : action.RunCooldownAll(_config.AutoReplyCooldown);
                        break;
                        case "ChatCommand" : action.RunCooldownAll(_config.ChatCommandCooldown);
                        break;
                        case "EnteredZone" : action.RunCooldownPlayer(player, _config.ZoneManagerCooldown);
                        break;
                        case "LeftZone" : action.RunCooldownPlayer(player, _config.ZoneManagerCooldown);
                        break;
                        case "EnteredMonument" : action.RunCooldownPlayer(player, _config.MonumentWatcherCooldown);
                        break;
                        case "LeftMonument" : action.RunCooldownPlayer(player, _config.MonumentWatcherCooldown);
                        break;
                    }
                }
            }
            pinfo.isNew = false;
            pinfo.justJoined = false;
        }
        private void ProcessReply(PluginConfig.ConfigAction action, Lang_Action defaultLangAction, BasePlayer triggerOwner = null, bool onlySendToTeam = false) {
            //skip if trigger owner is admin and disables it
            if (triggerOwner && triggerOwner.IsAdmin && action.DontTriggerAdmin) return;
            //keep track of already incremented lang replies
            Dictionary<string, string> cachedLangsReplies = new();
            ulong iconSteamId = GetActionIcon(action, triggerOwner, _config.IconSteamId);
            foreach (var player in BasePlayer.activePlayerList) {
                if(triggerOwner && onlySendToTeam && triggerOwner.currentTeam != 0 && triggerOwner.currentTeam != player.currentTeam) continue;
                if (!pData.Players.TryGetValue(player.userID, out var pinfo)) pData.Players.Add(player.userID, pinfo = new PlayerInfo {
                    TipsActive = true, isNew = true
                }
                );
                if ((action.PlayerCanDisable && !pinfo.TipsActive) || !MessageIsEligible(action, player.UserIDString)) continue;
                string playerLanguage = lang.GetLanguage(player.UserIDString);
                if (!cachedLangsReplies.TryGetValue(playerLanguage, out string reply)) {
                    bool retrievedCached = false;
                    //look for reply based on player language, if not use default server lang action
                    if (!Lang_TryGetAction(player, action.Type, action.Id, playerLanguage, out Lang_Action playerlangAction) || playerlangAction.Replies.Count == 0) {
                        //check if default lang reply was cached
                        if (cachedLangsReplies.TryGetValue(_config.DefaultLang, out reply)) retrievedCached = true;
                        else {
                            playerLanguage = _config.DefaultLang;
                            playerlangAction = defaultLangAction;
                        }
                    }
                    if (!retrievedCached) {
                        //double check to avoid index out of range (might be unnecessary)
                        if (playerlangAction.ReplyIndex >= playerlangAction.Replies.Count) playerlangAction.ReplyIndex = 0;
                        reply = playerlangAction.Replies[playerlangAction.ReplyIndex];
                        //increment reply index
                        IncrementReplyIndex(ref playerlangAction);
                        cachedLangsReplies.Add(playerLanguage, reply);
                    }
                }
                //define variables/placeholders
                reply = DefineVariables(triggerOwner ? triggerOwner : player, reply, TriggerDefinitions[action.Type]);
                //Log($"{action.Type} | ({player.displayName} | {player.UserIDString}) | {playerLanguage} | {reply}");
                timer.Once(0.5f, () => SendMessage(player, reply, action.SendInChat, iconSteamId, action.SendAsGameTip, action.IsBlueGameTip));
            }
        }
        private ulong GetActionIcon(PluginConfig.ConfigAction action, BasePlayer triggerOwner, string defaultIconSteamId) {
            ulong iconSteamId;
            if (triggerOwner != null && action.UseTriggerOwnerIcon) iconSteamId = triggerOwner.userID;
            else if (!ulong.TryParse(action.CustomIconSteamId, out iconSteamId) || iconSteamId <= 0) ulong.TryParse(defaultIconSteamId, out iconSteamId);
            return iconSteamId;
        }
        private void IncrementReplyIndex(ref Lang_Action lang_Action) {
            lang_Action.ReplyIndex++;
            if (lang_Action.ReplyIndex >= lang_Action.Replies.Count || lang_Action.ReplyIndex < 0) lang_Action.ReplyIndex = 0;
        }
        readonly List<string> availableVariables = new() {
            "{playername}", "{playerid}", "{playercountry}", "{wipetimeremaining}", "{online}", "{sleeping}", "{joining}"
        }
        ;
        private string DefineVariables(BasePlayer player, string message, TriggerDefinition triggerDefinition) {
            StringBuilder builder = new StringBuilder(message);
            builder.Replace("{playername}", player.displayName).Replace("{playerid}", player.UserIDString).Replace("{online}", $"{BasePlayer.activePlayerList.Count}").Replace("{sleeping}", $"{BasePlayer.sleepingPlayerList.Count}").Replace("{joining}", $"{ServerMgr.Instance.connectionQueue.Joining + ServerMgr.Instance.connectionQueue.Queued}");
            if (message.Contains("{playercountry}")) {
                var found = pData.Players.TryGetValue(player.userID, out var pinfo);
                if (found && !string.IsNullOrEmpty(pinfo.Country)) builder.Replace("{playercountry}", pinfo.Country);
                else builder.Replace("{playercountry}", "");
            }
            if (message.Contains("{wipetimeremaining}") && WipeTimer.serverinstance != null) {
                DateTimeOffset nowTime = DateTimeOffset.UtcNow;
                nowTime = nowTime.AddDays(WipeTimer.daysToAddTest);
                nowTime = nowTime.AddHours(WipeTimer.hoursToAddTest);
                DateTimeOffset wipeTime = WipeTimer.serverinstance.GetWipeTime(nowTime);
                TimeSpan timeSpan = wipeTime - nowTime;
                builder.Replace("{wipetimeremaining}", FormatTime(timeSpan, m : false, s : false));
            }
            switch (triggerDefinition.Key) {
                case "CrateHacked" : if (pData.Players.TryGetValue(player.userID, out var pinfo) && !string.IsNullOrEmpty(pinfo.HackLocation)) builder.Replace("{hacklocation}", pinfo.HackLocation);
                else builder.Replace("{hacklocation}", MapHelper.PositionToString(player.transform.position));
                break;
            }
            PlaceholderAPI?.CallHook("ProcessPlaceholders", player.IPlayer, builder);
            return builder.ToString();
        }
        private void Log(string text) {
            LogToFile("debug", $"[{DateTime.Now}] {text}", this);
        }
#endregion
#region Hooks
        private void UnsubscribeHooks() {
            Unsubscribe(nameof(OnPlayerChat));
            Unsubscribe(nameof(OnPlayerDisconnected));
            Unsubscribe(nameof(CanHackCrate));
            Unsubscribe(nameof(OnEntityDeath));
            Unsubscribe(nameof(OnPlayerSleepEnded));
            Unsubscribe(nameof(OnUserPermissionGranted));
            Unsubscribe(nameof(OnUserPermissionRevoked));
            Unsubscribe(nameof(OnUserGroupAdded));
            Unsubscribe(nameof(OnUserGroupRemoved));
            Unsubscribe(nameof(OnEnterZone));
            Unsubscribe(nameof(OnExitZone));
            Unsubscribe(nameof(OnPlayerEnteredMonument));
            Unsubscribe(nameof(OnPlayerExitedMonument));
        }
        private void SubscribeHooks() {
            foreach (var trigger in TriggerDefinitions) {
                if (string.IsNullOrEmpty(trigger.Value.Hooks)) continue;
                if (_config.Actions.Any(s => s.Type == trigger.Key && s.IsEnabled())) foreach (string hook in trigger.Value.Hooks.Split(',')) Subscribe(hook);
            }
        }
        private void OnPlayerChat(BasePlayer player, string message, Chat.ChatChannel chatchannel) {
            if (chatchannel != Chat.ChatChannel.Global && chatchannel != Chat.ChatChannel.Team) return;
            foreach (var keywords in _autoReplyPatterns.Where(regex => regex.Key.Match(message).Success)) NextTick(() => ProcessReplies(player, new() {
                "AutoReply"
            }
            , keywords.Value.Target, chatchannel == Chat.ChatChannel.Team && _config.BroadcastToTeamOnly));
        }
        private void OnClientAuth(Network.Connection connection) {
            pData.Players.TryGetValue(connection.userid, out var pinfo);
            FetchConnectionCountry(connection, pinfo);
        }
        private void OnPlayerConnected(BasePlayer player) {
            if (!player.userID.IsSteamId()) return;
            if (pData.Players.TryGetValue(player.userID, out var pinfo)) pinfo.justJoined = true;
            else pData.Players.Add(player.userID, pinfo = new PlayerInfo {
                TipsActive = true, isNew = true, justJoined = !HasActiveNewPlayerJoinedAction
            }
            );
            if (string.IsNullOrEmpty(pinfo.Country)) FetchConnectionCountry(player.Connection, pinfo);
        }
        private void OnPlayerDisconnected(BasePlayer player) {
            if (player != null) ProcessReplies(player, new() {
                "PlayerDisconnected"
            }
            );
        }
        private void CanHackCrate(BasePlayer player, HackableLockedCrate crate) {
            if (player == null || !player.userID.IsSteamId()) return;
            string Location = MapHelper.PositionToString(crate.transform.position);
            if (OnCargoShip(crate)) Location = "Cargo Ship";
            else {
                MonumentRef monument = GetMonumentFromPosition(crate.transform.position);
                if (monument != null) Location = $"{monument.DisplayName} ({Location})";
            }
            if (pData.Players.TryGetValue(player.userID, out var pinfo)) pinfo.HackLocation = Location;
            else pData.Players.Add(player.userID, new PlayerInfo {
                TipsActive = true, HackLocation = Location
            }
            );
            ProcessReplies(player, new() {
                "CrateHacked"
            }
            );
        }
        private void OnEntityDeath(BasePlayer player, HitInfo hitInfo) {
            if (player == null || !player.userID.IsSteamId()) return;
            if (pData.Players.TryGetValue(player.userID, out var pinfo)) {
                pinfo.wasDead = true;
                ProcessReplies(player, new() {
                    "PlayerDead"
                }
                , "FromEntityDeath");
            }
        }
        private void OnPlayerSleepEnded(BasePlayer player) {
            if (player.IsDead() || !player.IsConnected) return;
            ProcessReplies(player, new() {
                "NewPlayerJoined", "PlayerConnected", "PlayerDead"
            }
            );
        }
        private void OnUserPermissionGranted(string id, string permName) {
            var player = BasePlayer.FindByID(Convert.ToUInt64(id));
            if (player != null) ProcessReplies(player, new() {
                "PermissionGranted"
            }
            , permName);
        }
        private void OnUserPermissionRevoked(string id, string permName) {
            var player = BasePlayer.FindByID(Convert.ToUInt64(id));
            if (player != null) ProcessReplies(player, new() {
                "PermissionRevoked"
            }
            , permName);
        }
        private void OnUserGroupAdded(string userId, string groupName) {
            var player = BasePlayer.FindByID(Convert.ToUInt64(userId));
            if (player != null) ProcessReplies(player, new() {
                "AddedToGroup"
            }
            , groupName);
        }
        private void OnUserGroupRemoved(string userId, string groupName) {
            var player = BasePlayer.FindByID(Convert.ToUInt64(userId));
            if (player != null) ProcessReplies(player, new() {
                "RemovedFromGroup"
            }
            , groupName);
        }
        private void OnEnterZone(string ZoneID, BasePlayer player) {
            if (player != null) ProcessReplies(player, new() {
                "EnteredZone"
            }
            , ZoneID);
        }
        private void OnExitZone(string ZoneID, BasePlayer player) {
            if (player != null) ProcessReplies(player, new() {
                "LeftZone"
            }
            , ZoneID);
        }
        private void OnPlayerEnteredMonument(string monumentID, BasePlayer player, string type, string oldMonumentID) {
            if (player != null) ProcessReplies(player, new() {
                "EnteredMonument"
            }
            , monumentID);
        }
        private void OnPlayerExitedMonument(string monumentID, BasePlayer player, string type, string reason, string newMonumentID) {
            if (player != null) ProcessReplies(player, new() {
                "LeftMonument"
            }
            , monumentID);
        }
#endregion
#region Commands
        private void TipsToggleChatCMD(IPlayer user, string command, string[] args) {
            var player = user.Object as BasePlayer;
            if (player == null) return;
            var isActive = pData.ToggleTipsActive(player.userID);
            ulong iconSteamId;
            ulong.TryParse(_config.IconSteamId, out iconSteamId);
            SendMessage(player, isActive ? lang.GetMessage("toggle_enabled", this, player.UserIDString) : lang.GetMessage("toggle_disabled", this, player.UserIDString), IconSteamId : iconSteamId);
        }
        private void CustomChatCMD(IPlayer user, string command, string[] args) {
            var player = user.Object as BasePlayer;
            if (player == null) return;
            ProcessReplies(player, new() {
                "ChatCommand"
            }
            , command);
        }
#endregion
#region TriggerDefinition
        Dictionary<string, TriggerDefinition> TriggerDefinitions;
        private class TriggerDefinition {
            public string Key {
                get;
                set;
            }
            public string Hooks {
                get;
                set;
            }
            public bool RequiresTarget {
                get;
                set;
            }
            public bool UsesIsGlobalBroadcast = true;
            public bool UsesDontTriggerAdmin = true;
            public bool UsesGenericCooldown {
                get;
                set;
            }
            public bool UsesPlayerCooldown {
                get;
                set;
            }
            public bool HasTriggerOwner = true;
            public List<string> Variables = new();
        }
        private void InitTriggerDefinitions() {
            TriggerDefinitions = new();
            TriggerDefinitions.Add("Timed", new() {
                Key = "Timed", RequiresTarget = false, UsesIsGlobalBroadcast = false, UsesDontTriggerAdmin = false, HasTriggerOwner = false
            }
            );
            TriggerDefinitions.Add("ChatCommand", new() {
                Key = "ChatCommand", Hooks = "OnPlayerChat", RequiresTarget = true, UsesGenericCooldown = true
            }
            );
            TriggerDefinitions.Add("AutoReply", new() {
                Key = "AutoReply", Hooks = "OnPlayerChat", RequiresTarget = true, UsesGenericCooldown = true
            }
            );
            TriggerDefinitions.Add("NewPlayerJoined", new() {
                Key = "NewPlayerJoined", Hooks = "OnPlayerSleepEnded", RequiresTarget = false
            }
            );
            TriggerDefinitions.Add("PlayerConnected", new() {
                Key = "PlayerConnected", Hooks = "OnPlayerSleepEnded", RequiresTarget = false
            }
            );
            TriggerDefinitions.Add("PlayerDisconnected", new() {
                Key = "PlayerDisconnected", Hooks = "OnPlayerDisconnected", RequiresTarget = false
            }
            );
            TriggerDefinitions.Add("PermissionGranted", new() {
                Key = "PermissionGranted", Hooks = "OnUserPermissionGranted", RequiresTarget = true
            }
            );
            TriggerDefinitions.Add("PermissionRevoked", new() {
                Key = "PermissionRevoked", Hooks = "OnUserPermissionRevoked", RequiresTarget = true
            }
            );
            TriggerDefinitions.Add("AddedToGroup", new() {
                Key = "AddedToGroup", Hooks = "OnUserGroupAdded", RequiresTarget = true
            }
            );
            TriggerDefinitions.Add("RemovedFromGroup", new() {
                Key = "RemovedFromGroup", Hooks = "OnUserGroupRemoved", RequiresTarget = true
            }
            );
            TriggerDefinitions.Add("PlayerDead", new() {
                Key = "PlayerDead", Hooks = "OnEntityDeath,OnPlayerSleepEnded", RequiresTarget = false
            }
            );
            TriggerDefinitions.Add("CrateHacked", new() {
                Key = "CrateHacked", Hooks = "CanHackCrate", RequiresTarget = false, Variables = new() {
                    "{hacklocation}"
                }
            }
            );
            TriggerDefinitions.Add("EnteredZone", new() {
                Key = "EnteredZone", Hooks = "OnEnterZone", RequiresTarget = true, UsesPlayerCooldown = true
            }
            );
            TriggerDefinitions.Add("LeftZone", new() {
                Key = "LeftZone", Hooks = "OnExitZone", RequiresTarget = true, UsesPlayerCooldown = true
            }
            );
            TriggerDefinitions.Add("EnteredMonument", new() {
                Key = "EnteredMonument", Hooks = "OnPlayerEnteredMonument", RequiresTarget = true, UsesPlayerCooldown = true
            }
            );
            TriggerDefinitions.Add("LeftMonument", new() {
                Key = "LeftMonument", Hooks = "OnPlayerExitedMonument", RequiresTarget = true, UsesPlayerCooldown = true
            }
            );
        }
#endregion
#region Config
        bool HasActiveNewPlayerJoinedAction;
        private void ProcessConfig() {
            HasActiveNewPlayerJoinedAction = _config.Actions.Any(s => s.Type == "NewPlayerJoined" && s.IsEnabled());
            Lang_CacheActions();
        }
        private class PluginConfig {
            [JsonProperty(Order = 1000)]
            public VersionNumber Version;
            [JsonProperty(Order = 1, PropertyName = "Chat Icon (Steam Id)")]
            public string IconSteamId {
                get;
                set;
            }
            [JsonProperty(Order = 2, PropertyName = "Toggle Chat Command")]
            public string ToggleCommand {
                get;
                set;
            }
            [JsonProperty(Order = 3, PropertyName = "AutoReply Cooldown (in seconds)")]
            public int AutoReplyCooldown {
                get;
                set;
            }
            [JsonProperty(Order = 4, PropertyName = "ChatCommand Cooldown (in seconds)")]
            public int ChatCommandCooldown {
                get;
                set;
            }
            [JsonProperty(Order = 5, PropertyName = "ZoneManager Cooldown (in seconds)")]
            public int ZoneManagerCooldown {
                get;
                set;
            }
            [JsonProperty(Order = 6, PropertyName = "MonumentWatcher Cooldown (in seconds)")]
            public int MonumentWatcherCooldown {
                get;
                set;
            }
            [JsonProperty(Order = 7, PropertyName = "Sample Types for Reference (Do Not Edit)")]
            public string SampleTypes {
                get;
                set;
            }
            [JsonProperty(Order = 8, PropertyName = "Replies Server Languages (Creates lang file for each in data/AutomatedMessages/lang)")]
            public List<string> ServerLangs {
                get;
                set;
            }
            [JsonProperty(Order = 9, PropertyName = "Default Server Language")]
            public string DefaultLang {
                get;
                set;
            }
            [JsonProperty(Order = 10, PropertyName = "AutoReply `Broadcast to all` option to broadcast to team only if keywords sent from team chat")]
            public bool BroadcastToTeamOnly {
                get;
                set;
            }
            [JsonProperty(Order = 11, PropertyName = "Actions")]
            public List<ConfigAction> Actions {
                get;
                set;
            }
            [JsonProperty("Chat Icon (SteamId)")]
            public ulong _ObsIconSteamId {
                get;
                set;
            }
            [JsonProperty("Messages")]
            public List<ConfigAction> _ObsMessages;
            public bool ShouldSerialize_ObsMessages() => _ObsMessages != null;
            internal class ConfigAction {
                [JsonProperty("Id")]
                public string Id = GenerateId();
                [JsonProperty(Order = 0, PropertyName = "Enabled")]
                public bool Enabled {
                    get;
                    set;
                }
                [JsonProperty("Type (Check Sample Types above for Reference)")]
                public string Type = "";
                [JsonProperty("Broadcast to all?")]
                public bool IsGlobalBroadcast {
                    get;
                    set;
                }
                [JsonProperty("Don't trigger for admins")]
                public bool DontTriggerAdmin {
                    get;
                    set;
                }
                [JsonProperty("Send in chat")]
                public bool SendInChat = true;
                [JsonProperty("Send as game tip")]
                public bool SendAsGameTip {
                    get;
                    set;
                }
                [JsonProperty("Game tip color (true = blue - false = red)")]
                public bool IsBlueGameTip = true;
                [JsonProperty("Interval between messages in minutes (if Type = Timed)")]
                public int Interval = 0;
                [JsonProperty("Target")]
                public string Target = "";
                [JsonProperty("Custom chat icon (Steam Id)")]
                public string CustomIconSteamId = "0";
                [JsonProperty("Use trigger owner chat icon")]
                public bool UseTriggerOwnerIcon {
                    get;
                    set;
                }
                [JsonProperty("Permissions")]
                public List<string> Permissions = new();
                [JsonProperty("Groups")]
                public List<string> Groups = new();
                [JsonProperty("Blacklisted Permissions")]
                public List<string> BlacklistedPerms = new();
                [JsonProperty("Blacklisted Groups")]
                public List<string> BlacklistedGroups = new();
                [JsonProperty("Player Can Disable?")]
                public bool PlayerCanDisable {
                    get;
                    set;
                }
                [JsonIgnore]
                public bool OnCooldownAll;
                [JsonIgnore]
                public List<ulong> OnCooldown {
                    get;
                    set;
                }
                [JsonIgnore]
                public Dictionary<string, Lang_Action> CachedLangActions {
                    get;
                    set;
                }
                [JsonProperty("Messages (Random if more than one)")]
                public List<string> _ObsMessages;
                [JsonProperty("Replies")]
                public List<string> _ObsReplies;
                public void RunCooldownAll(int cooldown) {
                    if (cooldown <= 0) return;
                    OnCooldownAll = true;
                    _plugin.timer.Once(cooldown, () => {
                        OnCooldownAll = false;
                    }
                    );
                }
                public void RunCooldownPlayer(BasePlayer player, int cooldown) {
                    OnCooldown ??= new();
                    if (cooldown <= 0 || OnCooldown.Contains(player.userID)) return;
                    OnCooldown.Add(player.userID);
                    _plugin.timer.Once(cooldown, () => {
                        OnCooldown.Remove(player.userID);
                    }
                    );
                }
                public ConfigAction Clone(bool newGuid = false) {
                    return new ConfigAction {
                        Id = newGuid ? GenerateId() : Id, Enabled = Enabled, Type = Type, IsGlobalBroadcast = IsGlobalBroadcast, DontTriggerAdmin = DontTriggerAdmin, SendInChat = SendInChat, SendAsGameTip = SendAsGameTip, IsBlueGameTip = IsBlueGameTip, Interval = Interval, Target = Target, UseTriggerOwnerIcon = UseTriggerOwnerIcon, CustomIconSteamId = CustomIconSteamId, Permissions = new(Permissions), Groups = new(Groups), BlacklistedPerms = new(BlacklistedPerms), BlacklistedGroups = new(BlacklistedGroups), PlayerCanDisable = PlayerCanDisable, CachedLangActions = null
                    }
                    ;
                }
                public bool ShouldSerialize_ObsMessages() => _ObsMessages != null;
                public bool ShouldSerialize_ObsReplies() => _ObsReplies != null;
                private static string GenerateId() {
                    ulong timestamp = (ulong)DateTime.UtcNow.Ticks;
                    uint randomPart = (uint)UnityEngine.Random.Range(0, int.MaxValue);
                    return ((timestamp << 32) | randomPart).ToString();
                }
                public bool IsEnabled() => Enabled && (SendInChat || SendAsGameTip);
            }
            public bool ShouldSerialize_ObsIconSteamId() => _ObsIconSteamId != 0;
        }
        private PluginConfig GetDefaultConfig() {
            PluginConfig result = new() {
                IconSteamId = "0", Version = Version, ToggleCommand = "tips", AutoReplyCooldown = 30, ChatCommandCooldown = 30, ZoneManagerCooldown = 0, MonumentWatcherCooldown = 15, SampleTypes = string.Join(" | ", TriggerDefinitions.Keys), ServerLangs = new() {
                    "en", "es-ES", "it", "ru", "zh-CN"
                }
                , DefaultLang = GetOxideLanguage(), BroadcastToTeamOnly = true, Actions = new()
            }
            ;
            return result;
        }
        private void CheckForConfigUpdates() {
            bool changes = false;
            if (_config == null) {
                PluginConfig tmpDefaultConfig = GetDefaultConfig();
                _config = tmpDefaultConfig;
                changes = true;
            }
            string sampleTypes = string.Join(" | ", TriggerDefinitions.Keys);
            if(_config.SampleTypes != sampleTypes) {
                _config.SampleTypes = sampleTypes;
                changes = true;
            }
            //1.0.8 update
            if (_config.Version < new VersionNumber(1, 0, 8)) {
                PluginConfig tmpDefaultConfig = GetDefaultConfig();
                _config.ToggleCommand = tmpDefaultConfig.ToggleCommand;
                changes = true;
            }
            //1.0.16 update
            if (_config.Version < new VersionNumber(1, 0, 16)) {
                PluginConfig tmpDefaultConfig = GetDefaultConfig();
                _config.AutoReplyCooldown = tmpDefaultConfig.AutoReplyCooldown;
                changes = true;
            }
            //2.0.0 update
            if (_config.Version < new VersionNumber(2, 0, 0)) {
                if (_config._ObsMessages != null) _config.Actions = new(_config._ObsMessages);
                else _config.Actions = new();
                _config._ObsMessages = null;
                foreach (var action in _config.Actions) {
                    if (action._ObsMessages != null) action._ObsReplies = new(action._ObsMessages);
                    else action._ObsReplies = new();
                    action._ObsMessages = null;
                }
                changes = true;
            }
            if(string.IsNullOrEmpty(_config.DefaultLang) || !AvailableLangs.ContainsKey(_config.DefaultLang)) {
                if (!string.IsNullOrEmpty(_config.DefaultLang) && CorrectedLangNames.TryGetValue(_config.DefaultLang, out string changedTo)) {
                    PrintWarning($"Config default language {_config.DefaultLang} has been changed to '{changedTo}'");
                    _config.DefaultLang = changedTo;
                }
                else _config.DefaultLang = GetOxideLanguage();
                changes = true;
            }
            //2.0.6 update
            if (_config.Version < new VersionNumber(2, 0, 6)) {
                PluginConfig tmpDefaultConfig = GetDefaultConfig();
                _config.ServerLangs = _config.ServerLangs;
                _config.IconSteamId = _config._ObsIconSteamId.ToString();
                _config._ObsIconSteamId = 0;
                _config.ChatCommandCooldown = tmpDefaultConfig.ChatCommandCooldown;
                _config.ZoneManagerCooldown = tmpDefaultConfig.ZoneManagerCooldown;
                _config.MonumentWatcherCooldown = tmpDefaultConfig.MonumentWatcherCooldown;
                _config.ServerLangs = new() {
                    _config.DefaultLang
                }
                ;
                RepliesLangData = new();
                foreach (string serverLang in _config.ServerLangs) {
                    if (!AvailableLangs.ContainsKey(serverLang)) continue;
                    if (RepliesLangData.ContainsKey(serverLang)) continue;
                    Lang_Root langRoot = new();
                    foreach (var triggerDefinition in TriggerDefinitions) if (!langRoot.Triggers.ContainsKey(triggerDefinition.Key)) langRoot.Triggers.Add(triggerDefinition.Key, new());
                    RepliesLangData.Add(serverLang, langRoot);
                }
                foreach (var action in _config.Actions) {
                    if (action._ObsReplies != null) {
                        foreach (var langRoot in RepliesLangData) {
                            if(langRoot.Value.Triggers.TryGetValue(action.Type, out Lang_Trigger langTrigger)) {
                                langTrigger.Actions ??= new();
                                if(langRoot.Key == _config.DefaultLang) langTrigger.Actions.Add(action.Id, new() {
                                    Replies = action._ObsReplies
                                }
                                );
                                else langTrigger.Actions.Add(action.Id, new());
                            }
                        }
                        action._ObsReplies = null;
                    }
                }
                Lang_SaveRepliesData();
                changes = true;
            }
            else {
                if (_config.ServerLangs == null || _config.ServerLangs.Count == 0) {
                    _config.ServerLangs = new() {
                        GetOxideLanguage()
                    }
                    ;
                    changes = true;
                }
                List<string> langsRemoved = new();
                for (int i = _config.ServerLangs.Count - 1; i >= 0; i--) {
                    if (!AvailableLangs.ContainsKey(_config.ServerLangs[i])) {
                        if (CorrectedLangNames.TryGetValue(_config.ServerLangs[i], out string changedTo)) {
                            PrintWarning($"Config reply language {_config.ServerLangs[i]} has been changed to '{changedTo}'");
                            _config.ServerLangs[i] = changedTo;
                            changes = true;
                        }
                        else {
                            langsRemoved.Add(_config.ServerLangs[i]);
                            _config.ServerLangs.RemoveAt(i);
                            changes = true;
                        }
                    }
                }
                if (langsRemoved.Count > 0) {
                    PrintWarning($"Language code{(langsRemoved.Count > 1 ? "s" : "")} \"{string.Join(", ", langsRemoved)}\" {(langsRemoved.Count > 1 ? "are" : "is")} not available or not in correct code (removed from config), the following are the available options:\n{string.Join(", ", AvailableLangs.Keys)}.");
                    changes = true;
                }
                Lang_LoadRepliesData();
            }
            //2.0.9 update
            if (_config.Version < new VersionNumber(2, 0, 9)) {
                _config.BroadcastToTeamOnly = true;
                changes = true;
            }
            if (_config.Version != Version) changes = true;
            if (changes) {
                _config.Version = Version;
                PrintWarning("Config updated.");
                SaveConfig();
            }
        }
        protected override void LoadDefaultConfig() => _config = GetDefaultConfig();
        protected override void LoadConfig() {
            InitTriggerDefinitions();
            base.LoadConfig();
            _config = Config.ReadObject<PluginConfig>();
            CheckForConfigUpdates();
        }
        protected override void SaveConfig() => Config.WriteObject(_config);
#endregion
#region Data
        private PlayersData pData;
        private void OnServerSave() => timer.Once(UnityEngine.Random.Range(5f, 10f), SaveData);
        private bool wiped {
            get;
            set;
        }
        private void OnNewSave(string filename) => wiped = true;
        private void SaveData() => pData?.Save();
        public class PlayersData {
            public Dictionary<ulong, PlayerInfo> Players = new();
            public static PlayersData Load() {
                var data = Interface.Oxide.DataFileSystem.ReadObject<PlayersData>($"{nameof(AutomatedMessages)}/PlayerData");
                if (data == null || _plugin.wiped) {
                    _plugin.PrintWarning("No player data found! Creating a new data file.");
                    data = new();
                    data.Save();
                }
                return data;
            }
            public void Save() {
                Interface.Oxide.DataFileSystem.WriteObject($"{nameof(AutomatedMessages)}/PlayerData", this);
            }
            public bool CheckIfNew(ulong playerid) {
                return !Players.ContainsKey(playerid);
            }
            public void EnableTips(ulong play
// ... [Code preview truncated due to length. Full source in attached file] ...

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