C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Ext.Discord.Clients;
using Oxide.Ext.Discord.Connections;
using Oxide.Ext.Discord.Constants;
using Oxide.Ext.Discord.Entities;
using Oxide.Ext.Discord.Extensions;
using Oxide.Ext.Discord.Interfaces;
using Oxide.Ext.Discord.Libraries;
using Oxide.Ext.Discord.Logging;
namespace Oxide.Plugins {
[Info("Discord Roles", "MJSU", "2.1.0")]
[Description("Syncs players oxide group with discord roles")]
class DiscordRoles : CovalencePlugin, IDiscordPlugin {
#region Class Fields
[PluginReference]
private Plugin AntiSpam, Clans;
public DiscordClient Client {
get;
set;
}
private PluginConfig _pluginConfig;
//Plugin Config
private readonly List<PlayerSync> _processIds = new List<PlayerSync>();
private Timer _playerChecker;
private DiscordGuild _guild;
private BotConnection _discordSettings;
private const string AccentColor = "#de8732";
private readonly List<string> _added = new List<string>();
private readonly List<string> _removed = new List<string>();
private readonly DiscordLink _link = GetLibrary<DiscordLink>();
private readonly Hash<string, string> _nicknames = new Hash<string, string>();
private readonly List<string> _userRoleList = new List<string>();
public enum DebugEnum {
Message, None, Error, Warning, Info
}
public enum Source {
Server, Discord
}
public enum SyncEvent {
None, PluginLoaded, PlayerConnected, ServerGroupChanged, DiscordRoleChanged, DiscordNicknameChanged, PlayerLinkedChanged, DiscordServerJoinLeave
}
#endregion
#region Setup & Loading
private void Init() {
_discordSettings = new BotConnection {
ApiToken = _pluginConfig.DiscordApiKey, LogLevel = _pluginConfig.ExtensionDebugging, Intents = GatewayIntents.Guilds | GatewayIntents.GuildMembers
}
;
UnsubscribeAll();
}
protected override void LoadDefaultMessages() {
lang.RegisterMessages(new Dictionary<string, string> {
[LangKeys.Chat]
= $"[#BEBEBE][[{AccentColor}]{Title}[/#]] {{0}}[/#]", [LangKeys.ClanTag] = "[{0}] {1}", [LangKeys.ServerMessageGroupAdded] = "{player.name} has been added to server group {group.name}", [LangKeys.ServerMessageGroupRemoved] = "{player.name} has been removed to server group {group.name}", [LangKeys.ServerMessageRoleAdded] = "{player.name} has been added to discord role {role.name}", [LangKeys.ServerMessageRoleRemoved] = "{player.name} has been removed to discord role {role.name}", [LangKeys.DiscordMessageGroupAdded] = "{discord.name} has been added to server group {group.name}", [LangKeys.DiscordMessageGroupRemoved] = "{discord.name} has been removed to server group {group.name}", [LangKeys.DiscordMessageRoleAdded] = "{discord.name} has been added to discord role {role.name}", [LangKeys.DiscordMessageRoleRemoved] = "{discord.name} has been removed to discord role {role.name}",
}
, this);
}
protected override void LoadDefaultConfig() {
PrintWarning("Loading Default Config");
}
protected override void LoadConfig() {
base.LoadConfig();
Config.Settings.DefaultValueHandling = DefaultValueHandling.Populate;
_pluginConfig = AdditionalConfig(Config.ReadObject<PluginConfig>());
Config.WriteObject(_pluginConfig);
}
private PluginConfig AdditionalConfig(PluginConfig config) {
config.EventSettings = new EventSettings(config.EventSettings);
config.SyncData = config.SyncData ?? new List<SyncData> {
new SyncData("Default", default(Snowflake), Source.Server), new SyncData("VIP", default(Snowflake), Source.Discord)
}
;
for (int index = 0; index < config.SyncData.Count; index++) {
config.SyncData[index] = new SyncData(config.SyncData[index]);
}
return config;
}
private void OnServerInitialized() {
if (string.IsNullOrEmpty(_pluginConfig.DiscordApiKey)) {
PrintWarning("Please enter your bot token in the config and reload the plugin.");
return;
}
if (_pluginConfig.UseAntiSpam && AntiSpam == null) {
PrintWarning("AntiSpam is enabled in the config but is not loaded." + "Please disable the setting in the config or load AntiSpam: https://umod.org/plugins/anti-spam");
_pluginConfig.UseAntiSpam = false;
}
Client.Connect(_discordSettings);
}
#endregion
#region Discord Hooks
[HookMethod(DiscordExtHooks.OnDiscordGatewayReady)]
private void OnDiscordGatewayReady(GatewayReadyEvent ready) {
if (ready.Guilds.Count == 0) {
PrintError("Your bot was not found in any discord servers.Please invite it to a server and reload the plugin.");
return;
}
_guild = null;
if (ready.Guilds.Count == 1 && !_pluginConfig.GuildId.IsValid()) {
_guild = ready.Guilds.Values.FirstOrDefault();
}
if (_guild == null) {
_guild = ready.Guilds[_pluginConfig.GuildId];
if (_guild == null) {
PrintError("Failed to find a matching guild for the Discord Server Id." + "Please make sure your guild Id is correct and the bot is in the discord server.");
}
}
DiscordApplication app = Client.Bot.Application;
if (!app.HasApplicationFlag(ApplicationFlags.GatewayGuildMembersLimited) && !app.HasApplicationFlag(ApplicationFlags.GatewayGuildMembers)) {
PrintError($"You need to enable \"Server Members Intent\" for {Client.Bot.BotUser.Username} @ https://discord.com/developers/applications\n" + $"{Name} will not function correctly until that is fixed.Once updated please reload {Name}.");
return;
}
}
[HookMethod(DiscordExtHooks.OnDiscordGuildMembersLoaded)]
private void OnDiscordGuildMembersLoaded(DiscordGuild guild) {
if (guild.Id != _guild.Id) {
return;
}
HandleMembersLoaded();
SubscribeAll();
Puts($"{Title} Ready");
}
private void HandleMembersLoaded() {
if (!_pluginConfig.EventSettings.IsAnyEnabled(SyncEvent.PluginLoaded)) {
Debug(DebugEnum.Info, "Skipping plugin load event due to no events being enabled");
return;
}
for (int index = _pluginConfig.SyncData.Count - 1; index >= 0; index--) {
SyncData data = _pluginConfig.SyncData[index];
bool remove = false;
if (!permission.GroupExists(data.ServerGroup)) {
PrintWarning($"Server group does not exist: '{data.ServerGroup}'.Please create the group or correct the name");
remove = true;
}
DiscordRole role = _guild.Roles[data.DiscordRole];
if (role == null) {
PrintWarning($"Discord role ID does not exist: '{data.DiscordRole}'.\n" + "Please fix the role ID.");
remove = true;
}
if (remove) {
_pluginConfig.SyncData.RemoveAt(index);
}
}
timer.In(5f, CheckAllPlayers);
}
private void CheckAllPlayers() {
IReadOnlyDictionary<PlayerId, Snowflake> links = _link.PlayerToDiscordIds;
if (links == null) {
PrintWarning("No Discord Link plugin registered.Please add a Discord Link plugin and reload this plugin.");
return;
}
foreach (KeyValuePair<PlayerId, Snowflake> link in links) {
IPlayer player = link.Key.Player;
if (player.IsDummyPlayer()) {
continue;
}
_processIds.Add(new PlayerSync(player, link.Value, false, SyncEvent.PluginLoaded));
}
Debug(DebugEnum.Message, $"Starting sync for {_processIds.Count} linked players");
StartChecker();
}
private void StartChecker() {
if (_playerChecker == null || _playerChecker.Destroyed) {
_playerChecker = timer.Every(_pluginConfig.UpdateRate, ProcessNextStartupId);
}
}
private void ProcessNextStartupId() {
if (_processIds.Count == 0) {
_playerChecker?.Destroy();
_playerChecker = null;
return;
}
PlayerSync id = _processIds[0];
_processIds.RemoveAt(0);
ProcessUser(id);
}
#endregion
#region Commands
[Command("dcr.forcecheck")]
private void HandleCommand(IPlayer player, string cmd, string[] args) {
Debug(DebugEnum.Message, "Begin checking all players");
CheckAllPlayers();
}
#endregion
#region Hooks
private void OnUserConnected(IPlayer player) {
if (!_pluginConfig.EventSettings.IsAnyEnabled(SyncEvent.PlayerConnected)) {
Debug(DebugEnum.Info, "Skipping player connected event due to no events being enabled");
return;
}
Debug(DebugEnum.Info, $"{nameof(OnUserConnected)} Added {player.Name}({player.Id}) to be processed");
ProcessChange(player.Id, false, SyncEvent.PlayerConnected);
}
private void OnUserGroupAdded(string id, string groupName) {
if (!_pluginConfig.EventSettings.IsAnyEnabled(SyncEvent.ServerGroupChanged)) {
Debug(DebugEnum.Info, "Skipping server group changed event due to no events being enabled");
return;
}
Debug(DebugEnum.Info, $"{nameof(OnUserGroupAdded)} Added ({id}) to be processed because added to group {groupName}");
ProcessChange(id, false, SyncEvent.ServerGroupChanged);
}
private void OnUserGroupRemoved(string id, string groupName) {
if (!_pluginConfig.EventSettings.IsAnyEnabled(SyncEvent.ServerGroupChanged)) {
Debug(DebugEnum.Info, "Skipping server group changed event due to no events being enabled");
return;
}
Debug(DebugEnum.Info, $"{nameof(OnUserGroupRemoved)} Added ({id}) to be processed because removed from group {groupName}");
ProcessChange(id, false, SyncEvent.ServerGroupChanged);
}
[HookMethod(DiscordExtHooks.OnDiscordPlayerLinked)]
private void OnDiscordPlayerLinked(IPlayer player, DiscordUser user) {
if (!_pluginConfig.EventSettings.IsAnyEnabled(SyncEvent.PlayerLinkedChanged)) {
Debug(DebugEnum.Info, "Skipping player linked event due to no events being enabled");
return;
}
Debug(DebugEnum.Info, $"{nameof(OnDiscordPlayerLinked)} Added Player {player.Name}({player.Id}) Discord: {user.Username}#{user.Discriminator}({user.Id}) to be processed");
ProcessChange(player.Id, false, SyncEvent.PlayerLinkedChanged);
}
[HookMethod(DiscordExtHooks.OnDiscordPlayerUnlinked)]
private void OnDiscordPlayerUnlinked(IPlayer player, DiscordUser user) {
if (!_pluginConfig.EventSettings.IsAnyEnabled(SyncEvent.PlayerLinkedChanged)) {
Debug(DebugEnum.Info, "Skipping player unlinked event due to no events being enabled");
return;
}
Debug(DebugEnum.Info, $"{nameof(OnDiscordPlayerUnlinked)} Added Player {player.Name}({player.Id}) Discord: {user.Username}#{user.Discriminator}({user.Id}) to be processed");
ProcessChange(player.Id, true, SyncEvent.PlayerLinkedChanged);
}
[HookMethod(DiscordExtHooks.OnDiscordGuildMemberAdded)]
private void OnDiscordGuildMemberAdded(GuildMemberAddedEvent member) {
if (member.GuildId != _guild.Id) {
return;
}
if (!_pluginConfig.EventSettings.IsAnyEnabled(SyncEvent.DiscordServerJoinLeave)) {
Debug(DebugEnum.Info, "Skipping player join event due to no events being enabled");
return;
}
Debug(DebugEnum.Info, $"{nameof(OnDiscordGuildMemberAdded)} Added {member.DisplayName}({member.User.Id}) to be processed");
HandleDiscordChange(member.User, false, SyncEvent.DiscordServerJoinLeave);
}
[HookMethod(DiscordExtHooks.OnDiscordGuildMemberRemoved)]
private void OnDiscordGuildMemberRemoved(GuildMemberRemovedEvent member) {
if (member.GuildId != _guild.Id) {
return;
}
if (!_pluginConfig.EventSettings.IsAnyEnabled(SyncEvent.DiscordServerJoinLeave)) {
Debug(DebugEnum.Info, "Skipping player leave event due to no events being enabled");
return;
}
Debug(DebugEnum.Info, $"{nameof(OnDiscordGuildMemberRemoved)} Added {member.User.FullUserName}({member.User.Id}) to be processed");
HandleDiscordChange(member.User, true, SyncEvent.DiscordServerJoinLeave);
}
[HookMethod(DiscordExtHooks.OnDiscordGuildMemberUpdated)]
private void OnDiscordGuildMemberUpdated(GuildMember update, GuildMember oldMember, DiscordGuild guild) {
if (guild.Id != _guild?.Id) {
Debug(DebugEnum.Info, $"{nameof(OnDiscordGuildMemberUpdated)} Skipping {update.Nickname}({update.User.Id}) Guild Mismatch");
return;
}
PlayerId playerId = _link.GetPlayerId(update.User.Id);
if (!playerId.IsValid) {
Debug(DebugEnum.Info, $"{nameof(OnDiscordGuildMemberUpdated)} Player ID is null or empty for user {update.User.FullUserName}");
return;
}
IPlayer player = playerId.Player;
if (player == null) {
Debug(DebugEnum.Info, $"{nameof(OnDiscordGuildMemberUpdated)} Skipping {update.Nickname}({update.User.Id}) No Linked Player Link: {update.User.IsLinked()} {playerId}");
return;
}
_added.Clear();
_removed.Clear();
foreach (Snowflake snowflake in update.Roles.Except(oldMember.Roles)) {
_added.Add(_guild?.Roles[snowflake]?.Name ?? "Unknown Role");
}
foreach (Snowflake snowflake in oldMember.Roles.Except(update.Roles)) {
_removed.Add(_guild?.Roles[snowflake]?.Name ?? "Unknown Role");
}
bool shouldUpdate = false;
SyncEvent syncEvent = SyncEvent.None;
if (_added.Count != 0) {
shouldUpdate = true;
Debug(DebugEnum.Info, $"{nameof(OnDiscordGuildMemberUpdated)} Added {update.Nickname}({update.User.Id}) to be processed because added roles {string.Join(", ", _added)}");
syncEvent = SyncEvent.DiscordRoleChanged;
}
if (_removed.Count != 0) {
shouldUpdate = true;
Debug(DebugEnum.Info, $"{nameof(OnDiscordGuildMemberUpdated)} Added {update.Nickname}({update.User.Id}) to be processed because removed roles {string.Join(", ", _removed)}");
syncEvent = SyncEvent.DiscordRoleChanged;
}
if (update.Nickname != null && (!_nicknames.ContainsKey(update.Id) || _nicknames[update.Id] != update.Nickname) && update.Nickname != GetPlayerName(player)) {
shouldUpdate = true;
Debug(DebugEnum.Info, $"{nameof(OnDiscordGuildMemberUpdated)} Added {update.Nickname}({update.User.Id}) to be processed nickname changed: {oldMember.Nickname} -> {update.Nickname}");
syncEvent = SyncEvent.DiscordNicknameChanged;
}
if (!shouldUpdate) {
Debug(DebugEnum.Info, $"{nameof(OnDiscordGuildMemberUpdated)} Skipping {update.Nickname}({update.User.Id}) no changes detected.");
return;
}
if (!_pluginConfig.EventSettings.IsAnyEnabled(syncEvent)) {
Debug(DebugEnum.Info, "Skipping guild member updated event due to no events being enabled");
return;
}
HandleDiscordChange(update.User, false, syncEvent);
}
public void HandleDiscordChange(DiscordUser user, bool isLeaving, SyncEvent syncEvent) {
PlayerId playerId = _link.GetPlayerId(user.Id);
if (!playerId.IsValid) {
Debug(DebugEnum.Info, $"{nameof(HandleDiscordChange)} Player ID is null or empty for user {user.FullUserName}");
return;
}
IPlayer player = playerId.Player;
if (player == null) {
Debug(DebugEnum.Info, $"{nameof(HandleDiscordChange)} IPlayer not found for user {user.FullUserName}");
return;
}
_processIds.RemoveAll(p => p.MemberId == user.Id && !p.IsLeaving);
PlayerSync sync = new PlayerSync(player, user.Id, isLeaving, syncEvent);
if (isLeaving) {
sync.Member = new GuildMember {
User = user, Roles = new List<Snowflake>()
}
;
}
_processIds.Insert(0, sync);
StartChecker();
}
private void ProcessChange(string playerId, bool isLeaving, SyncEvent syncEvent) {
_processIds.RemoveAll(p => p.Player.Id == playerId);
IPlayer player = players.FindPlayerById(playerId);
if (player == null) {
return;
}
Snowflake discordId = player.GetDiscordUserId();
if (!discordId.IsValid()) {
return;
}
_processIds.Insert(0, new PlayerSync(player, discordId, isLeaving, syncEvent));
StartChecker();
}
#endregion
#region Role Handling
public void ProcessUser(PlayerSync sync) {
if (sync.Member == null) {
if (!sync.MemberId.IsValid()) {
return;
}
if (!_guild.Members.ContainsKey(sync.MemberId)) {
return;
}
_guild.GetMember(Client, sync.MemberId).Then(member => {
sync.Member = member;
ProcessUser(sync);
}
);
return;
}
try {
Debug(DebugEnum.Info, $"Start processing: Player: {sync.Player.Name}({sync.Player.Id}) Discord: {sync.Member.DisplayName}({sync.Member.User?.Id}) Is Leaving: {sync.IsLeaving}");
UnsubscribeAll();
HandleServerGroups(sync);
HandleDiscordRoles(sync);
HandleUserNick(sync);
}
finally {
SubscribeAll();
}
}
public void HandleServerGroups(PlayerSync playerSync) {
if (playerSync.IsLeaving) {
return;
}
IPlayer player = playerSync.Player;
GuildMember member = playerSync.Member;
string playerName = $"{player.Name}({playerSync.Player.Id}) {member.DisplayName}({member.User.Id})";
Debug(DebugEnum.Info, $"Processing Server for {player.Name}({player.Id}) Discord {member.DisplayName}({member.User.Id}) Is Leaving {playerSync.IsLeaving}");
if (!_pluginConfig.EventSettings.ServerSync.IsEnabled(playerSync.Event)) {
Debug(DebugEnum.Info, $"Skipping server sync due to event not being enabled for {playerSync.Event}");
return;
}
foreach (IGrouping<Snowflake, SyncData> data in _pluginConfig.SyncData.Where(s => s.Source == Source.Server).GroupBy(s => s.DiscordRole)) {
bool isInGroup = data.Any(d => permission.UserHasGroup(player.Id, d.ServerGroup));
bool isInDiscord = member.Roles.Contains(data.Key);
if (isInDiscord == isInGroup) {
Debug(DebugEnum.Info, $"{playerSync.Player.Name} skipping Server Sync: [{string.Join(", ", data.Select(d => d.ServerGroup).ToArray())}] -> {_guild.Roles[data.Key]?.Name} {(isInGroup ? "Already Synced" : "Not in group")}");
continue;
}
string roleName = _guild.Roles[data.Key]?.Name;
if (isInGroup) {
Debug(DebugEnum.Message, $"Adding player {playerName} to discord role {roleName}");
_guild.AddMemberRole(Client, member.User.Id, data.Key).Then(() => {
Debug(DebugEnum.Message, $"Successfully added {playerName} to {roleName}");
}
).Catch<ResponseError>(error => {
Debug(DebugEnum.Error, $"An error has occured adding {playerName} to {roleName}.Please check above this message for the error.");
}
);
}
else {
_guild.RemoveMemberRole(Client, playerSync.Member.User.Id, data.Key).Then(() => {
Debug(DebugEnum.Message, $"Successfully removed {playerName} from {roleName}");
}
).Catch<ResponseError>(error => {
Debug(DebugEnum.Error, $"An error has occured removing {playerName} from {roleName}.Please check above this message for the error.");
}
);
}
SyncData sync = data.FirstOrDefault(d => permission.UserHasGroup(player.Id, d.ServerGroup)) ?? data.FirstOrDefault();
SendSyncNotification(playerSync, sync, isInGroup);
}
}
public void HandleDiscordRoles(PlayerSync playerSync) {
IPlayer player = playerSync.Player;
GuildMember member = playerSync.Member;
string playerName = $"{player.Name}({playerSync.Player.Id}) {member.DisplayName}({member.User.Id})";
Debug(DebugEnum.Info, $"Processing Discord for {player.Name}({player.Id}) Discord {member.DisplayName}({member.User.Id}) Is Leaving {playerSync.IsLeaving} Roles: {GetUserRoles(playerSync.Member)}");
if (!_pluginConfig.EventSettings.DiscordSync.IsEnabled(playerSync.Event)) {
Debug(DebugEnum.Info, $"Skipping discord sync due to event not being enabled for {playerSync.Event}");
return;
}
foreach (IGrouping<string, SyncData> data in _pluginConfig.SyncData.Where(s => s.Source == Source.Discord).GroupBy(s => s.ServerGroup)) {
bool isInGroup = permission.UserHasGroup(player.Id, data.Key);
bool isInDiscord = false;
SyncData sync = null;
if (!playerSync.IsLeaving) {
foreach (SyncData syncData in data) {
if (member.Roles.Contains(syncData.DiscordRole)) {
sync = syncData;
isInDiscord = true;
break;
}
}
}
if (isInDiscord == isInGroup) {
Debug(DebugEnum.Info, $"{player?.Name} skipping Discord Sync: [{string.Join(", ", data.Select(d => _guild.Roles[d.DiscordRole]?.Name ?? string.Empty).ToArray())}] -> {data.Key} {(isInDiscord ? "Already Synced" : "Doesn't have role")}");
continue;
}
if (isInDiscord)
{
Debug(DebugEnum.Message, $"Adding player {playerName} to server group {data.Key}");
permission.AddUserGroup(player.Id, data.Key);
}
else
{
Debug(DebugEnum.Message, $"Removing player {playerName} from server group {data.Key}");
permission.RemoveUserGroup(player.Id, data.Key);
}
sync = sync ?? data.FirstOrDefault();
SendSyncNotification(playerSync, sync, isInDiscord);
}
}
public void HandleUserNick(PlayerSync sync)
{
IPlayer player = sync.Player;
if (!_pluginConfig.SyncNicknames || sync.IsLeaving)
{
Debug(DebugEnum.Info, $"{nameof(HandleUserNick)} don't sync nicknames or is leaving");
return;
}
if (sync.Member.User.Id == _guild.OwnerId)
{
Debug(DebugEnum.Info, $" {
nameof(HandleUserNick)
}
don't sync nickname discord server owner");
return;
}
if (!_pluginConfig.EventSettings.NicknameSync.IsEnabled(sync.Event))
{
Debug(DebugEnum.Info, $"Skipping nickname sync due to event not being enabled for {sync.Event}");
return;
}
string playerName = GetPlayerName(player);
if (playerName.Equals(sync.Member.Nickname))
{
Debug(DebugEnum.Info, $"{nameof(HandleUserNick)} skipping nickname as it matches what we expect: {playerName}");
return;
}
Debug(DebugEnum.Info, $"Updating {sync.Member.DisplayName}'s discord server nickname to {
playerName
}
");
_guild.EditMemberNick(Client, sync.Member.User.Id, playerName).Then(member =>
{
Debug(DebugEnum.Info, $"Successfully updated {
sync.Member.DisplayName
}
's discord server nickname to {playerName}");
_nicknames[sync.Member.User.Id] = member.Nickname;
}).Catch<ResponseError>(error =>
{
Debug(DebugEnum.Error, $"An error has occured updating {sync.Member.DisplayName}'s discord server nickname to {
playerName
}
");
});
}
private string GetPlayerName(IPlayer player)
{
string playerName = player.Name;
if (_pluginConfig.UseAntiSpam && AntiSpam != null && AntiSpam.IsLoaded)
{
playerName = AntiSpam.Call<string>("GetClearName", player);
if (string.IsNullOrEmpty(playerName))
{
Debug(DebugEnum.Warning, $"AntiSpam returned an empty string for '{player.Name}'");
playerName = player.Name;
}
else if (!playerName.Equals(player.Name))
{
Debug(DebugEnum.Info, $"Nickname '{player.Name}' was filtered by AntiSpam : '{playerName}'");
}
}
if (_pluginConfig.SyncClanTag)
{
string tag = Clans?.Call<string>("GetClanOf", player.Id);
if (!string.IsNullOrEmpty(tag))
{
playerName = Lang(LangKeys.ClanTag, player, tag, playerName);
}
}
if (playerName.Length > 32)
{
playerName = playerName.Substring(0, 32);
}
return playerName;
}
#endregion
#region Message Handling
private void SendSyncNotification(PlayerSync sync, SyncData data, bool wasAdded)
{
NotificationSettings settings = data.Notifications;
if (!settings.SendMessageToServer && !settings.SendMessageToDiscord)
{
return;
}
if (wasAdded && !settings.SendMessageOnAdd)
{
return;
}
if (!wasAdded && !settings.SendMessageOnRemove)
{
return;
}
if (settings.SendMessageToServer)
{
StringBuilder message = GetServerMessage(data, wasAdded);
ProcessMessage(message, sync, data);
Chat(message.ToString());
}
if (settings.SendMessageToDiscord)
{
if (!settings.DiscordMessageChannelId.IsValid())
{
return;
}
StringBuilder message = GetDiscordMessage(data, wasAdded);
ProcessMessage(message, sync, data);
DiscordMessage.Create(Client, settings.DiscordMessageChannelId, message.ToString());
}
}
private StringBuilder GetServerMessage(SyncData sync, bool wasAdded)
{
StringBuilder message = new StringBuilder();
if (wasAdded && !string.IsNullOrEmpty(sync.Notifications.ServerMessageAddedOverride))
{
message.Append(sync.Notifications.ServerMessageAddedOverride);
}
else if (!wasAdded && !string.IsNullOrEmpty(sync.Notifications.ServerMessageRemovedOverride))
{
message.Append(sync.Notifications.ServerMessageRemovedOverride);
}
else
{
switch (sync.Source)
{
case Source.Server:
message.Append(wasAdded ? LangNoFormat(LangKeys.ServerMessageRoleAdded) : LangNoFormat(LangKeys.ServerMessageRoleRemoved));
break;
case Source.Discord:
message.Append(wasAdded ? LangNoFormat(LangKeys.ServerMessageGroupAdded) : LangNoFormat(LangKeys.ServerMessageGroupRemoved));
break;
}
}
return message;
}
private StringBuilder GetDiscordMessage(SyncData sync, bool wasAdded)
{
StringBuilder message = new StringBuilder();
if (wasAdded && !string.IsNullOrEmpty(sync.Notifications.DiscordMessageAddedOverride))
{
message.Append(sync.Notifications.DiscordMessageAddedOverride);
}
else if (!wasAdded && !string.IsNullOrEmpty(sync.Notifications.DiscordMessageRemovedOverride))
{
message.Append(sync.Notifications.DiscordMessageRemovedOverride);
}
else
{
switch (sync.Source)
{
case Source.Server:
message.Append(wasAdded ? LangNoFormat(LangKeys.DiscordMessageRoleAdded) : LangNoFormat(LangKeys.DiscordMessageRoleRemoved));
break;
case Source.Discord:
message.Append(wasAdded ? LangNoFormat(LangKeys.DiscordMessageGroupAdded) : LangNoFormat(LangKeys.DiscordMessageGroupRemoved));
break;
}
}
return message;
}
private void ProcessMessage(StringBuilder message, PlayerSync sync, SyncData data)
{
IPlayer player = sync.Player;
GuildMember member = sync.Member;
if (player != null)
{
message.Replace(" {
player.id
}
", player.Id);
message.Replace(" {
player.name
}
", player.Name);
}
if (member != null)
{
message.Replace(" {
discord.id
}
", member.User.Id.ToString());
message.Replace(" {
discord.name
}
", member.User.Username);
message.Replace(" {
discord.discriminator
}
", member.User.Discriminator);
message.Replace(" {
discord.nickname
}
", member.Nickname);
}
DiscordRole role = _guild.Roles[data.DiscordRole];
if (role != null)
{
message.Replace(" {
role.id
}
", role.Id.ToString());
message.Replace(" {
role.name
}
", role.Name);
}
message.Replace(" {
group.name
}
", data.ServerGroup);
}
#endregion
#region Subscription Handling
public void UnsubscribeAll()
{
try
{
Unsubscribe(nameof(OnUserGroupAdded));
Unsubscribe(nameof(OnUserGroupRemoved));
Unsubscribe(nameof(OnUserConnected));
}
catch
{
}
}
public void SubscribeAll()
{
try
{
Subscribe(nameof(OnUserGroupAdded));
Subscribe(nameof(OnUserGroupRemoved));
Subscribe(nameof(OnUserConnected));
}
catch
{
}
}
#endregion
#region Helper Methods
public string GetUserRoles(GuildMember member)
{
_userRoleList.Clear();
foreach (Snowflake role in member.Roles)
{
_userRoleList.Add($" {
_guild.Roles[role].Name
}
( {
role.ToString()
}
)");
}
return string.Join(", ", _userRoleList);
}
public void Debug(DebugEnum level, string message)
{
if (level <= _pluginConfig.DebugLevel)
{
Puts($" {
level
}
: {
message
}
");
}
}
public void Chat(string message)
{
server.Broadcast(Lang(LangKeys.Chat, null, message));
}
public string Lang(string key, IPlayer player = null, params object[] args)
{
try
{
return string.Format(lang.GetMessage(key, this, player?.Id), args);
}
catch (Exception ex)
{
PrintError($"Lang Key '{key}' threw exception : \n {
ex
}
");
throw;
}
}
public string LangNoFormat(string key, IPlayer player = null) => lang.GetMessage(key, this, player?.Id);
#endregion
#region Classes
public class PluginConfig
{
[DefaultValue("")]
[JsonProperty(PropertyName = "Discord Bot Token")]
public string DiscordApiKey { get; set; }
[JsonProperty(PropertyName = "Discord Server ID (Optional if bot only in 1 guild)")]
public Snowflake GuildId { get; set; }
[DefaultValue(false)]
[JsonProperty(PropertyName = "Sync Nicknames")]
public bool SyncNicknames { get; set; }
[DefaultValue(false)]
[JsonProperty(PropertyName = "Sync Clan Tag")]
public bool SyncClanTag { get; set; }
[DefaultValue(2f)]
[JsonProperty(PropertyName = "Update Rate (Seconds)")]
public float UpdateRate { get; set; }
[DefaultValue(false)]
[JsonProperty(PropertyName = "Use AntiSpam On Discord Nickname")]
public bool UseAntiSpam { get; set; }
[JsonProperty(PropertyName = "Action To Perform By Event")]
public EventSettings EventSettings { get; set; }
[JsonProperty(PropertyName = "Sync Data")]
public List<SyncData> SyncData { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
[DefaultValue(DebugEnum.Warning)]
[JsonProperty(PropertyName = "Plugin Log Level (None, Error, Warning, Info)")]
public DebugEnum DebugLevel { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
[DefaultValue(DiscordLogLevel.Info)]
[JsonProperty(PropertyName = "Discord Extension Log Level (Verbose, Debug, Info, Warning, Error, Exception, Off)")]
public DiscordLogLevel ExtensionDebugging { get; set; }
}
public class EventSettings
{
[JsonProperty("Events To Sync Server Groups -> Discord Roles")]
public EnabledSyncEvents ServerSync { get; set; }
[JsonProperty("Events To Sync Discord Roles -> Server Groups")]
public EnabledSyncEvents DiscordSync { get; set; }
[JsonProperty("Events To Sync Discord Nickname")]
public EnabledSyncEvents NicknameSync { get; set; }
[JsonConstructor]
public EventSettings()
{
}
public EventSettings(EventSettings settings)
{
ServerSync = new EnabledSyncEvents
{
SyncOnPluginLoad = settings?.ServerSync?.SyncOnPluginLoad ?? true,
SyncOnPlayerConnected = settings?.ServerSync?.SyncOnPlayerConnected ?? true,
SyncOnServerGroupChanged = settings?.ServerSync?.SyncOnServerGroupChanged ?? true,
SyncOnDiscordRoleChanged = settings?.ServerSync?.SyncOnDiscordRoleChanged ?? true,
SyncOnDiscordNicknameChanged = settings?.ServerSync?.SyncOnDiscordNicknameChanged ?? false,
SyncOnLinkedChanged = settings?.ServerSync?.SyncOnLinkedChanged ?? true,
SyncOnDiscordServerJoinLeave = settings?.ServerSync?.SyncOnDiscordServerJoinLeave ?? true
};
DiscordSync = new EnabledSyncEvents
{
SyncOnPluginLoad = settings?.DiscordSync?.SyncOnPluginLoad ?? true,
SyncOnPlayerConnected = settings?.DiscordSync?.SyncOnPlayerConnected ?? true,
SyncOnServerGroupChanged = settings?.DiscordSync?.SyncOnServerGroupChanged ?? true,
SyncOnDiscordRoleChanged = settings?.DiscordSync?.SyncOnDiscordRoleChanged ?? true,
SyncOnDiscordNicknameChanged = settings?.DiscordSync?.SyncOnDiscordNicknameChanged ?? false,
SyncOnLinkedChanged = settings?.DiscordSync?.SyncOnLinkedChanged ?? true,
SyncOnDiscordServerJoinLeave = settings?.DiscordSync?.SyncOnDiscordServerJoinLeave ?? true
};
NicknameSync = new EnabledSyncEvents
{
SyncOnPluginLoad = settings?.NicknameSync?.SyncOnPluginLoad ?? true,
SyncOnPlayerConnected = settings?.NicknameSync?.SyncOnPlayerConnected ?? true,
SyncOnServerGroupChanged = settings?.NicknameSync?.SyncOnServerGroupChanged ?? false,
SyncOnDiscordRoleChanged = settings?.NicknameSync?.SyncOnDiscordRoleChanged ?? false,
SyncOnDiscordNicknameChanged = settings?.NicknameSync?.SyncOnDiscordNicknameChanged ?? true,
SyncOnLinkedChanged = settings?.NicknameSync?.SyncOnLinkedChanged ?? true,
SyncOnDiscordServerJoinLeave = settings?.NicknameSync?.SyncOnDiscordServerJoinLeave ?? false
};
}
public bool IsAnyEnabled(SyncEvent syncEvent)
{
return ServerSync.IsEnabled(syncEvent) || DiscordSync.IsEnabled(syncEvent) || NicknameSync.IsEnabled(syncEvent);
}
}
public class SyncData
{
[JsonProperty(PropertyName = "Server Group")]
public string ServerGroup { get; set; }
[JsonProperty(PropertyName = "Discord Role ID")]
public Snowflake DiscordRole { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
[JsonProperty(PropertyName = "Sync Source (Server or Discord)")]
public Source Source { get; set; }
[JsonProperty(PropertyName = "Sync Notification Settings")]
public NotificationSettings Notifications { get; set; }
[JsonConstructor]
public SyncData()
{
}
public SyncData(string serverGroup, Snowflake discordRole, Source source)
{
ServerGroup = serverGroup;
DiscordRole = discordRole;
Source = source;
Notifications = new NotificationSettings();
}
public SyncData(SyncData settings)
{
ServerGroup = settings?.ServerGroup ?? string.Empty;
DiscordRole = settings?.DiscordRole ?? default(Snowflake);
Source = settings?.Source ?? Source.Server;
Notifications = new NotificationSettings(settings?.Notifications);
}
}
public class NotificationSettings
{
[JsonProperty(PropertyName = "Send message to Server")]
public bool SendMessageToServer { get; set; }
[JsonProperty(PropertyName = "Send Message To Discord")]
public bool SendMessageToDiscord { get; set; }
[JsonProperty(PropertyName = "Discord Message Channel ID")]
public Snowflake DiscordMessageChannelId { get; set; }
[JsonProperty(PropertyName = "Send Message When Added")]
public bool SendMessageOnAdd { get; set; }
[JsonProperty(PropertyName = "Send Message When Removed")]
public bool SendMessageOnRemove { get; set; }
[JsonProperty(PropertyName = "Server Message Added Override Message")]
public string ServerMessageAddedOverride { get; set; }
[JsonProperty(PropertyName = "Server Message Removed Override Message")]
public string ServerMessageRemovedOverride { get; set; }
[JsonProperty(PropertyName = "Discord Message Added Override Message")]
public string DiscordMessageAddedOverride { get; set; }
[JsonProperty(PropertyName = "Discord Message Removed Override Message")]
public string DiscordMessageRemovedOverride { get; set; }
public NotificationSettings()
{
SendMessageToServer = false;
SendMessageToDiscord = false;
DiscordMessageChannelId = default(Snowflake);
SendMessageOnAdd = false;
SendMessageOnRemove = false;
ServerMessageAddedOverride = string.Empty;
ServerMessageRemovedOverride = string.Empty;
DiscordMessageAddedOverride = string.Empty;
DiscordMessageRemovedOverride = string.Empty;
}
public NotificationSettings(NotificationSettings settings)
{
SendMessageToServer = settings?.SendMessageToServer ?? false;
SendMessageToDiscord = settings?.SendMessageToDiscord ?? false;
DiscordMessageChannelId = settings?.DiscordMessageChannelId ?? default(Snowflake);
SendMessageOnAdd = settings?.SendMessageOnAdd ?? false;
SendMessageOnRemove = settings?.SendMessageOnRemove ?? false;
ServerMessageAddedOverride = settings?.ServerMessageAddedOverride ?? string.Empty;
ServerMessageRemovedOverride = settings?.ServerMessageRemovedOverride ?? string.Empty;
DiscordMessageAddedOverride = settings?.DiscordMessageAddedOverride ?? string.Empty;
DiscordMessageRemovedOverride = settings?.DiscordMessageRemovedOverride ?? string.Empty;
}
}
public class EnabledSyncEvents
{
[JsonProperty("Sync On Plugin Load")]
public bool SyncOnPluginLoad { get; set; }
[JsonProperty("Sync On Player Connected")]
public bool SyncOnPlayerConnected { get; set; }
[JsonProperty("Sync On Server Group Changed")]
public bool SyncOnServerGroupChanged { get; set; }
[JsonProperty("Sync On Discord Role Changed")]
public bool SyncOnDiscordRoleChanged { get; set; }
[JsonProperty("Sync On Discord Nickname Changed")]
public bool SyncOnDiscordNicknameChanged { get; set; }
[JsonProperty("Sync On Player Linked / Unlinked")]
public bool SyncOnLinkedChanged { get; set; }
[JsonProperty("Sync On User Join / Leave Discord Server")]
public bool SyncOnDiscordServerJoinLeave { get; set; }
public bool IsEnabled(SyncEvent syncEvent)
{
switch (syncEvent)
{
case SyncEvent.None:
return false;
case SyncEvent.PluginLoaded:
return SyncOnPluginLoad;
case SyncEvent.PlayerConnected:
return SyncOnPlayerConnected;
case SyncEvent.ServerGroupChanged:
return SyncOnServerGroupChanged;
case SyncEvent.DiscordRoleChanged:
return SyncOnDiscordRoleChanged;
case SyncEvent.DiscordNicknameChanged:
return SyncOnDiscordNicknameChanged;
case SyncEvent.PlayerLinkedChanged:
return SyncOnLinkedChanged;
case SyncEvent.DiscordServerJoinLeave:
return SyncOnDiscordServerJoinLeave;
default:
throw new ArgumentOutOfRangeException(nameof(syncEvent), syncEvent, null);
}
}
}
public class PlayerSync
{
public IPlayer Player { get; set; }
public GuildMember Member { get; set; }
public Snowflake MemberId { get; set; }
public SyncEvent Event { get; set; }
public bool IsLeaving { get; set; }
pub
// ... [Code preview truncated due to length. Full source in attached file] ...