C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
//Reference: System.Drawing
using Facepunch;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Ext.Discord.Builders;
using Oxide.Ext.Discord.Constants;
using Oxide.Ext.Discord.Entities;
using Oxide.Ext.Discord.Logging;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
using Oxide.Ext.Discord.Clients;
using Oxide.Ext.Discord.Connections;
using Oxide.Ext.Discord.Interfaces;
using UnityEngine;
using Color = System.Drawing.Color;
using Graphics = System.Drawing.Graphics;
using Star = ProtoBuf.PatternFirework.Star;
//DiscordSignLogger created with PluginMerge v(1.0.5.0) by MJSU @ https://github.com/dassjosh/Plugin.Merge
namespace Oxide.Plugins
{
[Info("Discord Sign Logger", "MJSU", "1.0.10")]
[Description("Logs Sign / Firework Changes To Discord")]
public partial class DiscordSignLogger : RustPlugin, IDiscordPlugin
{
#region Plugins\DiscordSignLogger.Fields.cs
[PluginReference] private Plugin RustTranslationAPI, SignArtist;
public DiscordClient Client { get; set; }
private PluginConfig _pluginConfig;
private PluginData _pluginData;
private PluginButtonData _buttonData;
public const string CommandPrefix = "DSL ";
private const string AccentColor = "#de8732";
private readonly MessageCreate _actionMessage = new MessageCreate
{
AllowedMentions = new AllowedMentions
{
AllowedTypes = new List<AllowedMentionTypes>(),
Roles = new List<Snowflake>(),
Users = new List<Snowflake>()
}
};
private readonly StringBuilder _sb = new StringBuilder();
private readonly StringBuilder _actions = new StringBuilder();
public readonly Hash<UnityEngine.Color, Brush> FireworkBrushes = new Hash<UnityEngine.Color, Brush>();
private readonly Hash<NetworkableId, SignageUpdate> _updates = new Hash<NetworkableId, SignageUpdate>();
private readonly Hash<string, string> _prefabNameLookup = new Hash<string, string>();
private DiscordChannel _actionChannel;
private ILogEvent _log;
private DiscordInteraction _interaction;
private GuildMember _activeMember;
public int FireworkImageSize;
public int FireworkHalfImageSize;
public int FireworkCircleSize;
private readonly object _true = true;
private readonly object _false = false;
public static DiscordSignLogger Instance;
#endregion
#region Plugins\DiscordSignLogger.Setup.cs
private void Init()
{
Instance = this;
UnsubscribeAll();
_pluginConfig.ReplaceImage.TextColor = _pluginConfig.ReplaceImage.TextColor.Replace("#", "");
_pluginConfig.ReplaceImage.BodyColor = _pluginConfig.ReplaceImage.BodyColor.Replace("#", "");
_pluginData = Interface.Oxide.DataFileSystem.ReadObject<PluginData>(Name);
_buttonData = Interface.Oxide.DataFileSystem.ReadObject<PluginButtonData>(Name + "_Buttons");
List<int> activeHash = new List<int>();
foreach (SignMessage message in _pluginConfig.SignMessages)
{
foreach (ImageMessageButtonCommand command in message.Commands)
{
command.SetCommandId();
activeHash.Add(command.CommandId);
_buttonData.AddOrUpdate(command);
}
}
_buttonData.CleanupExpired(activeHash, _pluginConfig.DeleteButtonCacheAfter);
SaveButtonData();
_pluginData.CleanupExpired(_pluginConfig.DeleteLogDataAfter);
SaveData();
}
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.FireworkSettings = new FireworkSettings(config.FireworkSettings);
config.ReplaceImage = new ReplaceImageSettings(config.ReplaceImage);
config.ActionLog = new ActionLogConfig(config.ActionLog);
config.SignMessages = config.SignMessages ?? new List<SignMessage>();
if (config.SignMessages.Count == 0)
{
config.SignMessages.Add(new SignMessage(null));
}
else
{
for (int index = 0; index < config.SignMessages.Count; index++)
{
config.SignMessages[index] = new SignMessage(config.SignMessages[index]);
}
}
return config;
}
private void OnServerInitialized()
{
FireworkCircleSize = _pluginConfig.FireworkSettings.CircleSize;
FireworkImageSize = _pluginConfig.FireworkSettings.ImageSize + FireworkCircleSize;
FireworkHalfImageSize = _pluginConfig.FireworkSettings.ImageSize / 2;
if (string.IsNullOrEmpty(_pluginConfig.DiscordApiKey))
{
PrintWarning("Please set the Discord Bot Token and reload the plugin");
return;
}
if (PlaceholderAPI == null || !PlaceholderAPI.IsLoaded)
{
PrintError("Missing plugin dependency PlaceholderAPI: https://umod.org/plugins/placeholder-api");
return;
}
if(PlaceholderAPI.Version < new VersionNumber(2, 2, 0))
{
PrintError("Placeholder API plugin must be version 2.2.0 or higher");
return;
}
if (SignArtist != null && SignArtist.IsLoaded && SignArtist.Version < new VersionNumber(1, 4, 0))
{
PrintWarning("Sign Artist version is outdated and may not function correctly.Please update SignArtist @ https://umod.org/plugins/sign-artist to version 1.4.0 or higher");
}
if (RustTranslationAPI == null || !RustTranslationAPI.IsLoaded)
{
foreach (ItemDefinition def in ItemManager.itemList)
{
BaseEntity entity = def.GetComponent<ItemModDeployable>()?.entityPrefab.Get().GetComponent<BaseEntity>();
if (entity is ISignage || entity is PatternFirework)
{
_prefabNameLookup[entity.ShortPrefabName] = def.displayName.translated;
}
}
}
Client.Connect(new BotConnection()
{
Intents = GatewayIntents.Guilds,
ApiToken = _pluginConfig.DiscordApiKey,
LogLevel = _pluginConfig.ExtensionDebugging
});
if (SignArtist == null || !SignArtist.IsLoaded)
{
Unsubscribe(nameof(OnPlayerCommand));
}
}
private void Unload()
{
SaveData();
SaveButtonData();
Instance = null;
}
#endregion
#region Plugins\DiscordSignLogger.CoreHooks.cs
private void OnImagePost(BasePlayer player, string url, bool raw, ISignage signage, uint textureIndex)
{
_updates[signage.NetworkID] = new SignageUpdate(player, signage, _pluginConfig.SignMessages, textureIndex, player == null, url);
}
private void OnSignUpdated(ISignage signage, BasePlayer player, int textureIndex = 0)
{
if (player == null)
{
_updates.Remove(signage.NetworkID);
return;
}
if (signage.GetTextureCRCs()[textureIndex] == 0)
{
return;
}
SignageUpdate update = _updates[signage.NetworkID] ?? new SignageUpdate(player, signage, _pluginConfig.SignMessages, (uint)textureIndex, player == null);
_updates.Remove(signage.NetworkID);
if (update.IgnoreMessage)
{
return;
}
SendDiscordMessage(update);
}
private void OnItemPainted(PaintedItemStorageEntity entity, Item item, BasePlayer player, byte[] image)
{
if (entity._currentImageCrc == 0)
{
return;
}
PaintedItemUpdate update = new PaintedItemUpdate(player, entity, item, image, _pluginConfig.SignMessages, false);
SendDiscordMessage(update);
}
private void OnFireworkDesignChanged(PatternFirework firework, ProtoBuf.PatternFirework.Design design, BasePlayer player)
{
if (design?.stars == null || design.stars.Count == 0)
{
return;
}
SendDiscordMessage(new FireworkUpdate(player, firework, _pluginConfig.SignMessages));
}
private object CanUpdateSign(BasePlayer player, BaseEntity entity)
{
if (!_pluginData.IsSignBanned(player))
{
return null;
}
Chat(player, LangKeys.BlockedMessage, GetFormattedDurationTime(_pluginData.GetRemainingBan(player)));
//Client side the sign will still be updated if we block it here.We destroy the entity client side to force a redraw of the image.NextTick(() =>
{
entity.DestroyOnClient(player.Connection);
entity.SendNetworkUpdate();
});
return _false;
}
private object OnFireworkDesignChange(PatternFirework firework, ProtoBuf.PatternFirework.Design design, BasePlayer player)
{
if (!_pluginData.IsSignBanned(player))
{
return null;
}
Chat(player, LangKeys.BlockedMessage, player, GetFormattedDurationTime(_pluginData.GetRemainingBan(player), player));
return _true;
}
private object OnPlayerCommand(BasePlayer player, string cmd, string[] args)
{
if (!cmd.StartsWith("sil", StringComparison.OrdinalIgnoreCase))
{
return null;
}
if (!_pluginData.IsSignBanned(player))
{
return null;
}
Chat(player, LangKeys.BlockedMessage, GetFormattedDurationTime(_pluginData.GetRemainingBan(player)));
return _true;
}
private void UnsubscribeAll()
{
Unsubscribe(nameof(OnImagePost));
Unsubscribe(nameof(OnSignUpdated));
Unsubscribe(nameof(OnFireworkDesignChanged));
Unsubscribe(nameof(CanUpdateSign));
Unsubscribe(nameof(OnFireworkDesignChange));
Unsubscribe(nameof(OnPlayerCommand));
}
private void SubscribeAll()
{
Subscribe(nameof(OnSignUpdated));
Subscribe(nameof(OnFireworkDesignChanged));
Subscribe(nameof(CanUpdateSign));
Subscribe(nameof(OnFireworkDesignChange));
if (SignArtist != null && SignArtist.IsLoaded)
{
Subscribe(nameof(OnPlayerCommand));
Subscribe(nameof(OnImagePost));
}
}
#endregion
#region Plugins\DiscordSignLogger.DiscordHooks.cs
[HookMethod(DiscordExtHooks.OnDiscordGuildCreated)]
private void OnDiscordGuildCreated(DiscordGuild guild)
{
bool subscribe = false;
foreach (SignMessage message in _pluginConfig.SignMessages)
{
if (message.MessageChannel == null && message.ChannelId.IsValid())
{
DiscordChannel channel = GetChannel(guild, message.ChannelId);
if (channel != null)
{
message.MessageChannel = channel;
subscribe = true;
}
}
}
if (_pluginConfig.ActionLog.ChannelId.IsValid())
{
DiscordChannel channel = GetChannel(guild, _pluginConfig.ActionLog.ChannelId);
if (channel != null)
{
_actionChannel = channel;
}
}
if (subscribe)
{
SubscribeAll();
Puts($"{Title} Ready");
}
}
[HookMethod(DiscordExtHooks.OnDiscordInteractionCreated)]
private void OnDiscordInteractionCreated(DiscordInteraction interaction)
{
switch (interaction.Type)
{
case InteractionType.MessageComponent:
HandleMessageComponentCommand(interaction);
break;
}
}
#endregion
#region Plugins\DiscordSignLogger.DiscordInteractions.cs
private void HandleMessageComponentCommand(DiscordInteraction interaction)
{
if (!interaction.Data.ComponentType.HasValue || interaction.Data.ComponentType.Value != MessageComponentType.Button)
{
return;
}
string buttonId = interaction.Data.CustomId;
if (!buttonId.StartsWith(CommandPrefix))
{
return;
}
SignUpdateLog log = _pluginData.GetLog(interaction.Message.Id);
if (log == null)
{
DisableAllButtons(interaction.Message);
SendComponentUpdateResponse(interaction);
CreateResponse(interaction, Lang(LangKeys.DeletedLog, null, _pluginConfig.DeleteLogDataAfter));
return;
}
buttonId = buttonId.Replace(CommandPrefix, string.Empty);
int hash;
if (!int.TryParse(buttonId, out hash))
{
DisableAllButtons(interaction.Message);
SendComponentUpdateResponse(interaction);
CreateResponse(interaction, Lang(LangKeys.DeletedLog, null, _pluginConfig.DeleteButtonCacheAfter));
return;
}
ImageMessageButtonCommand command = _buttonData.Get(hash);
if (command == null)
{
DisableAllButtons(interaction.Message);
SendComponentUpdateResponse(interaction);
CreateResponse(interaction, Lang(LangKeys.DeletedLog, null, _pluginConfig.DeleteButtonCacheAfter));
return;
}
RunCommand(interaction, log, command);
}
public void RunCommand(DiscordInteraction interaction, SignUpdateLog data, ImageMessageButtonCommand button)
{
try
{
_log = data;
_activeMember = interaction.Member;
_interaction = interaction;
if (button.RequirePermissions && !UserHasButtonPermission(interaction, button))
{
CreateResponse(interaction, Lang(LangKeys.NoPermission));
return;
}
IPlayer logPlayer = data.Player;
_actions.Clear();
foreach (string buttonCommand in button.Commands)
{
_sb.Clear();
_sb.Append(buttonCommand);
ParsePlaceholders(logPlayer, _sb);
string serverCommand = _sb.ToString();
covalence.Server.Command(serverCommand);
if (_actionChannel != null)
{
if (_actions.Length != 0)
{
_actions.AppendLine();
}
_actions.Append(Lang(LangKeys.ActionMessage));
ParsePlaceholders(logPlayer, _actions);
_actions.Replace("{dsl.command}", serverCommand);
}
}
if (_actionChannel != null)
{
_actionMessage.Content = _actions.ToString();
if (_pluginConfig.ActionLog.Buttons.Count != 0)
{
MessageComponentBuilder builder = new MessageComponentBuilder();
for (int index = 0; index < _pluginConfig.ActionLog.Buttons.Count; index++)
{
ActionMessageButtonCommand actionButton = _pluginConfig.ActionLog.Buttons[index];
if (actionButton.Commands.Count == 0)
{
continue;
}
if (actionButton.Style == ButtonStyle.Link)
{
builder.AddLinkButton(actionButton.DisplayName, ParsePlaceholders(logPlayer, actionButton.Commands[0]));
}
}
_actionMessage.Components = builder.Build();
}
_actionChannel.CreateMessage(Client, _actionMessage);
}
if (!string.IsNullOrEmpty(button.PlayerMessage))
{
BasePlayer player = logPlayer.Object as BasePlayer;
if (player != null && player.IsConnected)
{
Chat(player, button.PlayerMessage);
}
}
if (!string.IsNullOrEmpty(button.ServerMessage))
{
_sb.Clear();
_sb.Append(button.ServerMessage);
ParsePlaceholders(logPlayer, _sb);
covalence.Server.Broadcast(_sb.ToString());
}
if (_pluginConfig.DisableDiscordButton)
{
DisableButton(interaction.Message, interaction.Data.CustomId);
}
interaction.CreateResponse(Client, new InteractionResponse
{
Type = InteractionResponseType.UpdateMessage,
Data = new InteractionCallbackData
{
Components = interaction.Message.Components
}
});
}
finally
{
_log = null;
_activeMember = null;
_interaction = null;
}
}
public bool UserHasButtonPermission(DiscordInteraction interaction, ImageMessageButtonCommand button)
{
for (int index = 0; index < button.AllowedRoles.Count; index++)
{
Snowflake role = button.AllowedRoles[index];
if (interaction.Member.HasRole(role))
{
return true;
}
}
IPlayer player = interaction.Member.User.Player;
for (int index = 0; index < button.AllowedGroups.Count; index++)
{
string group = button.AllowedGroups[index];
if (permission.UserHasGroup(player.Id, group))
{
return true;
}
}
return false;
}
public void DisableButton(DiscordMessage message, string id)
{
for (int index = 0; index < message.Components.Count; index++)
{
ActionRowComponent row = message.Components[index];
for (int i = 0; i < row.Components.Count; i++)
{
BaseComponent component = row.Components[i];
if (component is ButtonComponent)
{
ButtonComponent button = (ButtonComponent)component;
if (button.CustomId == id)
{
button.Disabled = true;
return;
}
}
}
}
}
public void DisableAllButtons(DiscordMessage message)
{
for (int index = 0; index < message.Components.Count; index++)
{
ActionRowComponent row = message.Components[index];
for (int i = 0; i < row.Components.Count; i++)
{
BaseComponent component = row.Components[i];
if (component is ButtonComponent)
{
ButtonComponent button = (ButtonComponent)component;
button.Disabled = true;
}
}
}
}
private void SendComponentUpdateResponse(DiscordInteraction interaction)
{
interaction.CreateResponse(Client, new InteractionResponse
{
Type = InteractionResponseType.UpdateMessage,
Data = new InteractionCallbackData
{
Components = interaction.Message.Components
}
});
}
public void CreateResponse(DiscordInteraction interaction, string response)
{
interaction.CreateResponse(Client, new InteractionResponse
{
Type = InteractionResponseType.ChannelMessageWithSource,
Data = new InteractionCallbackData
{
Content = response,
Flags = MessageFlags.Ephemeral
}
});
}
#endregion
#region Plugins\DiscordSignLogger.DiscordMethods.cs
public void SendDiscordMessage(BaseImageUpdate update)
{
try
{
_log = update;
SignUpdateLog log = new SignUpdateLog(update);
for (int index = 0; index < update.Messages.Count; index++)
{
SignMessage signMessage = update.Messages[index];
MessageConfig message = signMessage.MessageConfig;
MessageCreate create = new MessageCreate();
if (!string.IsNullOrEmpty(message.Content))
{
create.Content = ParsePlaceholders(null, message.Content);
}
if (message.Embeds.Count != 0)
{
create.Embeds = new List<DiscordEmbed>(message.Embeds.Count);
foreach (EmbedConfig config in message.Embeds)
{
create.Embeds.Add(BuildEmbed(update.Player, config, update));
}
}
create.AddAttachment("image.png", update.GetImage(), "image/png", $"{update.DisplayName} Updated {update.Entity.ShortPrefabName} @{update.Entity.transform.position} On {DateTime.Now:f}");
MessageComponentBuilder builder = new MessageComponentBuilder();
for (int i = 0; i < signMessage.Commands.Count; i++)
{
ImageMessageButtonCommand command = signMessage.Commands[i];
if (command.Commands.Count == 0)
{
continue;
}
if (command.Style == ButtonStyle.Link)
{
builder.AddLinkButton(command.DisplayName, ParsePlaceholders(update.Player, command.Commands[0]));
}
else
{
builder.AddActionButton(command.Style, command.DisplayName, command.CommandCustomId);
}
}
create.Components = builder.Build();
signMessage.MessageChannel?.CreateMessage(Client, create).Then(discordMessage => { _pluginData.AddLog(discordMessage.Id, log); });
}
}
finally
{
_log = null;
}
}
private DiscordEmbed BuildEmbed(IPlayer player, EmbedConfig embed, BaseImageUpdate update)
{
DiscordEmbedBuilder builder = new DiscordEmbedBuilder();
if (!string.IsNullOrEmpty(embed.Title))
{
builder.AddTitle(ParsePlaceholders(player, embed.Title));
}
if (!string.IsNullOrEmpty(embed.Description))
{
builder.AddDescription(ParsePlaceholders(player, embed.Description));
}
if (!string.IsNullOrEmpty(embed.Url))
{
builder.AddUrl(ParsePlaceholders(player, embed.Url));
}
if (!string.IsNullOrEmpty(embed.Image))
{
builder.AddImage(ParsePlaceholders(player, embed.Image));
}
if (!string.IsNullOrEmpty(embed.Thumbnail))
{
builder.AddThumbnail(ParsePlaceholders(player, embed.Thumbnail));
}
if (!string.IsNullOrEmpty(embed.Color))
{
builder.AddColor(embed.Color);
}
if (embed.Timestamp)
{
builder.AddNowTimestamp();
}
if (embed.Footer.Enabled)
{
if (string.IsNullOrEmpty(embed.Footer.Text) &&
string.IsNullOrEmpty(embed.Footer.IconUrl))
{
AddPluginInfoFooter(builder);
}
else
{
string text = ParsePlaceholders(player, embed.Footer.Text);
string footerUrl = ParsePlaceholders(player, embed.Footer.IconUrl);
builder.AddFooter(text, footerUrl);
}
}
foreach (EmbedFieldConfig field in embed.Fields)
{
builder.AddField(ParsePlaceholders(player, field.Title), ParsePlaceholders(player, field.Value), field.Inline);
}
if (update is SignageUpdate)
{
SignageUpdate signage = (SignageUpdate)update;
if (!string.IsNullOrEmpty(signage.Url))
{
builder.AddField(ParsePlaceholders(player, Lang(LangKeys.SignArtistTitle)), ParsePlaceholders(player, Lang(LangKeys.SignArtistValue)), true);
}
}
return builder.Build();
}
private const string OwnerIcon = "https://i.postimg.cc/cLGQsP1G/Sign-3.png";
private void AddPluginInfoFooter(DiscordEmbedBuilder embed)
{
embed.AddFooter($"{Title} V{Version} by {Author}", OwnerIcon);
}
#endregion
#region Plugins\DiscordSignLogger.Commands.cs
[ConsoleCommand("dsl.erase")]
private void EraseCommand(ConsoleSystem.Arg arg)
{
if (!arg.IsAdmin)
{
return;
}
NetworkableId id = arg.GetEntityID(0);
uint index = arg.GetUInt(1);
BaseEntity entity = BaseNetworkable.serverEntities.Find(id) as BaseEntity;
if (entity == null)
{
return;
}
if (entity is ISignage)
{
ISignage signage = (ISignage)entity;
uint[] textures = signage.GetTextureCRCs();
uint crc = textures[index];
if (crc == 0)
{
return;
}
FileStorage.server.RemoveExact(crc, FileStorage.Type.png, signage.NetworkID, index);
textures[index] = 0;
entity.SendNetworkUpdate();
HandleReplaceImage(signage, index);
return;
}
if (entity is PaintedItemStorageEntity)
{
PaintedItemStorageEntity item = (PaintedItemStorageEntity)entity;
if (item._currentImageCrc != 0)
{
FileStorage.server.RemoveExact(item._currentImageCrc, FileStorage.Type.png, item.net.ID, 0);
item._currentImageCrc = 0;
item.SendNetworkUpdate();
}
}
if (entity is PatternFirework)
{
PatternFirework firework = (PatternFirework)entity;
firework.Design?.Dispose();
firework.Design = null;
firework.SendNetworkUpdateImmediate();
}
}
[ConsoleCommand("dsl.signblock")]
private void BanCommand(ConsoleSystem.Arg arg)
{
if (!arg.IsAdmin)
{
return;
}
ulong playerId = arg.GetULong(0);
float duration = arg.GetFloat(1);
_pluginData.AddSignBan(playerId, duration);
if (duration <= 0)
{
arg.ReplyWith($"{playerId} has been sign blocked permanently");
}
else
{
arg.ReplyWith($"{playerId} has been sign blocked for {GetFormattedDurationTime(TimeSpan.FromSeconds(duration))}");
}
SaveData();
}
[ConsoleCommand("dsl.signunblock")]
private void UnbanCommand(ConsoleSystem.Arg arg)
{
if (!arg.IsAdmin)
{
return;
}
ulong playerId = arg.GetULong(0);
_pluginData.RemoveSignBan(playerId);
SaveData();
arg.ReplyWith($"{playerId} has been unbanned");
}
private void HandleReplaceImage(ISignage signage, uint index)
{
if (_pluginConfig.ReplaceImage.Mode == ErasedMode.None || SignArtist == null || !SignArtist.IsLoaded)
{
return;
}
ReplaceImageSettings image = _pluginConfig.ReplaceImage;
if (signage is Signage)
{
if (image.Mode == ErasedMode.Text)
{
SignArtist.Call("API_SignText", null, signage, image.Message, image.FontSize, image.TextColor, image.BodyColor, index);
}
else if (!string.IsNullOrEmpty(image.Url))
{
SignArtist.Call("API_SkinSign", null, signage, image.Url, _false, index);
}
}
else if (signage is PhotoFrame)
{
if (!string.IsNullOrEmpty(image.Url))
{
SignArtist.Call("API_SkinPhotoFrame", null, signage, image.Url);
}
}
else if (signage is CarvablePumpkin)
{
if (!string.IsNullOrEmpty(image.Url))
{
SignArtist.Call("API_SkinPumpkin", null, signage, image.Url);
}
}
}
#endregion
#region Plugins\DiscordSignLogger.Helpers.cs
public DiscordChannel GetChannel(DiscordGuild guild, Snowflake id)
{
return guild?.Channels[id] ?? guild?.Threads[id];
}
public IPlayer FindPlayerById(string id)
{
return covalence.Players.FindPlayerById(id);
}
public string Lang(string key, BasePlayer player = null)
{
return lang.GetMessage(key, this, player ? player.UserIDString : null);
}
public string Lang(string key, BasePlayer player = null, params object[] args)
{
try
{
return string.Format(lang.GetMessage(key, this, player ? player.UserIDString : null), args);
}
catch (Exception ex)
{
PrintError($"Lang Key '{key}' threw exception\n:{ex}");
throw;
}
}
public void Chat(BasePlayer player, string key) => PrintToChat(player, Lang(LangKeys.Chat, player, Lang(key, player)));
public void Chat(BasePlayer player, string key, params object[] args) => PrintToChat(player, Lang(LangKeys.Chat, player, Lang(key, player, args)));
public void SaveData() => Interface.Oxide.DataFileSystem.WriteObject(Name, _pluginData);
public void SaveButtonData() => Interface.Oxide.DataFileSystem.WriteObject(Name + "_Buttons", _buttonData);
#endregion
#region Plugins\DiscordSignLogger.Lang.cs
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
[LangKeys.Chat] = $"<color=#bebebe>[<color={AccentColor}>{Title}</color>] {{0}}</color>",
[LangKeys.NoPermission] = "You do not have permission to perform this action",
[LangKeys.KickReason] = "Inappropriate sign/firework image",
[LangKeys.BanReason] = "Inappropriate sign/firework image",
[LangKeys.BlockedMessage] = "You're not allowed to update this sign/firework because you have been blocked.Your block will expire in {0}.",
[LangKeys.ActionMessage] = $"[{Title}] <@{{dsl.discord.user.id}}> ran command \"{{dsl.command}}\"",
[LangKeys.DeletedLog] = "The log data for this message was not found.If it's older than {0} days then it may have been deleted.",
[LangKeys.DeletedButtonCache] = "Button was not found in cache.If this message is older than {0} days then it may have been deleted.",
[LangKeys.SignArtistTitle] = "Sign Artist URL:",
[LangKeys.SignArtistValue] = "{dsl.signartist.url}",
[LangKeys.Format.Day] = "day ",
[LangKeys.Format.Days] = "days ",
[LangKeys.Format.Hour] = "hour ",
[LangKeys.Format.Hours] = "hours ",
[LangKeys.Format.Minute] = "minute ",
[LangKeys.Format.Minutes] = "minutes ",
[LangKeys.Format.Second] = "second",
[LangKeys.Format.Seconds] = "seconds",
[LangKeys.Format.TimeField] = $"<color={AccentColor}>{{0}}</color> {{1}}"
}, this);
lang.RegisterMessages(new Dictionary<string, string>
{
[LangKeys.Chat] = $"<color=#bebebe>[<color={AccentColor}>{Title}</color>] {{0}}</color>",
[LangKeys.NoPermission] = "У вас нет разрешения на выполнение этого действия",
[LangKeys.KickReason] = "Недопустимое изображение знака/фейерверка",
[LangKeys.BanReason] = "Недопустимое изображение знака/фейерверка",
[LangKeys.BlockedMessage] = "Возможность использовать изображения на знаке/феерверке для вас заблокирована.Разблокировка через {0}.",
[LangKeys.ActionMessage] = $"[{Title}] <@{{dsl.discord.user.id}}> выполнил команду \"{{dsl.command}}\"",
[LangKeys.DeletedLog] = "Данные журнала для этого сообщения не найдены.Если сообщение старше {0} дней, возможно, оно было удалено.",
[LangKeys.DeletedButtonCache] = "Кнопка не найдена в кеше.Если сообщение старше {0} дней, возможно, оно было удалено.",
[LangKeys.SignArtistTitle] = "Sign Artist URL:",
[LangKeys.SignArtistValue] = "{dsl.signartist.url}",
[LangKeys.Format.Day] = "день ",
[LangKeys.Format.Days] = "дней ",
[LangKeys.Format.Hour] = "час ",
[LangKeys.Format.Hours] = "часов ",
[LangKeys.Format.Minute] = "минуту ",
[LangKeys.Format.Minutes] = "минут ",
[LangKeys.Format.Second] = "секунду",
[LangKeys.Format.Seconds] = "секунд",
[LangKeys.Format.TimeField] = $"<color={AccentColor}>{{0}}</color> {{1}}"
}, this, "ru");
}
private string GetFormattedDurationTime(TimeSpan time, BasePlayer player = null)
{
_sb.Clear();
if (time.TotalDays >= 1)
{
BuildTime(_sb, time.Days == 1 ? LangKeys.Format.Day : LangKeys.Format.Days, player, time.Days);
}
if (time.TotalHours >= 1)
{
BuildTime(_sb, time.Hours == 1 ? LangKeys.Format.Hour : LangKeys.Format.Hours, player, time.Hours);
}
if (time.TotalMinutes >= 1)
{
BuildTime(_sb, time.Minutes == 1 ? LangKeys.Format.Minute : LangKeys.Format.Minutes, player, time.Minutes);
}
BuildTime(_sb, time.Seconds == 1 ? LangKeys.Format.Second : LangKeys.Format.Seconds, player, time.Seconds);
return _sb.ToString();
}
private void BuildTime(StringBuilder sb, string key, BasePlayer player, int value)
{
sb.Append(Lang(LangKeys.Format.TimeField, player, value, Lang(key, player)));
}
#endregion
#region Plugins\DiscordSignLogger.PlaceholderApi.cs
#pragma warning disable CS0649
[PluginReference] private Plugin PlaceholderAPI;
#pragma warning restore CS0649
private Action<IPlayer, StringBuilder, bool> _replacer;
private string ParsePlaceholders(IPlayer player, string field)
{
_sb.Clear();
_sb.Append(field);
GetReplacer()?.Invoke(player, _sb, false);
if (_sb.Length == 0)
{
_sb.Append("");
}
return _sb.ToString();
}
private void ParsePlaceholders(IPlayer player, StringBuilder sb)
{
GetReplacer()?.Invoke(player, sb, false);
}
private void OnPluginUnloaded(Plugin plugin)
{
if (plugin?.Name == "PlaceholderAPI")
{
_replacer = null;
}
}
public string GetSignAristUrl()
{
SignageUpdate signage = _log as SignageUpdate;
return signage?.Url ?? string.Empty;
}
private void OnPlaceholderAPIReady()
{
RegisterPlaceholder("dsl.entity.id", (player, s) =>
{
BaseEntity entity = _log.Entity;
return entity ? entity.net?.ID.Value ?? 0 : 0;
}, "Displays the entity ID");
RegisterPlaceholder("dsl.entity.textureindex", (player, s) => _log?.TextureIndex ?? 0, "Displays the texture index");
RegisterPlaceholder("dsl.entity.name", (player, s) =>
{
if (_log.ItemId != 0)
{
return GetItemName(_log.ItemId);
}
BaseEntity entity = _log.Entity;
return entity ? GetEntityName(entity) : "Entity Not Found";
}, "Displays the entity item name");
RegisterPlaceholder("dsl.entity.owner.id", (player, s) =>
{
BaseEntity entity = _log.Entity;
return entity ? entity.OwnerID : 0;
}, "Displays the entity Owner ID");
RegisterPlaceholder("dsl.entity.owner.name", (player, s) =>
{
BaseEntity entity = _log.Entity;
if (!entity)
{
return "Unknown";
}
IPlayer owner = covalence.Players.FindPlayerById(entity.OwnerID.ToString());
if (owner == null)
{
return "Unknown";
}
BasePlayer ownerPlayer = (BasePlayer)owner.Object;
return ownerPlayer ? ownerPlayer.displayName : owner.Name;
}, "Displays the entity owner player name");
RegisterPlaceholder("dsl.entity.position", (player, s) =>
{
BaseEntity entity = _log.Entity;
if (!entity)
{
if (string.IsNullOrEmpty(s))
{
return Vector3.zero;
}
return 0f;
}
Vector3 pos = entity.transform.position;
if (string.IsNullOrEmpty(s))
{
return pos;
}
if (s.Equals("x", StringComparison.OrdinalIgnoreCase))
{
return pos.x;
}
if (s.Equals("y", StringComparison.OrdinalIgnoreCase))
{
return pos.y;
}
if (s.Equals("z", StringComparison.OrdinalIgnoreCase))
{
return pos.z;
}
return pos;
}, "Displays the position of the entity");
RegisterPlaceholder("dsl.discord.user.id", (player, s) => _activeMember?.Id ?? default(Snowflake), "Discord user id who clicked the button");
RegisterPlaceholder("dsl.discord.user.name", (player, s) => _activeMember?.DisplayName ?? "Unknown User", "Discord display name of user who clicked the button");
RegisterPlaceholder("dsl.kick.reason", (player, s) => Lang(LangKeys.KickReason), "Kick Reason Lang Value");
RegisterPlaceholder("dsl.ban.reason", (player, s) => Lang(LangKeys.BanReason), "Ban Reason Lang Value");
RegisterPlaceholder("dsl.signartist.url", (player, s) => GetSignAristUrl(), "Sign Artist URL");
RegisterPlaceholder("dsl.action.guild.id", (player, s) => _interaction?.GuildId ?? default(Snowflake), "Actioned Message Guild ID");
RegisterPlaceholder("dsl.action.channel.id", (player, s) => _interaction?.ChannelId ?? default(Snowflake), "Actioned Message Channel ID");
RegisterPlaceholder("dsl.action.message.id", (player, s) => _interaction.Message?.Id ?? default(Snowflake), "Actioned Message Message ID");
}
private void RegisterPlaceholder(string key, Func<IPlayer, string, object> action, string description = null)
{
if (IsPlaceholderApiLoaded())
{
PlaceholderAPI.Call("AddPlaceholder", this, key, action, description);
}
}
private Action<IPlayer, StringBuilder, bool> GetReplacer()
{
if (!IsPlaceholderApiLoaded())
{
return _replacer;
}
return _replacer ?? (_replacer = PlaceholderAPI.Call<Action<IPlayer, StringBuilder, bool>>("GetProcessPlaceholders", 1));
}
private bool IsPlaceholderApiLoaded() => PlaceholderAPI != null && PlaceholderAPI.IsLoaded;
#endregion
#region Plugins\DiscordSignLogger.RustTranslationApi.cs
public string GetEntityName(BaseEntity entity)
{
if (!entity)
{
return string.Empty;
}
if (RustTranslationAPI != null && RustTranslationAPI.IsLoaded)
{
string name = RustTranslationAPI.Call<string>("GetDeployableTranslation", lang.GetServerLanguage(), entity.ShortPrefabName);
if (!string.IsNullOrEmpty(name))
{
return name;
}
}
return _prefabNameLookup[entity.ShortPrefabName] ?? entity.ShortPrefabName;
}
public string GetItemName(int itemId)
{
if (itemId == 0)
{
return string.Empty;
}
if (RustTranslationAPI != null && RustTranslationAPI.IsLoaded)
{
string name = RustTranslationAPI.Call<string>("GetItemTranslationByID", lang.GetServerLanguage(), itemId);
if (!string.IsNullOrEmpty(name))
{
return name;
}
}
return ItemManager.FindItemDefinition(itemId).displayName.translated;
}
#endregion
#region Configuration\BaseDiscordButton.cs
public class BaseDiscordButton
{
[JsonProperty(PropertyName = "Button Display Name")]
public string DisplayName { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
[JsonProperty(PropertyName = "Button Style")]
public ButtonStyle Style { get; set; }
[JsonProperty(PropertyName = "Commands")]
public List<string> Commands { get; set; }
[JsonConstructor]
public BaseDiscordButton()
{
}
public BaseDiscordButton(BaseDiscordButton settings)
{
DisplayName = settings?.DisplayName ?? "Button Display Name";
Style = settings?.Style ?? ButtonStyle.Primary;
Commands = settings?.Commands ?? new List<string>();
}
}
#endregion
#region Configuration\FireworkSettings.cs
public class FireworkSettings
{
[JsonProperty(PropertyName = "Image Size (Pixels)")]
public int ImageSize { get; set; }
[JsonProperty(PropertyName = "Circle Size (Pixels)")]
public int CircleSize { get; set; }
public FireworkSettings(FireworkSettings settings)
{
ImageSize = settings?.ImageSize ?? 25
// ... [Code preview truncated due to length. Full source in attached file] ...