using System.Linq; using System.Collections.Generic; using Newtonsoft.Json; using ConVar; using Oxide.Core; using Oxide.Core.Libraries.Covalence; using Oxide.Ext.Discord; using Oxide.Ext.Discord.Attributes; using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Entities.Channels; using Oxide.Ext.Discord.Entities.Guilds; using Oxide.Ext.Discord.Entities.Gatway; using Oxide.Ext.Discord.Entities.Gatway.Events; using Oxide.Ext.Discord.Entities.Messages; using Oxide.Ext.Discord.Entities.Messages.Embeds; using Oxide.Ext.Discord.Entities.Permissions; using Oxide.Ext.Discord.Entities.Users; using Oxide.Ext.Discord.Libraries.Linking; using Oxide.Game.Rust.Libraries; using Oxide.Ext.Discord.Entities.Activities; using Oxide.Ext.Discord.Entities.Gatway.Commands; namespace Oxide.Plugins { [Info("DiscordCore", "ThePitereq", "1.0.0")] public class DiscordCore : RustPlugin, IDiscordLinkPlugin { public IDictionary GetSteamToDiscordIds() => data.userData; [DiscordClient] private readonly DiscordClient discordClient; private readonly DiscordLink discordLink = GetLibrary(); private readonly Dictionary authCodes = new Dictionary(); private DiscordChannel chatChannel; private DiscordGuild discordGuild; private bool initialized = false; private void OnServerInitialized() { config = Config.ReadObject(); Config.WriteObject(config); if (config.token.Length < 30) { PrintWarning("THIS IS NOT VALID DISCORD API TOKEN! INPUT CORRECT DISCORD API TOKEN. UNLOADING PLUGIN..."); Server.Command($"o.unload {Name}"); return; } foreach (var command in config.commands) cmd.AddChatCommand(command, this, nameof(DiscordCommand)); LoadData(); discordLink.AddLinkPlugin(this); DiscordSettings settings = new DiscordSettings() { ApiToken = config.token, Intents = GatewayIntents.Guilds | GatewayIntents.GuildMembers | GatewayIntents.GuildMessages | GatewayIntents.DirectMessages, LogLevel = Ext.Discord.Logging.DiscordLogLevel.Info }; discordClient.Connect(settings); } private void Unload() { discordClient.Disconnect(); SaveData(); } private void OnPlayerConnected(BasePlayer player) { if (discordLink.IsLinked(player.UserIDString)) SynchronizeDiscord(player.UserIDString); else if (config.rustGroupId != "") permission.RemoveUserGroup(player.UserIDString, config.rustGroupId); } private void OnDiscordGatewayReady(GatewayReadyEvent ready) { if (!ready.Guilds.Any()) { PrintWarning("CANNOT FIND BOT ON ANY SERVER. BOT NEEDS TO BE CONNECTED TO ONLY 1 SERVER. UNLOADING PLUGIN..."); Server.Command($"o.unload {Name}"); return; } discordGuild = ready.Guilds.First().Value; if (config.playerCount) { UpdateStatus(); timer.Every(60, () => UpdateStatus()); } foreach (var player in BasePlayer.activePlayerList) if (discordLink.IsLinked(player.UserIDString)) SynchronizeDiscord(player.UserIDString); } private void OnDiscordGuildMembersLoaded() { if (config.chatChannel != 0) chatChannel = discordGuild.Channels.FirstOrDefault(c => c.Value.Id == config.chatChannel).Value; else { Unsubscribe(nameof(OnPlayerChat)); Unsubscribe(nameof(OnDiscordGuildMessageCreated)); } initialized = true; } private void OnDiscordDirectMessageCreated(DiscordMessage message, DiscordChannel channel) { if (!initialized) return; if (message.Author.Id == discordClient.Bot.BotUser.Id) return; if (channel == null) { message.Author.CreateDirectMessageChannel(discordClient, callback => OnDiscordDirectMessageCreated(message, callback)); return; } if (discordLink.IsLinked(message.Author)) { IPlayer linkedUser = message.Author.Player; DiscordEmbed embed = new DiscordEmbed() { Title = Lang("Discord_AlreadyConnectedTitle", linkedUser.Id), Description = Lang("Discord_AlreadyConnectedDescription", linkedUser.Id), Color = DiscordColor.DarkGreen, Thumbnail = new EmbedThumbnail() { Url = "https://i.imgur.com/cfjOqfm.png" } }; channel.CreateMessage(discordClient, embed); } else if (authCodes.ContainsKey(message.Content)) { IPlayer player = covalence.Players.FindPlayerById(authCodes[message.Content]); discordLink.OnLinked(this, player, message.Author); DiscordEmbed embed = new DiscordEmbed() { Title = Lang("Discord_ConnectedTitle", player.Id), Description = Lang("Discord_ConnectedDescription", player.Id), Color = DiscordColor.DarkGreen, Thumbnail = new EmbedThumbnail() { Url = "https://i.imgur.com/cfjOqfm.png" } }; SynchronizeDiscord(player.Id); channel.CreateMessage(discordClient, embed); } else { DiscordEmbed embed = new DiscordEmbed() { Title = Lang("Discord_FailureTitle"), Description = Lang("Discord_FailureDescription", null, message.Content, config.commands.First()), Color = DiscordColor.DarkRed, Thumbnail = new EmbedThumbnail() { Url = "https://i.imgur.com/O2Gt3DL.png" } }; channel.CreateMessage(discordClient, embed); } } private void OnDiscordGuildMessageCreated(DiscordMessage message, DiscordChannel channel) { if (!initialized) return; if (message.Author.Id == discordClient.Bot.BotUser.Id) return; if (channel.Id == config.chatChannel) { if (!discordLink.IsLinked(message.Author.Id)) return; IPlayer player = discordLink.GetPlayer(message.Author.Id); foreach (var onlinePlayer in BasePlayer.activePlayerList) onlinePlayer.SendConsoleCommand($"chat.add 0 {player.Id} \"{string.Format(config.chatFormat, player.Name, message.Content)}\""); Puts($"[DTR Chat] [Discord] {player.Name} » {message.Content}"); } } private void OnPlayerChat(BasePlayer player, string message, Chat.ChatChannel channel) { if (!initialized) return; if (channel != 0) return; if (message.Contains("@everyone") || message.Contains("@here")) return; chatChannel.CreateMessage(discordClient, string.Format(config.discordChatFormat, player.displayName, message)); } private void DiscordCommand(BasePlayer player, string command, string[] args) { if (!initialized) return; if (data.userData.ContainsKey(player.UserIDString)) { if (args.Length == 0) { SendReply(player, Lang("Game_AlreadyConnected", player.UserIDString)); } else if (args.Length == 1 && args[0].ToLower() == "dc") { DiscordUser user = discordLink.GetLinkedMember(player.UserIDString, discordGuild)?.User; if (user != null) { discordLink.OnUnlinked(this, player.IPlayer, user); if (config.discordGroupId != 0) discordGuild.RemoveGuildMemberRole(discordClient, user.Id, config.discordGroupId); } if (config.rustGroupId != "") permission.RemoveUserGroup(player.UserIDString, config.rustGroupId); data.userData.Remove(player.UserIDString); SendReply(player, Lang("Game_Unlinked", player.UserIDString)); } return; } if (authCodes.ContainsValue(player.UserIDString)) { SendReply(player, Lang("Game_AlreadyGenerated", player.UserIDString, authCodes.FirstOrDefault(x => x.Value == player.UserIDString).Key), discordClient.Bot.BotUser.GetFullUserName); return; } string code = $"{Random.Range(100000, 999999)}"; if (authCodes.ContainsValue(code)) { DiscordCommand(player, command, args); return; } authCodes.Add(code, player.UserIDString); SendReply(player, Lang("Game_CodeGenerated", player.UserIDString, code, discordClient.Bot.BotUser.GetFullUserName)); } private void API_SendPrivateMessage(string userId, string message) { if (!initialized) return; if (discordLink.IsLinked(userId)) { DiscordUser user = discordLink.GetDiscordUser(userId); if (user != null) user.CreateDirectMessageChannel(discordClient, callback1 => callback1.CreateMessage(discordClient, message)); } } private void API_SendMessage(string channelId, string message) { if (!initialized) return; DiscordChannel channel = discordGuild.Channels[(Snowflake)channelId]; channel.CreateMessage(discordClient, message); } private void UpdateStatus() { UpdatePresenceCommand status = new UpdatePresenceCommand { Afk = false, Since = 0, Status = UserStatusType.Online, Activities = new List() { new DiscordActivity() { Type = ActivityType.Game, Name = $"{BasePlayer.activePlayerList.Count}/{ConVar.Server.maxplayers}" } } }; discordClient.Bot.UpdateStatus(status); } private void SynchronizeDiscord(string userId) { IPlayer player = covalence.Players.FindPlayerById(userId); Snowflake discordId = (Snowflake)discordLink.GetDiscordId(userId); if (config.rustGroupId != "") player.AddToGroup(config.rustGroupId); if (config.discordGroupId != "") discordGuild.AddGuildMemberRole(discordClient, discordId, config.discordGroupId); } protected override void LoadDefaultMessages() { lang.RegisterMessages(new Dictionary { ["Discord_AlreadyConnectedTitle"] = "You are connected!", ["Discord_AlreadyConnectedDescription"] = "Your account is already connected!", ["Discord_ConnectedTitle"] = "Verification Success!", ["Discord_ConnectedDescription"] = "Your account has been connected with discord\n**Congratulations!**", ["Discord_FailureTitle"] = "Verification Failure!", ["Discord_FailureDescription"] = "**{0}** is not valid code! Write **/{1}** in-game to generate new code or send the correct one!", ["Game_AlreadyConnected"] = "Your account is already connected with our Discord!", ["Game_AlreadyGenerated"] = "Your code is already generated!\nYour code: {0}\n\nSend this code in private message to {1} BOT on Server's Discord. (/info)", ["Game_CodeGenerated"] = "You've generated your connect code!\nYour code: {0}\n\nSend this code in private message to {1} BOT on Server's Discord. (/info)", ["Game_Unlinked"] = "You've unlinked your account from Discord server.\nYou can reconnect it again using /discord command." }, this); } private string Lang(string key, string id = null, params object[] args) => string.Format(lang.GetMessage(key, this, id), args); private PluginConfig config = new PluginConfig(); protected override void LoadDefaultConfig() { Config.WriteObject(config = new PluginConfig() { commands = new List() { "discord", "dc", "connect" } }, true); } private class PluginConfig { [JsonProperty("BOT API Token")] public string token = "Paste Token Here!"; [JsonProperty("Commands")] public List commands = new List(); [JsonProperty("Show Player Count In Status")] public bool playerCount = false; [JsonProperty("Connect Granted - Discord Group ID")] public Snowflake discordGroupId = (Snowflake)0; [JsonProperty("Connect Granted - RUST Group Name")] public string rustGroupId = ""; [JsonProperty("RUST Chat - Discord Channel ID")] public Snowflake chatChannel = (Snowflake)0; [JsonProperty("RUST Chat - Discord Output Format")] public string discordChatFormat = "**{0}** » *{1}*"; [JsonProperty("RUST Chat - RUST Output Format")] public string chatFormat = "[Discord] {0} » {1}"; } private static PluginData data = new PluginData(); public class PluginData { [JsonProperty("User Data")] public Dictionary userData = new Dictionary(); } private void LoadData() { data = Interface.Oxide.DataFileSystem.ReadObject(Name); timer.Every(Random.Range(500, 700), SaveData); } private void SaveData() => Interface.Oxide.DataFileSystem.WriteObject(Name, data); } }