using System; using System.Linq; using System.Collections.Generic; using UnityEngine; using Newtonsoft.Json; using Oxide.Core; namespace Oxide.Plugins { [Info("CMe", "TF Crazy", "1.0.4")] [Description("The /me command allows you to display a specific action above the head of a player. It’s particularly used for actions that couldn’t have been done in game in a roleplay context.")] public class CMe : RustPlugin { #region Fields private static string permUse = "cme.use"; private static string permView = "cme.view"; private static List adminList = new List(); #endregion #region Server /// Iniialize private void OnServerInitialized() { permission.RegisterPermission(permUse, this); permission.RegisterPermission(permView, this); cmd.AddChatCommand(cfg.chat.command, this, nameof(cmdCMeCommand)); } /// Destroy object if plugin unload private void Unload() { Me message; foreach(BasePlayer player in BasePlayer.activePlayerList) { message = player.GetComponent(); if (message != null) UnityEngine.Object.Destroy(message); } } #endregion #region Component /// Create me objet public class Me : MonoBehaviour { private BasePlayer player; private TimeSpan start; private string message; public void Awake() => player = GetComponent(); /// Called for display player message /// String: Contains messsage sended by player public void DisplayMessage(string text) { this.start = DateTime.Now.TimeOfDay; if(cfg.setting.capitalize) this.message = text.ToUpper(); this.message = cfg.setting.pattern.Replace("{message}", this.message); InvokeRepeating("Instance", 0f, 0.075f); } /// Display message for all players in radius public void Instance() { if(start.Add(TimeSpan.FromSeconds(cfg.setting.duration)) < DateTime.Now.TimeOfDay) Destroy(this); foreach (BasePlayer target in BasePlayer.activePlayerList) { if(target == null) continue; if(!player.IPlayer.HasPermission(permView)) continue; if(!IsReady(player)) continue; if(!CheckDistance(player.transform.position,target.transform.position, cfg.setting.range)) continue; FakeAdminEnable(target); DrawText(target, new Vector3(player.transform.position.x, player.transform.position.y + 2f, player.transform.position.z), message, cfg.setting.color, cfg.setting.size, 0.1f); FakeAdminDisable(target); } } } #endregion #region Chat Command /// Chat command for create me /// BasePlayer: contain informations about the player /// String: chat command /// String[]: message sended in array private void cmdCMeCommand(BasePlayer player, string command, string[] args) { if(player == null) return; if(!player.IPlayer.HasPermission(permUse)) { SendReply(player, GetLang("Msg_NotAllowed", true, player.IPlayer.Id, cfg.chat.command)); return; } if(args == null || args.Count() == 0) { SendReply(player, GetLang("Msg_Command", true, player.IPlayer.Id, cfg.chat.command)); return; } Me message; message = player.GetComponent(); if (message != null) UnityEngine.Object.Destroy(message); message = player.gameObject.AddComponent(); message.DisplayMessage(string.Join(" ", args)); } #endregion #region Function /// Check if player is ready for receive action /// BasePlayer: contain informations about the player /// True if player can receive private static bool IsReady(BasePlayer player) { if(player.IsDead()) return false; if(player.IsSleeping()) return false; if(player.IsReceivingSnapshot) return false; return true; } /// Check if two players are less than or equal to the specified distance /// Vector3: location of player /// Vector3: location of target /// Float: location of target /// Bool: true if less or equal private static bool CheckDistance(Vector3 p, Vector3 t, float radius) { var distance = Math.Floor(Vector3.Distance(p, t)); if (distance >= radius) return false; return true; } /// Draw text /// BasePlayer: contain informations about the player /// Vector3: location for display /// String: message /// String: color to hex /// Int: size /// Float: display duration private static void DrawText(BasePlayer player, Vector3 pos, string text, string color, int size, float duration) => player.SendConsoleCommand("ddraw.text", duration, Color.white, pos, $"{text}"); /// Get language dictionary message /// String: Dictionary key /// Bool: Default false. If true add chat prefix after message /// String: Default null. Player Id (IPlayer) /// Params Object: Arguments array /// String: formated or empty private string GetLang(string langKey, bool prefix = false, string playerId = null, params object[] args) { string str = string.Empty; if(prefix) str = $"{cfg.chat.title_msg}

"; return str + string.Format(lang.GetMessage(langKey, this, playerId), args); } /// Set admin to fake admin (for send protected command) /// BasePlayer: contain informations about the player private static void FakeAdminEnable(BasePlayer player) { if(player.IsAdmin) { if(!adminList.Contains(player.userID)) adminList.Add(player.userID); return; } player.SetPlayerFlag(BasePlayer.PlayerFlags.IsAdmin, true); player.SendNetworkUpdateImmediate(); } /// Unset admin to fake admin (for send protected command) /// BasePlayer: contain informations about the player private static void FakeAdminDisable(BasePlayer player) { if(adminList.Contains(player.userID)) return; player.SetPlayerFlag(BasePlayer.PlayerFlags.IsAdmin, false); player.SendNetworkUpdateImmediate(); } #endregion #region Config private static ConfigData cfg; private class ConfigData { [JsonProperty(PropertyName = "CONFIG")] public Setting setting { get; set; } [JsonProperty(PropertyName = "CHAT")] public Chat chat { get; set; } [JsonProperty(PropertyName = "VERSION")] public VersionNumber version { get; set; } } private class Setting { [JsonProperty(PropertyName = "» Message duration (seconds)")] public int duration { get; set; } [JsonProperty(PropertyName = "» Message size")] public int size { get; set; } [JsonProperty(PropertyName = "» Message color")] public string color { get; set; } [JsonProperty(PropertyName = "» Message pattern")] public string pattern { get; set; } [JsonProperty(PropertyName = "» Message in capital letters ?")] public bool capitalize { get; set; } [JsonProperty(PropertyName = "» Display range")] public float range { get; set; } } private class Chat { [JsonProperty(PropertyName = "» Chat Command")] public string command { get; set; } [JsonProperty(PropertyName = "» Chat Prefix message")] public string title_msg { get; set; } [JsonProperty(PropertyName = "» Chat prefix size")] public int title_size { get; set; } [JsonProperty(PropertyName = "» Chat prefix color")] public string title_color { get; set; } } private ConfigData GetBaseConfig() { return new ConfigData { setting = new Setting { duration = 10, size = 20, color = "#ce422b", pattern = "* {message} *", capitalize = true, range = 15f }, chat = new Chat { command = "me", title_msg = "Roleplay Message", title_size = 18, title_color = "#ce422b", }, version = Version }; } protected override void LoadConfig() { base.LoadConfig(); cfg = Config.ReadObject(); if (cfg.version < Version) UpdateConfigValues(); Config.WriteObject(cfg, true); } protected override void LoadDefaultConfig() => cfg = GetBaseConfig(); protected override void SaveConfig() => Config.WriteObject(cfg, true); private void UpdateConfigValues() { PrintWarning("Config update detected! Updating config values..."); ConfigData baseConfig = GetBaseConfig(); cfg.version = Version; PrintWarning("Config update completed!"); } #endregion #region Localization /// /// Language text /lang /// protected override void LoadDefaultMessages() { /// /// English /// lang.RegisterMessages(new Dictionary { ["Msg_Command"] = "Syntax: /{0} your message.", ["Msg_NotAllowed"] = "You are not allowed to use the /{0} command." }, this); /// /// French /// lang.RegisterMessages(new Dictionary { ["Msg_Command"] = "Syntaxe : /{0} votre message.", ["Msg_NotAllowed"] = "Vous n'êtes pas autorisé à utiliser la commande /{0}." }, this, "fr"); } #endregion } }