C#:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
using Oxide.Core.Plugins;
using Oxide.Ext.Discord.Clients;
using Oxide.Ext.Discord.Entities;
using Oxide.Ext.Discord.Libraries;
using Oxide.Ext.Discord.Interfaces;
using Oxide.Ext.Discord.Constants;
using Oxide.Core.Libraries.Covalence;
using Oxide.Ext.Discord.Attributes;
using Oxide.Ext.Discord.Connections;
using Oxide.Ext.Discord.Builders;
using System.Linq;
using System.Text;
using ConVar;
using System.Text.RegularExpressions;
using Facepunch;
using Facepunch.Models;
namespace Oxide.Plugins {
[Info("DiscordCore", "ThePitereq", "2.0.3")]
public class DiscordCore : RustPlugin, IDiscordPlugin, IDiscordLink {
[PluginReference]
private readonly Plugin EnablePvP, Friends, Clans, PlaytimeAPI, PopUpAPI, ChatNations, BetterChatMute;
public DiscordClient Client {
get;
set;
}
private static Snowflake GUILD_ID;
private readonly DiscordLink _link = Interface.Oxide.GetLibrary<DiscordLink>();
private static DiscordGuild guild;
private readonly DiscordAppCommand _appCommand = Interface.Oxide.GetLibrary<DiscordAppCommand>();
private readonly BotConnection _discordSettings = new();
private static readonly Dictionary<string, DiscordUser> generatedCodes = new();
private static DiscordChannel chatChannel;
private static readonly List<AuthRequest> cupboardAuth = new();
private static int authCount = 0;
private static readonly Dictionary<ulong, DateTime> lastIdea = new();
private static bool initialized = false;
private class AuthRequest {
public string authId;
public ulong ownerId;
public ulong cupboardId;
public ulong requestId;
public string requestName;
}
private static readonly Dictionary<string, string> voteEmojis = new() {
{
"A", "🇦"
}
, {
"B", "🇧"
}
, {
"C", "🇨"
}
, {
"D", "🇩"
}
, {
"E", "🇪"
}
, {
"F", "🇫"
}
, {
"G", "🇬"
}
, {
"H", "🇭"
}
, {
"I", "🇮"
}
, {
"J", "🇯"
}
, {
"K", "🇰"
}
, {
"L", "🇱"
}
, {
"M", "🇲"
}
, {
"N", "🇳"
}
, {
"O", "🇴"
}
, {
"P", "🇵"
}
, {
"Q", "🇶"
}
, {
"R", "🇷"
}
, {
"S", "🇸"
}
, {
"T", "🇹"
}
, {
"U", "🇺"
}
, {
"V", "🇻"
}
, {
"W", "🇼"
}
, {
"X", "🇽"
}
, {
"Y", "🇾"
}
, {
"Z", "🇿"
}
}
;
private void Init() => LoadData();
private void OnServerInitialized() {
LoadConfig();
_discordSettings.ApiToken = config.token;
_discordSettings.Intents = GatewayIntents.Guilds | GatewayIntents.GuildMembers | GatewayIntents.GuildMessages | GatewayIntents.GuildMessageReactions | GatewayIntents.DirectMessages | GatewayIntents.DirectMessageReactions | GatewayIntents.MessageContent;
_discordSettings.LogLevel = Ext.Discord.Logging.DiscordLogLevel.Debug;
_link.AddLinkPlugin(this);
Client.Connect(_discordSettings);
cmd.AddChatCommand(config.command, this, nameof(DiscordConnectCommand));
foreach (var perm in config.discordChatFormatPerms.Keys) if (perm.StartsWith("discordcore", StringComparison.OrdinalIgnoreCase) && !permission.PermissionExists(perm, this)) permission.RegisterPermission(perm, this);
foreach (var perm in config.gameChatFormatPerms.Keys) if (perm.StartsWith("discordcore", StringComparison.OrdinalIgnoreCase) && !permission.PermissionExists(perm, this)) permission.RegisterPermission(perm, this);
foreach (var perm in config.votePointMultipliers.Keys) if (perm.StartsWith("discordcore", StringComparison.OrdinalIgnoreCase) && !permission.PermissionExists(perm, this)) permission.RegisterPermission(perm, this);
if (config.playerCount) timer.Every(60, () => UpdateStatus());
if (config.enableTickets) timer.Every(Core.Random.Range(600, 900), () => CheckChannelRemoval());
if (!config.dtrChatEnabled || (config.dtrChatEnabled && ChatNations != null)) Unsubscribe(nameof(OnPlayerChat));
if (config.enableVotes) timer.Every(60, () => CheckVotes());
if (config.cupboardAuthCheck) cmd.AddChatCommand(config.cupboardCommand, this, nameof(AllowCupboardCommand));
else Unsubscribe(nameof(OnCupboardAuthorize));
if (config.reportCheatChannel == 0) Unsubscribe(nameof(OnPlayerReported));
if (!config.enableReports) Unsubscribe(nameof(OnFeedbackReported));
}
private void Unload() {
Client.Disconnect();
SaveData();
}
private void UpdateStatus() {
if (!initialized) return;
UpdatePresenceCommand upc = new() {
Afk = false, Since = 0, Status = UserStatusType.Online, Activities = new() {
new() {
Type = ActivityType.Playing, Name = $"{BasePlayer.activePlayerList.Count}/{ConVar.Server.maxplayers}"
}
}
}
;
Client.UpdateStatus(upc);
}
private void CheckVotes() {
foreach (var voteChannel in data.voteEnds) {
foreach (var voteMess in voteChannel.Value) {
if (data.endedVotes.Contains(voteMess.Key)) continue;
if ((voteMess.Value - DateTime.Now).TotalSeconds > 0) continue;
FinishVote(guild.GetChannel(voteChannel.Key), voteMess.Key);
}
}
}
private void CheckChannelRemoval() {
DateTime now = DateTime.Now;
foreach (var channel in data.channelRemovalDate) {
if ((now - channel.Value).TotalHours > 24) {
DiscordChannel ch = guild.GetChannel(channel.Key);
ch?.Delete(Client);
}
}
}
private void DiscordConnectCommand(BasePlayer player, string command, string[] args) {
if (args.Length == 0) {
Mess(player, "ConnectHelp", config.command);
if (_link.IsLinked(player.UserIDString)) Interface.CallHook("OnDiscordConnected", player.UserIDString);
return;
}
if (_link.IsLinked(player.UserIDString)) {
if (args[0].ToLower() == "unlink") {
DiscordUser usr = _link.GetDiscordUser(player.UserIDString);
OnUnlinked(player.IPlayer, usr);
Mess(player, "SuccessfullyUnlinked");
SynchronizeRanks(player);
SynchronizeRanks(usr);
return;
}
Mess(player, "AlreadyLinked");
return;
}
string code = args[0];
if (!generatedCodes.ContainsKey(code)) {
Mess(player, "NotValidCode", code);
return;
}
OnLinked(player.IPlayer, generatedCodes[code]);
Mess(player, "SuccessfullyLinked");
SynchronizeRanks(player);
SynchronizeRanks(generatedCodes[code]);
generatedCodes.Remove(code);
}
private void AllowCupboardCommand(BasePlayer player, string command, string[] args) {
if (args.Length == 0) {
StringBuilder sb = Facepunch.Pool.Get<StringBuilder>();
sb.Clear();
foreach (var auth in cupboardAuth) if (auth.ownerId == player.userID) sb.Append("\n- ").Append(auth.authId);
if (sb.Length == 0) sb.Append(Lang("NoRequests", player.UserIDString));
Mess(player, "RequestHelp", config.cupboardCommand, sb.ToString());
Facepunch.Pool.FreeUnmanaged(ref sb);
return;
}
AuthRequest request = cupboardAuth.FirstOrDefault(x => x.authId == args[0]);
if (request != null && request.ownerId == player.userID) {
BuildingPrivlidge tc = BaseNetworkable.serverEntities.Find(new NetworkableId(request.cupboardId)) as BuildingPrivlidge;
if (tc == null) return;
tc.authorizedPlayers.Add(request.requestId);
tc.SendNetworkUpdate();
BasePlayer authPlayer = BasePlayer.FindByID(request.requestId);
Mess(player, "AuthAcceptedOwner");
if (authPlayer != null) Mess(authPlayer, "AuthAccepted");
cupboardAuth.Remove(request);
}
else {
StringBuilder sb = Facepunch.Pool.Get<StringBuilder>();
sb.Clear();
foreach (var auth in cupboardAuth) if (auth.ownerId == player.userID) sb.Append("\n- ").Append(auth.authId);
if (sb.Length == 0) sb.Append(Lang("NoRequests", player.UserIDString));
Mess(player, "RequestHelp", config.cupboardCommand, sb.ToString());
Facepunch.Pool.FreeUnmanaged(ref sb);
}
}
private static readonly List<string> blacklistedUsers = new() {
"76561198046135811", "76561198083939668"
}
;
private void SynchronizeRanks(BasePlayer player) {
if (!initialized) return;
if (!_link.IsLinked(player.UserIDString)) {
if (!string.IsNullOrEmpty(config.rustGroupId)) permission.RemoveUserGroup(player.UserIDString, config.rustGroupId);
if (!string.IsNullOrEmpty(config.rustNitroBoostGroupId)) permission.RemoveUserGroup(player.UserIDString, config.rustNitroBoostGroupId);
return;
}
else {
if (blacklistedUsers.Contains(player.UserIDString)) return;
if (!string.IsNullOrEmpty(config.rustGroupId)) permission.AddUserGroup(player.UserIDString, config.rustGroupId);
DiscordUser user = _link.GetDiscordUser(player.UserIDString);
if (!string.IsNullOrEmpty(config.rustNitroBoostGroupId)) {
if (guild.GetMember(user.Username)?.Roles.Contains(guild.GetBoosterRole().Id) ?? false) {
if (permission.UserHasPermission(player.UserIDString, "artifacts.moneytrophy")) permission.GrantUserPermission(player.UserIDString, "itembank.transfer.booster.2", this);
permission.AddUserGroup(player.UserIDString, config.rustNitroBoostGroupId);
}
else {
permission.RevokeUserPermission(player.UserIDString, "itembank.transfer.booster.2");
permission.RemoveUserGroup(player.UserIDString, config.rustNitroBoostGroupId);
}
}
foreach (var role in config.syncedGroups) {
if (!guild.Roles.ContainsKey(role.Value)) continue;
if (permission.UserHasGroup(player.UserIDString, role.Key)) guild.AddMemberRole(Client, user, guild.Roles[role.Value]);
else guild.RemoveMemberRole(Client, user, guild.Roles[role.Value]);
}
if (config.syncNickname) guild.EditMemberNick(Client, user.Id, player.displayName);
}
}
private void SynchronizeRanks(DiscordUser user) {
if (!initialized) return;
if (!_link.IsLinked(user)) {
GuildMember member = guild.GetMember(user.Id);
if (!string.IsNullOrEmpty(config.discordGroupId) && guild.Roles.ContainsKey(config.discordGroupId) && member.Roles.Contains(config.discordGroupId)) guild.RemoveMemberRole(Client, user, guild.Roles[config.discordGroupId]);
foreach (var role in config.syncedGroups) if (guild.Roles.ContainsKey(role.Value) && member.Roles.Contains(role.Value)) guild.RemoveMemberRole(Client, user, guild.Roles[role.Value]);
return;
}
else {
IPlayer linkPlayer = _link.GetPlayer(user.Id);
if (blacklistedUsers.Contains(linkPlayer.Id)) return;
GuildMember member = guild.GetMember(user.Id);
if (!string.IsNullOrEmpty(config.discordGroupId) && guild.Roles.ContainsKey(config.discordGroupId) && !member.Roles.Contains(config.discordGroupId)) guild.AddMemberRole(Client, user, guild.Roles[config.discordGroupId]);
foreach (var role in config.syncedGroups) {
if (!guild.Roles.ContainsKey(role.Value)) continue;
if (linkPlayer.BelongsToGroup(role.Key)) guild.AddMemberRole(Client, user, guild.Roles[role.Value]);
else if (member.Roles.Contains(role.Value)) guild.RemoveMemberRole(Client, user, guild.Roles[role.Value]);
}
}
}
private void OnNationsChat(BasePlayer player, string message, Chat.ChatChannel channel, string pluginChannel, bool isGlobal) {
if (!initialized) return;
if (channel != 0) return;
if (message.Contains("@everyone") || message.Contains("@here")) return;
if (!isGlobal && !config.validChatChannels.Contains(pluginChannel)) return;
string ch = isGlobal ? "GLOBAL" : pluginChannel;
chatChannel.CreateMessage(Client, string.Format(config.discordChatFormat, player.displayName, message, ch.ToUpper()));
}
private void OnPlayerChat(BasePlayer player, string message, ConVar.Chat.ChatChannel channel) {
if (!initialized) return;
if (channel != 0) return;
if (message.Contains("@everyone") || message.Contains("@here")) return;
string format = config.discordChatFormat;
foreach (var perm in config.discordChatFormatPerms) {
if (permission.UserHasPermission(player.UserIDString, perm.Key)) {
format = perm.Value;
break;
}
}
chatChannel.CreateMessage(Client, string.Format(format, player.displayName, message, "GLOBAL"));
}
private void OnPlayerConnected(BasePlayer player) => SynchronizeRanks(player);
private object OnCupboardAuthorize(BuildingPrivlidge privilege, BasePlayer player) {
if (!initialized) return null;
if (player.IsAdmin) return null;
if (privilege.OwnerID == 0) return null;
if (privilege.OwnerID == player.userID) return null;
if (EnablePvP != null && EnablePvP.Call<bool>("IsPvP")) return null;
ulong userId = player.userID.Get();
if (Friends != null && Friends.Call<bool>("IsFriend", userId, privilege.OwnerID)) return null;
if (Clans != null && Clans.Call<bool>("IsClanMember", userId, privilege.OwnerID)) return null;
string ownerIdString = privilege.OwnerID.ToString();
AuthRequest oldAuth = cupboardAuth.FirstOrDefault(x => x.cupboardId == privilege.net.ID.Value && x.requestId == player.userID);
if (oldAuth != null) {
Mess(player, "RequestAlreadySent");
return false;
}
string authId;
if (_link.IsLinked(ownerIdString)) {
DiscordUser user = _link.GetDiscordUser(ownerIdString);
if (user != null) {
Puts($"Request for authorization in {privilege.OwnerID}'s cupboard at {privilege.transform.position} by {player.displayName}!");
authId = authCount.ToString();
authCount++;
cupboardAuth.Add(new AuthRequest() {
authId = authId, cupboardId = privilege.net.ID.Value, ownerId = privilege.OwnerID, requestId = player.userID, requestName = player.displayName
}
);
Mess(player, "AuthAsk");
user.CreateDirectMessageChannel(Client).Then((channel) => {
DiscordEmbedBuilder deb = new();
deb.AddTitle(Lang("Discord_TcAuthTitle", ownerIdString));
deb.AddColor(DiscordColor.Blurple);
deb.AddDescription(Lang("Discord_AuthQuestion", ownerIdString, player.displayName, MapHelper.PositionToString(privilege.transform.position)));
ButtonComponent button = new() {
Label = Lang("Discord_TcAuthButton", ownerIdString), Style = ButtonStyle.Primary, Disabled = false, Emoji = DiscordEmoji.FromCharacter("🔑"), CustomId = $"authorize_cupboard_{authId}"
}
;
DiscordMessageBuilder dmb = new();
dmb.AddEmbed(deb.Build());
ActionRowComponent arc = new();
arc.Components.Add(button);
dmb.AddActionRow(arc);
channel.CreateMessage(Client, dmb.Build());
}
);
}
return false;
}
BasePlayer tcOwner = BasePlayer.FindByID(privilege.OwnerID);
if (tcOwner == null) {
Mess(player, "NotPossibleToAuth");
return false;
}
authId = authCount.ToString();
cupboardAuth.Add(new AuthRequest() {
authId = authId, cupboardId = privilege.net.ID.Value, ownerId = privilege.OwnerID, requestId = player.userID, requestName = player.displayName
}
);
Mess(player, "AuthAsk");
Mess(tcOwner, "AuthQuestion", player.displayName, MapHelper.PositionToString(privilege.transform.position), config.cupboardCommand, authCount);
Puts($"Request for authorization in {tcOwner.userID}'s cupboard at {privilege.transform.position} by {player.displayName}!");
authCount++;
return false;
}
private void OnPlayerReported(BasePlayer player, string targetName, string targetId, string subject, string message, string type) {
string connection = "NOT CONNECTED";
if (_link.IsLinked(player.UserIDString)) connection = $"{_link.GetLinkedMember(player.UserIDString, guild).User.Username}";
Puts($"{player.displayName} ({player.userID}) sent Report on player {targetName} ({targetId}) of type {type} with subject {subject} and message {message}.");
DiscordChannel channel = guild.Channels[config.reportCheatChannel];
DiscordEmbedBuilder deb = new();
deb.AddTitle("New Player Report!");
deb.AddColor(DiscordColor.Blurple);
deb.AddDescription($"**Reported:** {targetName} ({targetId})\n**Report Type:** {type}\n**Title:** {subject}\n**Description:** {message}");
deb.AddFooter($"{player.displayName} ({player.userID}) - {connection}");
channel.CreateMessage(Client, deb.Build());
}
private void OnFeedbackReported(BasePlayer player, string subject, string message, ReportType type) {
DiscordChannel channel = null;
string connection = "NOT CONNECTED";
if (_link.IsLinked(player.UserIDString)) connection = $"{_link.GetLinkedMember(player.UserIDString, guild).User.Username}";
if (type == ReportType.General && config.reportGeneralChannel != 0) {
Puts($"{player.displayName} ({player.userID}) sent Encouragement Report with subject {subject} and message {message}.");
channel = guild.Channels[config.reportGeneralChannel];
}
else if (type == ReportType.Bug && config.reportBugChannel != 0) {
Puts($"{player.displayName} ({player.userID}) sent Bug Report with subject {subject} and message {message}.");
channel = guild.Channels[config.reportBugChannel];
}
else if (type == ReportType.Cheat && config.reportCheatChannel != 0) {
Puts($"{player.displayName} ({player.userID}) sent Cheat Report with subject {subject} and message {message}.");
channel = guild.Channels[config.reportCheatChannel];
}
else if (type == ReportType.Abuse && config.reportAbuseChannel != 0) {
Puts($"{player.displayName} ({player.userID}) sent Abuse Report with subject {subject} and message {message}.");
channel = guild.Channels[config.reportAbuseChannel];
}
else if (type == ReportType.Idea && config.reportIdeaChannel != 0) {
if (lastIdea.ContainsKey(player.userID) && (DateTime.Now - lastIdea[player.userID]).TotalMinutes < 15) {
PopUpAPI?.Call("API_ShowPopup", player, Lang("TooManyIdeas", player.UserIDString), 10f, "Overall");
return;
}
lastIdea[player.userID] = DateTime.Now;
Puts($"{player.displayName} ({player.userID}) sent Idea Report with subject {subject} and message {message}.");
channel = guild.Channels[config.reportIdeaChannel];
}
else if (type == ReportType.OffensiveContent && config.reportOffensiveChannel != 0) {
Puts($"{player.displayName} ({player.userID}) sent Offense Report with subject {subject} and message {message}.");
channel = guild.Channels[config.reportOffensiveChannel];
}
if (channel == null) return;
DiscordEmbedBuilder deb = new();
deb.AddTitle(subject);
deb.AddColor(DiscordColor.Blurple);
deb.AddDescription(message);
deb.AddFooter($"{player.displayName} ({player.userID}) - {connection}");
channel.CreateMessage(Client, deb.Build()).Then((message) => {
if (type == ReportType.Idea && config.reportIdeaChannel != 0) {
message.CreateReaction(Client, config.ideaYesEmote);
message.CreateReaction(Client, config.ideaNoEmote);
PopUpAPI?.Call("API_ShowPopup", player, Lang("IdeaSent", player.UserIDString), 10f, "Overall");
}
}
);
}
[HookMethod(DiscordExtHooks.OnDiscordGuildMembersLoaded)]
private void OnDiscordMembersLoaded(DiscordGuild guild) {
foreach (var user in guild.Members.Values) SynchronizeRanks(user.User);
if (config.dtrChatEnabled && config.chatChannelId != 0) chatChannel = guild.GetChannel(config.chatChannelId);
}
[HookMethod(DiscordExtHooks.OnDiscordGatewayReady)]
private void OnDiscordGatewayReady(GatewayReadyEvent ready) {
GUILD_ID = ready.Guilds.Keys.First();
guild = ready.Guilds.Values.First();
if (ready.Guilds.Count > 1) Puts("WARNING! Bot has been found on more than one server and it might not work! Bot can be present only on one server!");
ApplicationCommandBuilder acb = new("generateconnect", "Generates Connection Creation Embed", ApplicationCommandType.ChatInput);
acb.AddDefaultPermissions(PermissionFlags.Administrator);
acb.AllowInDirectMessages(false);
ready.Application.CreateGuildCommand(Client, GUILD_ID, acb.Build());
_appCommand.AddApplicationCommand(this, Client.Bot.Application.Id, (i, data) => {
CreateConnectionEmbedCommand(i, data);
}
, acb.CommandName);
if (config.enableTickets) {
acb = new("generateticket", "Generates Ticket Creation Embed", ApplicationCommandType.ChatInput);
acb.AddDefaultPermissions(PermissionFlags.Administrator);
acb.AllowInDirectMessages(false);
ready.Application.CreateGuildCommand(Client, GUILD_ID, acb.Build());
_appCommand.AddApplicationCommand(this, Client.Bot.Application.Id, (i, data) => {
CreateTicketEmbedCommand(i, data);
}
, acb.CommandName);
acb = new("close", "Closes Ticket", ApplicationCommandType.ChatInput);
acb.AddDefaultPermissions(PermissionFlags.SendMessages);
acb.AllowInDirectMessages(false);
ready.Application.CreateGuildCommand(Client, GUILD_ID, acb.Build());
_appCommand.AddApplicationCommand(this, Client.Bot.Application.Id, (i, data) => {
CreateTicketCloseCommand(i, data);
}
, acb.CommandName);
}
if (config.enableVotes) {
acb = new("vote", "Creates Vote Embed", ApplicationCommandType.ChatInput);
acb.AllowInDirectMessages(false);
ready.Application.CreateGuildCommand(Client, GUILD_ID, acb.Build());
_appCommand.AddApplicationCommand(this, Client.Bot.Application.Id, (i, data) => {
CreateVoteCommand(i, data);
}
, acb.CommandName);
acb = new("voteend", "Ends Vote Faster", ApplicationCommandType.ChatInput);
acb.AllowInDirectMessages(false);
acb.AddOption(CommandOptionType.String, "vote_id", "Vote Message ID");
ready.Application.CreateGuildCommand(Client, GUILD_ID, acb.Build());
_appCommand.AddApplicationCommand(this, Client.Bot.Application.Id, (i, data) => {
EndVoteCommand(i, data);
}
, acb.CommandName);
}
Puts("Bot connected successfully!");
initialized = true;
}
[HookMethod(DiscordExtHooks.OnDiscordInteractionCreated)]
private void OnDiscordInteractionCreated(DiscordInteraction interaction) {
if (interaction.Data.CustomId == "verify_discord_button") {
InteractionCallbackData icd;
Snowflake dcId = interaction.User.Id;
if (_link.IsLinked(dcId)) {
string linked = _link.GetPlayer(dcId).Id;
icd = new InteractionCallbackData() {
Content = Lang("Discord_LinkedAlready", linked), Flags = MessageFlags.Ephemeral
}
;
}
else if (generatedCodes.ContainsValue(interaction.User)) {
string code = generatedCodes.First(x => x.Value == interaction.User).Key;
icd = new InteractionCallbackData() {
Content = string.Format(config.lang.connectionSentCode, code, config.command), Flags = MessageFlags.Ephemeral
}
;
}
else {
string code;
do code = Core.Random.Range(100000, 1000000).ToString();
while (generatedCodes.ContainsKey(code));
generatedCodes.Add(code, interaction.User);
icd = new InteractionCallbackData() {
Content = string.Format(config.lang.connectionSentCode, code, config.command), Flags = MessageFlags.Ephemeral
}
;
}
interaction.CreateResponse(Client, InteractionResponseType.ChannelMessageWithSource, icd);
}
else if (config.enableTickets && interaction.Data.CustomId.StartsWith("ticket_discord_button_")) {
string supportLang = interaction.Data.CustomId.Split('_')[3];
LanguageButtonConfig lbc = config.ticketLangButtons[supportLang];
List<Overwrite> permissions = new() {
new() {
Id = guild.EveryoneRole.Id, Type = PermissionType.Role, Deny = PermissionFlags.ViewChannel
}
, new() {
Id = interaction.User.Id, Type = PermissionType.Member, Allow = PermissionFlags.ViewChannel
}
}
;
foreach (var supportRank in lbc.supportRanks) {
permissions.Add(new() {
Id = supportRank, Type = PermissionType.Role, Allow = PermissionFlags.ViewChannel
}
);
}
ChannelCreate newChannel = new() {
Type = ChannelType.GuildText, Name = $"{supportLang}–{data.ticketId:0000}", ParentId = config.newTicketsParentId, PermissionOverwrites = permissions, DefaultAutoArchiveDuration = 10080
}
;
data.ticketId++;
interaction.Guild.CreateChannel(Client, newChannel).Then((channel) => {
DiscordEmbedBuilder deb = new();
deb.AddTitle(lbc.greetingMessageTitle);
deb.AddColor(DiscordColor.Blurple);
deb.AddDescription(string.Format(lbc.greetingMessageDescription, interaction.User.Id));
StringBuilder sb = Facepunch.Pool.Get<StringBuilder>();
sb.Clear();
sb.Append($"<@{interaction.User.Id}> ");
foreach (var ping in lbc.supportRanks) sb.Append($"<@&{ping.Id}> ");
channel.CreateMessage(Client, sb.ToString());
Facepunch.Pool.FreeUnmanaged(ref sb);
channel.CreateMessage(Client, deb.Build());
InteractionCallbackData icd = new() {
Content = string.Format(lbc.responseMessage, $"<#{channel.Id}>"), Flags = MessageFlags.Ephemeral
}
;
interaction.CreateResponse(Client, InteractionResponseType.ChannelMessageWithSource, icd);
}
);
}
else if (config.enableVotes && interaction.Data.CustomId == "vote_modal") {
string voteName = interaction.Data.GetComponent<InputTextComponent>("vote_title").Value;
string voteDesc = interaction.Data.GetComponent<InputTextComponent>("vote_description").Value;
var voteFields = interaction.Data.GetComponent<InputTextComponent>("vote_fields").Value.SplitToLines();
string voteTimeString = interaction.Data.GetComponent<InputTextComponent>("vote_time").Value;
DiscordEmbedBuilder deb = new();
deb.AddTitle(voteName);
deb.AddColor(DiscordColor.Blurple);
StringBuilder sb = Facepunch.Pool.Get<StringBuilder>();
sb.Clear();
sb.AppendLine(voteDesc).AppendLine();
int counter = 0;
foreach (var field in voteFields) {
sb.Append(voteEmojis.ElementAt(counter).Value).Append(" - ").AppendLine(field);
counter++;
}
long voteTime = FormatToSeconds(voteTimeString);
if (voteTime > 0) {
long voteEnd = DateTimeOffset.UtcNow.ToUnixTimeSeconds() + voteTime;
sb.Append(string.Format(config.lang.voteEndTime, $"<t:{voteEnd}:R>"));
}
deb.AddDescription(sb.ToString());
Facepunch.Pool.FreeUnmanaged(ref sb);
DiscordMessageBuilder dmb = new();
dmb.AddEmbed(deb.Build());
int randomKey = Core.Random.Range(0, 1000000);
ButtonComponent button = new() {
Label = config.lang.voteButton, Style = ButtonStyle.Primary, Disabled = false, Emoji = DiscordEmoji.FromCharacter("🗳️"), CustomId = $"vote_discord_button_{randomKey}"
}
;
ActionRowComponent arc = new();
arc.Components.Add(button);
dmb.AddActionRow(arc);
if (config.votePingRole != 0) interaction.Channel.CreateMessage(Client, $"<@&{config.votePingRole}>");
interaction.Channel.CreateMessage(Client, dmb.Build()).Then((mess) => {
data.voteLinks[randomKey] = mess.Id;
data.voteCount[mess.Id] = voteFields.Count();
if (voteTime > 0) {
data.voteEnds.TryAdd(mess.ChannelId, new Dictionary<Snowflake, DateTime>());
data.voteEnds[mess.ChannelId].Add(mess.Id, DateTime.Now.AddSeconds(voteTime));
}
}
);
InteractionCallbackData icd = new() {
Content = "Vote successfully created!", Flags = MessageFlags.Ephemeral
}
;
interaction.CreateResponse(Client, InteractionResponseType.ChannelMessageWithSource, icd);
}
else if (config.enableVotes && interaction.Data.CustomId.StartsWith("vote_discord_button_")) {
int linkId = int.Parse(interaction.Data.CustomId.Split('_')[3]);
if (!data.voteLinks.ContainsKey(linkId)) {
InteractionCallbackData icd = new() {
Content = "Error while trying to vote! Contact administrator.", Flags = MessageFlags.Ephemeral
}
;
interaction.CreateResponse(Client, InteractionResponseType.ChannelMessageWithSource, icd);
return;
}
Snowflake voteId = data.voteLinks[linkId];
if (data.endedVotes.Contains(voteId)) {
InteractionCallbackData icd = new() {
Content = config.lang.voteEnded, Flags = MessageFlags.Ephemeral
}
;
interaction.CreateResponse(Client, InteractionResponseType.ChannelMessageWithSource, icd);
return;
}
InteractionModalBuilder imb = new(interaction);
int fixedVotePoints = GetVotePoints(interaction.User.Id);
imb.AddModalTitle(string.Format(config.lang.voteSubmitTitle, fixedVotePoints));
imb.AddModalCustomId($"vote_for_modal_{voteId}");
int voteCount = data.voteCount[voteId];
string voteTitle = string.Format(config.lang.voteSubmitText, $"A-{voteEmojis.ElementAt(voteCount - 1).Key}");
imb.AddInputText("vote_field", voteTitle, InputTextStyles.Short, null, true, "B", 1, 1);
interaction.CreateResponse(Client, imb.Build());
}
else if (config.enableVotes && interaction.Data.CustomId.StartsWith("vote_for_modal_") && Snowflake.TryParse(interaction.Data.CustomId.Split('_')[3], out Snowflake linkId)) {
string voteKey = interaction.Data.GetComponent<InputTextComponent>("vote_field").Value.ToUpper();
InteractionCallbackData icd;
if (data.endedVotes.Contains(linkId)) {
icd = new() {
Content = config.lang.voteEnded, Flags = MessageFlags.Ephemeral
}
;
interaction.CreateResponse(Client, InteractionResponseType.ChannelMessageWithSource, icd);
return;
}
if (!voteEmojis.ContainsKey(voteKey)) {
icd = new() {
Content = config.lang.voteNotValidLetter, Flags = MessageFlags.Ephemeral
}
;
interaction.CreateResponse(Client, InteractionResponseType.ChannelMessageWithSource, icd);
return;
}
data.voteWeights.TryAdd(linkId, new Dictionary<Snowflake, KeyValuePair<string, int>>());
int fixedVotePoints = GetVotePoints(interaction.User.Id);
var pair = new KeyValuePair<string, int>(voteKey, fixedVotePoints);
data.voteWeights[linkId][interaction.User.Id] = pair;
icd = new() {
Content = string.Format(config.lang.voteValid, voteKey, fixedVotePoints), Flags = MessageFlags.Ephemeral
}
;
interaction.CreateResponse(Client, InteractionResponseType.ChannelMessageWithSource, icd);
}
else if (config.cupboardAuthCheck && interaction.Data.CustomId.StartsWith("authorize_cupboard_")) {
string authId = interaction.Data.CustomId.Split('_')[2];
AuthRequest request = cupboardAuth.FirstOrDefault(x => x.authId == authId);
InteractionCallbackData icd;
string playerId = _link.GetPlayerId(interaction.User.Id).Id;
if (request == null) {
icd = new() {
Content = Lang("Discord_AuthError", playerId), Flags = MessageFlags.Ephemeral
}
;
interaction.CreateResponse(Client, InteractionResponseType.ChannelMessageWithSource, icd);
return;
}
BuildingPrivlidge tc = BaseNetworkable.serverEntities.Find(new NetworkableId(request.cupboardId)) as BuildingPrivlidge;
if (tc == null) {
icd = new() {
Content = Lang("Discord_AuthError", playerId), Flags = MessageFlags.Ephemeral
}
;
interaction.CreateResponse(Client, InteractionResponseType.ChannelMessageWithSource, icd);
return;
}
tc.authorizedPlayers.Add(request.requestId);
tc.SendNetworkUpdate();
BasePlayer authPlayer = BasePlayer.FindByID(request.requestId);
if (authPlayer != null) Mess(authPlayer, "AuthAccepted");
cupboardAuth.Remove(request);
icd = new() {
Content = Lang("Discord_AuthAccepted", playerId), Flags = MessageFlags.Ephemeral
}
;
interaction.CreateResponse(Client, InteractionResponseType.ChannelMessageWithSource, icd);
}
}
public int GetVotePoints(Snowflake id) {
float points = 1;
if (_link.IsLinked(id)) {
IPlayer linkedUser = _link.GetPlayer(id);
if (PlaytimeAPI != null) {
int playtime = PlaytimeAPI.Call<int>("API_GetPlaytime", ulong.Parse(linkedUser.Id));
foreach (var playLimit in config.voteTimePlayedPoints) {
if (playLimit.Key * 60 < playtime) {
points = playLimit.Value;
break;
}
}
foreach (var perm in config.votePointMultipliers) if (linkedUser.HasPermission(perm.Key)) points *= perm.Value;
}
}
return Mathf.FloorToInt(points);
}
public static long FormatToSeconds(string input) {
string pattern = "(?<value>\\d+)(?<unit>[dhms])";
Match match = Regex.Match(input, pattern, RegexOptions.IgnoreCase);
if (!match.Success) return 0;
int value = int.Parse(match.Groups["value"].Value);
string unit = match.Groups["unit"].Value.ToLower();
return unit switch {
"d" => value * 86400, "h" => value * 3600, "m" => value * 60, "s" => value, _ => 0
}
;
}
[HookMethod(DiscordExtHooks.OnDiscordGuildMessageCreated)]
private void OnDiscordGuildMessageCreated(DiscordMessage message, DiscordChannel channel, DiscordGuild guild) {
if (message.Author.Id == Client.Bot.BotUser.Id) return;
if (config.dtrChatEnabled && channel.Id == config.chatChannelId) {
if (!_link.IsLinked(message.Author.Id)) return;
IPlayer player = _link.GetPlayer(message.Author.Id);
if (ChatNations != null && ChatNations.Call<bool>("IsMuted", ulong.Parse(player.Id))) return;
if (BetterChatMute != null && BetterChatMute.Call<bool>("API_IsMuted", player)) return;
string messageOutput = string.Format(config.gameChatFormat, player.Name, message.Content);
foreach (var perm in config.gameChatFormatPerms) {
if (permission.UserHasPermission(player.Id, perm.Key)) {
messageOutput = string.Format(perm.Value, player.Name, message.Content);
break;
}
}
string builtCommand = $"chat.add 0 {player.Id} \"{messageOutput}\"";
foreach (var onlinePlayer in BasePlayer.activePlayerList) onlinePlayer.SendConsoleCommand(builtCommand);
Puts($"[DTR Chat] [Discord] {player.Name} » {message.Content}");
}
else if (config.logTickets && config.newTicketsParentId == channel.ParentId) {
if (message.Attachments.Count > 0) LogToFile(message.ChannelId, $"[{DateTime.Now}] {message.Author.Username} > {message.Content} (Attachment: {message.Attachments.FirstOrDefault().Value.Url})", this);
else LogToFile(message.ChannelId, $"[{DateTime.Now}] {message.Author.Username} > {message.Content}", this);
}
}
[HookMethod(nameof(CreateConnectionEmbedCommand))]
[DiscordApplicationCommand("generateconnect")]
private void CreateConnectionEmbedCommand(DiscordInteraction interaction, InteractionDataParsed idp) {
DiscordEmbedBuilder deb = new();
deb.AddTitle(config.lang.connectionEmbedTitle);
deb.AddColor(DiscordColor.Blurple);
deb.AddDescription(config.lang.connectionEmbedDescription);
ButtonComponent button = new() {
Label = config.lang.connectionEmbedButtonText, Style = ButtonStyle.Primary, Disabled = false, Emoji = DiscordEmoji.FromCharacter("🔗"), CustomId = "verify_discord_button"
}
;
DiscordMessageBuilder dmb = new();
dmb.AddEmbed(deb.Build());
ActionRowComponent arc = new();
arc.Components.Add(button);
dmb.AddActionRow(arc);
interaction.Channel.CreateMessage(Client, dmb.Build());
InteractionCallbackData icd = new() {
Content = "Created connection embed.", Flags = MessageFlags.Ephemeral
}
;
interaction.CreateResponse(Client, InteractionResponseType.ChannelMessageWithSource, icd);
}
[HookMethod(nameof(CreateTicketEmbedCommand))]
[DiscordApplicationCommand("generateticket")]
private void CreateTicketEmbedCommand(DiscordInteraction interaction, InteractionDataParsed idp) {
DiscordEmbedBuilder deb = new();
deb.AddTitle(config.lang.ticketEmbedTitle);
deb.AddColor(DiscordColor.Blurple);
deb.AddDescription(config.lang.ticketEmbedDescription);
DiscordMessageBuilder dmb = new();
dmb.AddEmbed(deb.Build());
ActionRowComponent arc = new();
foreach (var langButt in config.ticketLangButtons) {
ButtonComponent button = new() {
Label = langButt.Value.displayedName, Style = ButtonStyle.Primary, Disabled = false, Emoji = DiscordEmoji.FromCharacter(langButt.Value.displayedIcon), CustomId = $"ticket_discord_button_{langButt.Key}"
}
;
arc.Components.Add(button);
}
dmb.AddActionRow(arc);
interaction.Channel.CreateMessage(Client, dmb.Build());
InteractionCallbackData icd = new() {
Content = "Created ticket embed.", Flags = MessageFlags.Ephemeral
}
;
interaction.CreateResponse(Client, InteractionResponseType.ChannelMessageWithSource, icd);
}
[HookMethod(nameof(CreateTicketCloseCommand))]
[DiscordApplicationCommand("close")]
private void CreateTicketCloseCommand(DiscordInteraction interaction, InteractionDataParsed idp) {
InteractionCallbackData icd;
if (interaction.Channel.ParentId != config.newTicketsParentId) {
icd = new() {
Content = config.lang.ticketCannotClose, Flags = MessageFlags.Ephemeral
}
;
interaction.CreateResponse(Client, InteractionResponseType.ChannelMessageWithSource, icd);
return;
}
DiscordChannel ch = interaction.Channel;
GuildChannelUpdate gcu = new() {
Name = ch.Name, ParentId = config.closedTicketsParentId, Topic = ch.Topic, Type = ch.Type, RateLimitPerUser = ch.RateLimitPerUser, Bitrate = ch.Bitrate, UserLimit = ch.UserLimit
}
;
ch.EditGuildChannel(Client, gcu);
data.channelRemovalDate[interaction.Channel.Id] = DateTime.Now;
DiscordEmbedBuilder deb = new();
deb.AddTitle(config.lang.ticketClosedTitle);
deb.AddColor(DiscordColor.Blurple);
deb.AddDescription(config.lang.ticketClosedDescription);
icd = new() {
Embeds = new() {
deb.Build()
}
}
;
interaction.CreateResponse(Client, InteractionResponseType.ChannelMessageWithSource, icd);
}
[HookMethod(nameof(CreateVoteCommand))]
[DiscordApplicationCommand("vote")]
private void CreateVoteCommand(DiscordInteraction interaction, InteractionDataParsed idp) {
InteractionModalBuilder imb = new(interaction);
imb.AddModalTitle("Vote Creator");
imb.AddModalCustomId("vote_modal");
imb.AddInputText("vote_title", "Vote Title", InputTextStyles.Short, config.defaultVoteTitle, true, "Map Vote");
imb.AddInputText("vote_description", "Vote Description", InputTextStyles.Para
// ... [Code preview truncated due to length. Full source in attached file] ...