From 735bc8e8ae721e6c5a9971b149fe6c4c5daa7a83 Mon Sep 17 00:00:00 2001 From: Michael Chen Date: Tue, 18 Jan 2022 11:46:23 +0100 Subject: [PATCH] Bump version to 1.1.2 Cleaner item list display Allow full item list as file Fixed online status message with new handler --- .../MinecraftDiscordBot.csproj | 2 +- MinecraftDiscordBot/Models/Fluid.cs | 2 ++ MinecraftDiscordBot/Models/Item.cs | 21 ++++++++++++++- MinecraftDiscordBot/Program.cs | 23 ++++++++++++++-- .../Services/RefinedStorageService.cs | 26 ++++++++++++++++--- 5 files changed, 67 insertions(+), 7 deletions(-) diff --git a/MinecraftDiscordBot/MinecraftDiscordBot.csproj b/MinecraftDiscordBot/MinecraftDiscordBot.csproj index 21f27df..3cf40ea 100644 --- a/MinecraftDiscordBot/MinecraftDiscordBot.csproj +++ b/MinecraftDiscordBot/MinecraftDiscordBot.csproj @@ -6,7 +6,7 @@ enable enable Linux - 1.1.1 + 1.1.2 Michael Chen $(Authors) https://gitlab.com/chenmichael/mcdiscordbot diff --git a/MinecraftDiscordBot/Models/Fluid.cs b/MinecraftDiscordBot/Models/Fluid.cs index 07c4556..11e4b78 100644 --- a/MinecraftDiscordBot/Models/Fluid.cs +++ b/MinecraftDiscordBot/Models/Fluid.cs @@ -19,4 +19,6 @@ public class Fluid { : $"{Amount:n0} mB of {DisplayName}"; [JsonIgnore] public string CleanDisplayName => DisplayName[1..^1]; + [JsonIgnore] + public string? TagString => Tags is string[] tags ? string.Join(", ", tags) : null; } diff --git a/MinecraftDiscordBot/Models/Item.cs b/MinecraftDiscordBot/Models/Item.cs index 70e5298..05bc556 100644 --- a/MinecraftDiscordBot/Models/Item.cs +++ b/MinecraftDiscordBot/Models/Item.cs @@ -1,5 +1,6 @@ using Newtonsoft.Json; using System.Diagnostics; +using System.Text; namespace MinecraftDiscordBot.Models; @@ -10,5 +11,23 @@ public class Item : Fluid { public Md5Hash Fingerprint { get; set; } = default!; [JsonProperty("nbt", Required = Required.DisallowNull)] public dynamic? NBT { get; set; } - public override string ToString() => $"{Amount:n0}x {DisplayName}"; + public override string ToString() => $"{AmountString} {CleanDisplayName}"; + [JsonIgnore] + public string DetailString { + get { + var sb = new StringBuilder(); + sb.AppendFormat("{0} {1}, fp: {2}", AmountString, CleanDisplayName, Fingerprint); + if (TagString is string tags) + sb.AppendFormat(", tags: [{0}]", tags); + if (NBT is not null) + sb.AppendFormat(", NBT: {0}", JsonConvert.SerializeObject(NBT)); + return sb.ToString(); + } + } + [JsonIgnore] + public string AmountString => Amount switch { + > 1000000 => $"> {Amount / 1000000:n0}m", + > 10000 => $"~ {Amount / 1000.0f:n2}k", + _ => Amount.ToString() + }; } diff --git a/MinecraftDiscordBot/Program.cs b/MinecraftDiscordBot/Program.cs index 09a7474..44609c2 100644 --- a/MinecraftDiscordBot/Program.cs +++ b/MinecraftDiscordBot/Program.cs @@ -57,10 +57,11 @@ public class Program : IDisposable, ICommandHandler, IUserRoleMana _config = config; _computer = new(this); _computer.ChatMessageReceived += MinecraftMessageReceived; + _computer.SocketChanged += ComputerConnectedChanged; _administrators = config.Administrators.ToHashSet(); ClientScript = GetClientScript(config); _client.Log += LogAsync; - _client.MessageReceived += (msg) => DiscordMessageReceived(msg); + _client.MessageReceived += (msg) => DiscordMessageReceived(msg, 20 * 1000); _client.ReactionAdded += DiscordReactionAdded; _wssv = new WebSocketServer($"ws://0.0.0.0:{config.Port}") { RestartAfterListenError = true @@ -69,6 +70,11 @@ public class Program : IDisposable, ICommandHandler, IUserRoleMana _whitelistedChannels = config.Channels.ToHashSet(); } + private void ComputerConnectedChanged(object? sender, IWebSocketConnection? e) { + _ = Task.Run(() => Broadcast(i => i.SendMessageAsync(e is not null + ? "The Minecraft client is now available!" + : "The Minecraft client disconnected!"))); + } private void MinecraftMessageReceived(object? sender, ChatEvent e) => Task.Run(() => WebhookBroadcast(i => i.SendMessageAsync(e.Message, username: e.Username, avatarUrl: $"https://crafatar.com/renders/head/{e.UUID}"))); private Task WebhookBroadcast(Func> apply) => Task.WhenAll(Channels.Select(i => apply(new DiscordWebhookClient(i.Webhook)))); @@ -211,7 +217,8 @@ public class Program : IDisposable, ICommandHandler, IUserRoleMana private Task SendResponse(SocketUserMessage message, ResponseType response) => response switch { ResponseType.IChoiceResponse res => HandleChoice(message, res), ResponseType.StringResponse res => message.ReplyAsync(res.Message), - _ => message.ReplyAsync($"Whoops, someone forgot to implement '{response.GetType()}' responses?"), + ResponseType.FileResponse res => message.Channel.SendFileAsync(res.Path, text: res.Message), + _ => message.ReplyAsync($"Whoops, someone forgot to implement '{response.GetType().Name}' responses?"), }; private readonly ConcurrentDictionary _choiceWait = new(); @@ -340,6 +347,8 @@ public abstract class ResponseType { private static string DefaultDisplay(T obj) => obj?.ToString() ?? throw new InvalidProgramException("ToString did not yield anything!"); public static ResponseType AsString(string message) => new StringResponse(message); public static ResponseType FromChoice(string query, IEnumerable choice, Func resultHandler, Func? display = null) => new ChoiceResponse(query, choice, resultHandler, display ?? DefaultDisplay); + internal static ResponseType File(string path, string message) => new FileResponse(path, message); + public class StringResponse : ResponseType { public StringResponse(string message) => Message = message; public string Message { get; } @@ -363,4 +372,14 @@ public abstract class ResponseType { _displayer = display; } } + + public class FileResponse : ResponseType { + public FileResponse(string path, string message) { + Path = path; + Message = message; + } + + public string Path { get; } + public string Message { get; } + } } \ No newline at end of file diff --git a/MinecraftDiscordBot/Services/RefinedStorageService.cs b/MinecraftDiscordBot/Services/RefinedStorageService.cs index 9224e26..8f1fbeb 100644 --- a/MinecraftDiscordBot/Services/RefinedStorageService.cs +++ b/MinecraftDiscordBot/Services/RefinedStorageService.cs @@ -1,4 +1,5 @@ -using Discord.WebSocket; +using Discord; +using Discord.WebSocket; using MinecraftDiscordBot.Commands; using MinecraftDiscordBot.Models; using System.Text; @@ -146,6 +147,7 @@ public class RefinedStorageService : CommandRouter { [CommandHandler(CmdListItems, HelpText = "Gets a list of items that are currently stored in the RS system.")] public async Task HandleItemListing(SocketUserMessage message, string[] parameters, CancellationToken ct) { + if (parameters.Length is 1 && parameters[0] == "full") return await SendFullItemList(message, ct); var sb = new StringBuilder(); sb.Append("The Refined Storage system currently stores these items:"); var items = await RefreshItemList(ct); @@ -153,11 +155,29 @@ public class RefinedStorageService : CommandRouter { var taken = 0; foreach (var item in items) { if (sb.Length > 500) break; - sb.AppendFormat("\n{0:n0}x {1}", item.Amount, item.DisplayName); + sb.Append('\n'); + sb.Append(item.ToString()); taken++; } - if (items.Count > taken) sb.AppendFormat("\nand {0} more items.", items.Skip(taken).Sum(i => i.Amount)); + if (items.Count > taken) sb.AppendFormat("\nand {0:n0} more items.", items.Skip(taken).Sum(i => i.Amount)); } return ResponseType.AsString(sb.ToString()); } + + private async Task SendFullItemList(SocketUserMessage message, CancellationToken ct) { + var path = await GetItemListFile(ct); + return ResponseType.File(path, $"{message.Author.Mention} Here you go:"); + } + + private async Task GetItemListFile(CancellationToken ct) { + var items = await RefreshItemList(ct); + var file = Path.Combine(Path.GetTempPath(), "itemlist.txt"); + var fs = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Write); + using (var sw = new StreamWriter(fs, Encoding.UTF8)) { + await sw.WriteLineAsync("The RS System stores the following items:"); + foreach (var item in items) + await sw.WriteLineAsync(item.DetailString); + }; + return file; + } }