using Newtonsoft.Json.Linq; using Oxide.Core; using Oxide.Core.Libraries; using Oxide.Core.Plugins; using System; using System.Collections.Generic; using System.Reflection; using System.Text; using System.Text.RegularExpressions; namespace Oxide.Plugins { [Info("Rust:IO Clans", "playrust.io / dcode", "1.7.3", ResourceId = 842)] [Description("Allows your players to form and manage clans with Rust:IO")] public class Clans : RustPlugin { #region Rust:IO Bindings private Library lib; private MethodInfo isInstalled; private MethodInfo hasFriend; private MethodInfo addFriend; private MethodInfo deleteFriend; private void ioInitialize() { lib = Interface.Oxide.GetLibrary("RustIO"); if (lib == null || (isInstalled = lib.GetFunction("IsInstalled")) == null || (hasFriend = lib.GetFunction("HasFriend")) == null || (addFriend = lib.GetFunction("AddFriend")) == null || (deleteFriend = lib.GetFunction("DeleteFriend")) == null) { lib = null; Puts("Rust:IO is not present. You need to install Rust:IO first in order to use this plugin!"); } } private bool ioIsInstalled() { if (lib == null) return false; return (bool)isInstalled.Invoke(lib, new object[] { }); } private bool ioHasFriend(string playerId, string friendId) { if (lib == null) return false; return (bool)hasFriend.Invoke(lib, new object[] { playerId, friendId }); } private bool ioAddFriend(string playerId, string friendId) { if (lib == null) return false; return (bool)addFriend.Invoke(lib, new object[] { playerId, friendId }); } private bool ioDeleteFriend(string playerId, string friendId) { if (lib == null) return false; return (bool)deleteFriend.Invoke(lib, new object[] { playerId, friendId }); } #endregion private Dictionary clans = new Dictionary(); private Dictionary originalNames = new Dictionary(); private Regex tagRe = new Regex("^[a-zA-Z0-9]{2,6}$"); private Dictionary messages = new Dictionary(); private Dictionary lookup = new Dictionary(); private bool addClanMatesAsFriends = true; private int limitMembers = -1; private int limitModerators = -1; private void loadData() { clans.Clear(); var data = Interface.Oxide.DataFileSystem.GetDatafile("rustio_clans"); if (data["clans"] != null) { var clansData = (Dictionary)Convert.ChangeType(data["clans"], typeof(Dictionary)); foreach (var iclan in clansData) { string tag = iclan.Key; var clanData = iclan.Value as Dictionary; string description = (string)clanData["description"]; string owner = (string)clanData["owner"]; List moderators = new List(); foreach (var imoderator in clanData["moderators"] as List) { moderators.Add((string)imoderator); } List members = new List(); foreach (var imember in clanData["members"] as List) { members.Add((string)imember); } List invited = new List(); foreach (var iinvited in clanData["invited"] as List) { invited.Add((string)iinvited); } Clan clan; clans.Add(tag, clan = new Clan() { tag = tag, description = description, owner = owner, moderators = moderators, members = members, invited = invited }); lookup[owner] = clan; foreach (var member in members) lookup[member] = clan; } } } private void saveData() { var data = Interface.Oxide.DataFileSystem.GetDatafile("rustio_clans"); var clansData = new Dictionary(); foreach (var clan in clans) { var clanData = new Dictionary(); clanData.Add("tag", clan.Value.tag); clanData.Add("description", clan.Value.description); clanData.Add("owner", clan.Value.owner); var moderators = new List(); foreach (var imoderator in clan.Value.moderators) moderators.Add(imoderator); var members = new List(); foreach (var imember in clan.Value.members) members.Add(imember); var invited = new List(); foreach (var iinvited in clan.Value.invited) invited.Add(iinvited); clanData.Add("moderators", moderators); clanData.Add("members", members); clanData.Add("invited", invited); clansData.Add(clan.Value.tag, clanData); } data["clans"] = clansData; Interface.Oxide.DataFileSystem.SaveDatafile("rustio_clans"); } private List texts = new List() { "%NAME% has come online!", "%NAME% has gone offline.", "You are currently not a member of a clan.", "You are the owner of:", "You are a moderator of:", "You are a member of:", "Members online:", "Pending invites:", "To learn more about clans, type: /clan help", "Usage: /clan create \"TAG\" \"Description\"", "You are already a member of a clan.", "Clan tags must be 2 to 6 characters long and may contain standard letters and numbers only", "Please provide a short description of your clan.", "There is already a clan with this tag.", "You are now the owner of your new clan:", "To invite new members, type: /clan invite \"Player name\"", "Usage: /clan invite \"Player name\"", "You need to be a moderator of your clan to use this command.", "No such player or player name not unique:", "This player is already a member of your clan:", "This player is not a member of your clan:", "This player has already been invited to your clan:", "This player is already a moderator of your clan:", "This player is not a moderator of your clan:", "%MEMBER% invited %PLAYER% to the clan.", "Usage: /clan join \"TAG\"", "You have not been invited to join this clan.", "%NAME% has joined the clan!", "You have been invited to join the clan:", "To join, type: /clan join \"%TAG%\"", "This clan has already reached the maximum number of members.", "This clan has already reached the maximum number of moderators.", "Usage: /clan promote \"Player name\"", "You need to be the owner of your clan to use this command.", "%OWNER% promoted %MEMBER% to moderator.", "Usage: /clan demote \"Player name\"", "Usage: /clan leave", "You have left your current clan.", "%NAME% has left the clan.", "Usage: /clan kick \"Player name\"", "This player is an owner or moderator and cannot be kicked:", "%NAME% kicked %MEMBER% from the clan.", "Usage: /clan disband forever", "Your current clan has been disbanded forever.", "Usage: /clan delete \"TAG\"", "You need to be a server owner to delete clans.", "There is no clan with that tag:", "Your clan has been deleted by the server owner.", "You have deleted the clan:", "Available commands:", "/clan - Displays relevant information about your current clan", "/c Message... - Sends a message to all online clan members", "/clan create \"TAG\" \"Description\" - Creates a new clan you own", "/clan join \"TAG\" - Joins a clan you have been invited to", "/clan leave - Leaves your current clan", "Moderator commands:", "/clan invite \"Player name\" - Invites a player to your clan", "/clan kick \"Player name\" - Kicks a member from your clan", "Owner commands:", "/clan promote \"Name\" - Promotes a member to moderator", "/clan demote \"Name\" - Demotes a moderator to member", "/clan disband forever - Disbands your clan (no undo)", "Server owner commands:", "/clan delete \"TAG\" - Deletes a clan (no undo)", "/clan - Displays your current clan status", "/clan help - Learn how to create or join a clan" }; protected override void LoadDefaultConfig() { var messages = new Dictionary(); foreach (var text in texts) { if (messages.ContainsKey(text)) Puts("Duplicate translation string: " + text); else messages.Add(text, text); } Config["messages"] = messages; Config.Set("addClanMatesAsFriends", true); Config.Set("limit", "members", -1); Config.Set("limit", "moderators", -1); } private string _(string text, Dictionary replacements = null) { if (messages.ContainsKey(text) && messages[text] != null) text = messages[text]; if (replacements != null) foreach (var replacement in replacements) text = text.Replace("%" + replacement.Key + "%", replacement.Value); return text; } private Clan findClan(string tag) { Clan clan; if (clans.TryGetValue(tag, out clan)) return clan; return null; } private Clan findClanByUser(string userId) { Clan clan; if (lookup.TryGetValue(userId, out clan)) return clan; return null; } private BasePlayer findPlayerByPartialName(string name) { if (string.IsNullOrEmpty(name)) return null; BasePlayer player = null; name = name.ToLower(); var allPlayers = BasePlayer.activePlayerList.ToArray(); foreach (var p in allPlayers) { if (p.displayName == name) { if (player != null) return null; // Not unique player = p; } } if (player != null) return player; foreach (var p in allPlayers) { if (p.displayName.ToLower().IndexOf(name) >= 0) { if (player != null) return null; // Not unique player = p; } } return player; } private string stripTag(string name, Clan clan) { if (clan == null) return name; var re = new Regex(@"^\[" + clan.tag + @"\]\s"); while (re.IsMatch(name)) name = name.Substring(clan.tag.Length + 3); return name; } private void setupPlayer(BasePlayer player) { var prevName = player.displayName; var playerId = player.UserIDString; var clan = findClanByUser(playerId); player.displayName = stripTag(player.displayName, clan); string originalName = null; if (!originalNames.ContainsKey(playerId)) { originalNames.Add(playerId, originalName = player.displayName); } else { originalName = originalNames[playerId]; } if (clan == null) { player.displayName = originalName; } else { var tag = "[" + clan.tag + "]" + " "; if (!player.displayName.StartsWith(tag)) player.displayName = tag + originalName; } if (player.displayName != prevName) player.SendNetworkUpdate(); } private void setupPlayers(List playerIds) { foreach (var playerId in playerIds) { var uid = Convert.ToUInt64(playerId); var player = BasePlayer.FindByID(uid); if (player != null) setupPlayer(player); else { player = BasePlayer.FindSleeping(uid); if (player != null) setupPlayer(player); } } } private void OnServerInitialized() { try { ioInitialize(); LoadConfig(); try { var customMessages = Config.Get>("messages"); if (customMessages != null) foreach (var pair in customMessages) messages[pair.Key] = (string)pair.Value; loadData(); } catch (Exception ex2) { PrintWarning("oxide/config/Clans.json seems to contain an invalid 'messages' structure. Please delete the config file once and reload the plugin."); } foreach (var player in BasePlayer.activePlayerList) setupPlayer(player); foreach (var player in BasePlayer.sleepingPlayerList) setupPlayer(player); try { addClanMatesAsFriends = Config.Get("addClanMatesAsFriends"); } catch { } try { limitMembers = Config.Get("limit", "members"); } catch { } try { limitModerators = Config.Get("limit", "moderators"); } catch { } } catch (Exception ex) { PrintError("OnServerInitialized failed", ex); } } private void OnUserApprove(Network.Connection connection) { originalNames[connection.userid.ToString()] = connection.username; } private void OnPlayerInit(BasePlayer player) { string originalName; if (originalNames.TryGetValue(player.UserIDString, out originalName)) player.displayName = originalName; try { setupPlayer(player); var clan = findClanByUser(player.UserIDString); if (clan != null) clan.Broadcast(_("%NAME% has come online!", new Dictionary() { { "NAME", stripTag(player.displayName, clan) } })); } catch (Exception ex) { PrintError("OnPlayerInit failed", ex); } } private void OnPlayerDisconnected(BasePlayer player) { try { var clan = findClanByUser(player.UserIDString); if (clan != null) clan.Broadcast(_("%NAME% has gone offline.", new Dictionary() { { "NAME", stripTag(player.displayName, clan) } })); } catch (Exception ex) { PrintError("OnPlayerDisconnected failed", ex); } } private void Unload() { try { foreach (var pair in originalNames) { var playerId = Convert.ToUInt64(pair.Key); var player = BasePlayer.FindByID(playerId); if (player != null) player.displayName = pair.Value; else { player = BasePlayer.FindSleeping(playerId); if (player != null) player.displayName = pair.Value; } } } catch (Exception ex) { PrintError("Unload failed", ex); } } private void SendHelpText(BasePlayer player) { var sb = new StringBuilder() .Append("Clans by http://playrust.io\n") .Append(" ").Append(_("/clan - Displays your current clan status")).Append("\n") .Append(" ").Append(_("/clan help - Learn how to create or join a clan")); player.ChatMessage(sb.ToString()); } [ChatCommand("clan")] private void ClanCommand(BasePlayer player, string command, string[] args) { var userId = player.UserIDString; var myClan = findClanByUser(userId); var sb = new StringBuilder(); if (args.Length == 0) { sb.Append("Clans " + Version + " by http://playrust.io\n"); if (myClan == null) { sb.Append(_("You are currently not a member of a clan.")).Append("\n"); } else { if (myClan.IsOwner(userId)) { sb.Append(_("You are the owner of:")); } else if (myClan.IsModerator(userId)) sb.Append(_("You are a moderator of:")); else sb.Append(_("You are a member of:")); sb.Append(" [").Append(myClan.tag).Append("] ").Append(myClan.description).Append("\n"); sb.Append(_("Members online:")).Append(" "); List onlineMembers = new List(); int n = 0; foreach (var memberId in myClan.members) { var p = BasePlayer.FindByID(Convert.ToUInt64(memberId)); if (p != null) { if (n > 0) sb.Append(", "); if (myClan.IsOwner(memberId)) { sb.Append("").Append(stripTag(p.displayName, myClan)).Append(""); } else if (myClan.IsModerator(memberId)) { sb.Append("").Append(stripTag(p.displayName, myClan)).Append(""); } else { sb.Append(p.displayName); } ++n; } } sb.Append("\n"); if ((myClan.IsOwner(userId) || myClan.IsModerator(userId)) && myClan.invited.Count > 0) { sb.Append(_("Pending invites:")).Append(" "); int m = 0; foreach (var inviteId in myClan.invited) { var p = BasePlayer.FindByID(Convert.ToUInt64(inviteId)); if (p != null) { if (m > 0) sb.Append(", "); sb.Append(p.displayName); ++m; } } sb.Append("\n"); } } sb.Append(_("To learn more about clans, type: /clan help")); SendReply(player, "{0}", sb.ToString()); return; } switch (args[0]) { case "create": if (args.Length != 3) { sb.Append(_("Usage: /clan create \"TAG\" \"Description\"")); break; } if (myClan != null) { sb.Append(_("You are already a member of a clan.")); break; } if (!tagRe.IsMatch(args[1])) { sb.Append(_("Clan tags must be 2 to 6 characters long and may contain standard letters and numbers only")); break; } args[2] = args[2].Trim(); if (args[2].Length < 2 || args[2].Length > 30) { sb.Append(_("Please provide a short description of your clan.")); break; } if (clans.ContainsKey(args[1])) { sb.Append(_("There is already a clan with this tag.")); break; } myClan = Clan.Create(args[1], args[2], userId); clans.Add(myClan.tag, myClan); saveData(); lookup[userId] = myClan; setupPlayer(player); // Add clan tag sb.Append(_("You are now the owner of your new clan:")).Append(" "); sb.Append("[").Append(myClan.tag).Append("] ").Append(myClan.description).Append("\n"); sb.Append(_("To invite new members, type: /clan invite \"Player name\"")); myClan.onCreate(); break; case "invite": if (args.Length != 2) { sb.Append(_("Usage: /clan invite \"Player name\"")); break; } if (myClan == null) { sb.Append(_("You are currently not a member of a clan.")); break; } if (!myClan.IsOwner(userId) && !myClan.IsModerator(userId)) { sb.Append(_("You need to be a moderator of your clan to use this command.")); break; } var invPlayer = findPlayerByPartialName(args[1]); if (invPlayer == null) { sb.Append(_("No such player or player name not unique:")).Append(" ").Append(args[1]); break; } var invUserId = invPlayer.UserIDString; if (myClan.members.Contains(invUserId)) { sb.Append(_("This player is already a member of your clan:")).Append(" ").Append(invPlayer.displayName); break; } if (myClan.invited.Contains(invUserId)) { sb.Append(_("This player has already been invited to your clan:")).Append(" ").Append(invPlayer.displayName); break; } myClan.invited.Add(invUserId); saveData(); myClan.Broadcast(_("%MEMBER% invited %PLAYER% to the clan.", new Dictionary() { { "MEMBER", stripTag(player.displayName, myClan) }, { "PLAYER", invPlayer.displayName } })); invPlayer.SendConsoleCommand("chat.add", "", _("You have been invited to join the clan:") + " [" + myClan.tag + "] " + myClan.description + "\n" + _("To join, type: /clan join \"%TAG%\"", new Dictionary() { { "TAG", myClan.tag } })); myClan.onUpdate(); break; case "join": if (args.Length != 2) { sb.Append(_("Usage: /clan join \"TAG\"")); break; } if (myClan != null) { sb.Append(_("You are already a member of a clan.")); break; } myClan = findClan(args[1]); if (myClan == null || !myClan.IsInvited(userId)) { sb.Append(_("You have not been invited to join this clan.")); break; } if (limitMembers >= 0 && myClan.members.Count >= limitMembers) { sb.Append(_("This clan has already reached the maximum number of members.")); break; } myClan.invited.Remove(userId); myClan.members.Add(userId); saveData(); lookup[userId] = myClan; setupPlayer(player); myClan.Broadcast(_("%NAME% has joined the clan!", new Dictionary() { { "NAME", stripTag(player.displayName, myClan) } })); foreach (var memberId in myClan.members) { if (memberId != userId && ioIsInstalled() && addClanMatesAsFriends) { ioAddFriend(memberId, userId); ioAddFriend(userId, memberId); } } myClan.onUpdate(); break; case "promote": if (args.Length != 2) { sb.Append(_("Usage: /clan promote \"Player name\"")); break; } if (myClan == null) { sb.Append(_("You are currently not a member of a clan.")); break; } if (!myClan.IsOwner(userId)) { sb.Append(_("You need to be the owner of your clan to use this command.")); break; } var promotePlayer = findPlayerByPartialName(args[1]); if (promotePlayer == null) { sb.Append(_("No such player or player name not unique:") + " " + args[1]); break; } var promotePlayerUserId = promotePlayer.UserIDString; if (!myClan.IsMember(promotePlayerUserId)) { sb.Append(_("This player is not a member of your clan:") + " " + promotePlayer.displayName); break; } if (myClan.IsModerator(promotePlayerUserId)) { sb.Append(_("This player is already a moderator of your clan:") + " " + promotePlayer.displayName); break; } if (limitModerators >= 0 && myClan.moderators.Count >= limitModerators) { sb.Append(_("This clan has already reached the maximum number of moderators.")); break; } myClan.moderators.Add(promotePlayerUserId); saveData(); myClan.Broadcast(_("%OWNER% promoted %MEMBER% to moderator.", new Dictionary() { { "OWNER", stripTag(player.displayName, myClan) }, { "MEMBER", stripTag(promotePlayer.displayName, myClan) } })); myClan.onUpdate(); break; case "demote": if (args.Length != 2) { sb.Append(_("Usage: /clan demote \"Player name\"")); break; } if (myClan == null) { sb.Append(_("You are currently not a member of a clan.")); break; } if (!myClan.IsOwner(userId)) { sb.Append(_("You need to be the owner of your clan to use this command.")); break; } var demotePlayer = findPlayerByPartialName(args[1]); if (demotePlayer == null) { sb.Append(_("No such player or player name not unique:") + " " + args[1]); break; } var demotePlayerUserId = demotePlayer.UserIDString; if (!myClan.IsMember(demotePlayerUserId)) { sb.Append(_("This player is not a member of your clan:") + " " + demotePlayer.displayName); break; } if (!myClan.IsModerator(demotePlayerUserId)) { sb.Append(_("This player is not a moderator of your clan:") + " " + demotePlayer.displayName); break; } myClan.moderators.Remove(demotePlayerUserId); saveData(); myClan.Broadcast(player.displayName + " demoted " + demotePlayer.displayName + " to a member"); myClan.onUpdate(); break; case "leave": if (args.Length != 1) { sb.Append(_("Usage: /clan leave")); break; } if (myClan == null) { sb.Append(_("You are currently not a member of a clan.")); break; } if (myClan.members.Count == 1) { // Remove the clan once the last member leaves clans.Remove(myClan.tag); } else { myClan.moderators.Remove(userId); myClan.members.Remove(userId); myClan.invited.Remove(userId); if (myClan.IsOwner(userId) && myClan.members.Count > 0) { // Make the first member the new owner myClan.owner = myClan.members[0]; } } saveData(); lookup.Remove(userId); setupPlayer(player); // Remove clan tag sb.Append(_("You have left your current clan.")); myClan.Broadcast(_("%NAME% has left the clan.", new Dictionary() { { "NAME", player.displayName } })); myClan.onUpdate(); break; case "kick": if (args.Length != 2) { sb.Append(_("Usage: /clan kick \"Player name\"")); break; } if (myClan == null) { sb.Append(_("You are currently not a member of a clan.")); break; } if (!myClan.IsOwner(userId) && !myClan.IsModerator(userId)) { sb.Append(_("You need to be a moderator of your clan to use this command.")); break; } var kickPlayer = findPlayerByPartialName(args[1]); if (kickPlayer == null) { sb.Append(_("No such player or player name not unique:") + " " + args[1]); break; } var kickPlayerUserId = kickPlayer.UserIDString; if (!myClan.IsMember(kickPlayerUserId) && !myClan.IsInvited(kickPlayerUserId)) { sb.Append(_("This player is not a member of your clan:") + " " + kickPlayer.displayName); break; } if (myClan.IsOwner(kickPlayerUserId) || myClan.IsModerator(kickPlayerUserId)) { sb.Append(_("This player is an owner or moderator and cannot be kicked:") + " " + kickPlayer.displayName); break; } myClan.members.Remove(kickPlayerUserId); myClan.invited.Remove(kickPlayerUserId); saveData(); lookup.Remove(kickPlayerUserId); setupPlayer(kickPlayer); // Remove clan tag myClan.Broadcast(_("%NAME% kicked %MEMBER% from the clan.", new Dictionary() { { "NAME", stripTag(player.displayName, myClan) }, { "MEMBER", kickPlayer.displayName } })); myClan.onUpdate(); break; case "disband": if (args.Length != 2) { sb.Append(_("Usage: /clan disband forever")); break; } if (myClan == null) { sb.Append(_("You are currently not a member of a clan.")); break; } if (!myClan.IsOwner(userId)) { sb.Append(_("You need to be the owner of your clan to use this command.")); break; } clans.Remove(myClan.tag); saveData(); foreach (var member in myClan.members) lookup.Remove(member); myClan.Broadcast(_("Your current clan has been disbanded forever.")); setupPlayers(myClan.members); // Remove clan tags myClan.onDestroy(); break; case "delete": if (args.Length != 2) { sb.Append(_("Usage: /clan delete \"TAG\"")); break; } if (player.net.connection.authLevel < 2) { sb.Append(_("You need to be a server owner to delete clans.")); break; } Clan clan; if (!clans.TryGetValue(args[1], out clan)) { sb.Append(_("There is no clan with that tag:")).Append(" ").Append(args[1]); break; } clan.Broadcast(_("Your clan has been deleted by the server owner.")); clans.Remove(args[1]); saveData(); foreach (var member in clan.members) lookup.Remove(member); setupPlayers(clan.members); sb.Append(_("You have deleted the clan:")).Append(" [").Append(clan.tag).Append("] ").Append(clan.description); myClan.onDestroy(); break; default: sb.Append(_("Available commands:")).Append("\n"); sb.Append(" ").Append(_("/clan - Displays relevant information about your current clan")).Append("\n"); sb.Append(" ").Append(_("/c Message... - Sends a message to all online clan members")).Append("\n"); sb.Append(" ").Append(_("/clan create \"TAG\" \"Description\" - Creates a new clan you own")).Append("\n"); sb.Append(" ").Append(_("/clan join \"TAG\" - Joins a clan you have been invited to")).Append("\n"); sb.Append(" ").Append(_("/clan leave - Leaves your current clan")).Append("\n"); sb.Append(_("Moderator commands:")).Append("\n"); sb.Append(" ").Append(_("/clan invite \"Player name\" - Invites a player to your clan")).Append("\n"); sb.Append(" ").Append(_("/clan kick \"Player name\" - Kicks a member from your clan")).Append("\n"); sb.Append(_("Owner commands:")).Append("\n"); sb.Append(" ").Append(_("/clan promote \"Name\" - Promotes a member to moderator")).Append("\n"); sb.Append(" ").Append(_("/clan demote \"Name\" - Demotes a moderator to member")).Append("\n"); sb.Append(" ").Append(_("/clan disband forever - Disbands your clan (no undo)")).Append("\n"); if (player.net.connection.authLevel >= 2) { sb.Append(_("Server owner commands:")).Append("\n"); sb.Append(" ").Append(_("/clan delete \"TAG\" - Deletes a clan (no undo)")).Append("\n"); } break; } SendReply(player, "{0}", sb.ToString().TrimEnd()); } [ChatCommand("c")] private void ClanChatCommand(BasePlayer player, string command, string[] args) { var playerId = player.UserIDString; var myClan = findClanByUser(playerId); if (myClan == null) { SendReply(player, "{0}", _("You are currently not a member of a clan.")); return; } var message = string.Join(" ", args); if (string.IsNullOrEmpty(message)) return; myClan.Broadcast(stripTag(player.displayName, myClan) + ": " + message); var playerName = originalNames.ContainsKey(playerId) ? originalNames[playerId] : player.displayName; Puts("[CLANCHAT] {0} - {1}: {2}", myClan.tag, playerName, message); } public class Clan { public string tag; public string description; public string owner; public List moderators = new List(); public List members = new List(); public List invited = new List(); public static Clan Create(string tag, string description, string ownerId) { var clan = new Clan() { tag = tag, description = description, owner = ownerId }; clan.members.Add(ownerId); return clan; } public bool IsOwner(string userId) { return userId == owner; } public bool IsModerator(string userId) { return moderators.Contains(userId); } public bool IsMember(string userId) { return members.Contains(userId); } public bool IsInvited(string userId) { return invited.Contains(userId); } public void Broadcast(string message) { foreach (var memberId in members) { var player = BasePlayer.FindByID(Convert.ToUInt64(memberId)); if (player == null) continue; player.SendConsoleCommand("chat.add", "", "(CLAN) " + message); } } internal JObject ToJObject() { var obj = new JObject(); obj["tag"] = tag; obj["description"] = description; obj["owner"] = owner; var jmoderators = new JArray(); foreach (var moderator in moderators) jmoderators.Add(moderator); obj["moderators"] = jmoderators; var jmembers = new JArray(); foreach (var member in members) jmembers.Add(member); obj["members"] = jmembers; var jinvited = new JArray(); foreach (var invite in invited) jinvited.Add(invite); obj["invited"] = jinvited; return obj; } internal void onCreate() => Interface.Call("OnClanCreate", tag); internal void onUpdate() => Interface.Call("OnClanUpdate", tag); internal void onDestroy() => Interface.Call("OnClanDestroy", tag); } #region Plugin API [HookMethod("GetClan")] private JObject GetClan(string tag) { var clan = findClan(tag); if (clan == null) return null; return clan.ToJObject(); } [HookMethod("GetAllClans")] private JArray GetAllClans() { return new JArray(clans.Keys); } [HookMethod("GetClanOf")] private string GetClanOf(object player) { if (player == null) throw new ArgumentException("player"); if (player is ulong) player = ((ulong)player).ToString(); else if (player is BasePlayer) player = (player as BasePlayer).userID.ToString(); if (!(player is string)) throw new ArgumentException("player"); var clan = findClanByUser((string)player); if (clan == null) return null; return clan.tag; } #endregion } }