diff --git a/ChatTwo/ChatTwo.csproj b/ChatTwo/ChatTwo.csproj index c788535..645e11c 100755 --- a/ChatTwo/ChatTwo.csproj +++ b/ChatTwo/ChatTwo.csproj @@ -1,6 +1,6 @@ - 1.24.3 + 1.24.4 net8.0-windows enable enable diff --git a/ChatTwo/EmoteCache.cs b/ChatTwo/EmoteCache.cs index ff58302..ba52201 100644 --- a/ChatTwo/EmoteCache.cs +++ b/ChatTwo/EmoteCache.cs @@ -11,6 +11,13 @@ namespace ChatTwo; public static class EmoteCache { + private static readonly HttpClient Client = new(); + + private const string BetterTTV = "https://api.betterttv.net/3"; + private const string GlobalEmotes = $"{BetterTTV}/cached/emotes/global"; + private const string Top100Emotes = "{0}/emotes/shared/top?before={1}&limit=100"; + private const string EmotePath = "https://cdn.betterttv.net/emote/{0}/1x"; + private struct Top100 { [JsonPropertyName("emote")] @@ -37,18 +44,11 @@ public static class EmoteCache Done } - private const string BetterTTV = "https://api.betterttv.net/3"; - private const string GlobalEmotes = $"{BetterTTV}/cached/emotes/global"; - private const string Top100Emotes = "{0}/emotes/shared/top?before={1}&limit=100"; - private const string EmotePath = "https://cdn.betterttv.net/emote/{0}/1x"; - - private static readonly HttpClient Client = new(); - // All of this data is uninitalized while State is not `LoadingState.Done` public static LoadingState State = LoadingState.Unloaded; - private static Dictionary EmoteImages = new(); - private static Dictionary Cache = new(); + private static readonly Dictionary Cache = new(); + private static readonly Dictionary EmoteImages = new(); public static string[] SortedCodeArray = []; @@ -127,9 +127,9 @@ public static class EmoteCache public class IEmote { + public bool Failed; public bool IsLoaded; - public bool IsAnimated = false; public IDalamudTextureWrap Texture; public virtual void Draw(Vector2 size) @@ -182,6 +182,7 @@ public static class EmoteCache } catch (Exception ex) { + Failed = true; Plugin.Log.Error(ex, $"Unable to load {emote.Code} with id {emote.Id}"); } } @@ -271,6 +272,7 @@ public static class EmoteCache } catch (Exception ex) { + Failed = true; Plugin.Log.Error(ex, $"Unable to load {emote.Code} with id {emote.Id}"); } } diff --git a/ChatTwo/Ui/ChatLogWindow.cs b/ChatTwo/Ui/ChatLogWindow.cs index 2e28570..808988c 100644 --- a/ChatTwo/Ui/ChatLogWindow.cs +++ b/ChatTwo/Ui/ChatLogWindow.cs @@ -1513,8 +1513,11 @@ public sealed class ChatLogWindow : Window DrawChunk(chunks[i], wrap, handler, lineWidth); if (i < chunks.Count - 1) + { ImGui.SameLine(); - else if (chunks[i].Link is EmotePayload && Plugin.Config.ShowEmotes) { + } + else if (chunks[i].Link is EmotePayload && Plugin.Config.ShowEmotes) + { // Emote payloads seem to not automatically put newlines, which // is an issue when modern mode is disabled. ImGui.SameLine(); @@ -1554,16 +1557,20 @@ public sealed class ChatLogWindow : Window var emoteSize = ImGui.CalcTextSize("W"); emoteSize = emoteSize with { Y = emoteSize.X } * 1.5f; + // We only draw a dummy if it is still loading, in the case it failed we draw the actual name var image = EmoteCache.GetEmote(emotePayload.Code); - if (image is { IsLoaded: true }) - image.Draw(emoteSize); - else - ImGui.Dummy(emoteSize); + if (image is { Failed: false }) + { + if (image.IsLoaded) + image.Draw(emoteSize); + else + ImGui.Dummy(emoteSize); - if (ImGui.IsItemHovered()) - ImGui.SetTooltip(emotePayload.Code); + if (ImGui.IsItemHovered()) + ImGui.SetTooltip(emotePayload.Code); - return; + return; + } } var colour = text.Foreground; diff --git a/ChatTwo/Util/ChunkUtil.cs b/ChatTwo/Util/ChunkUtil.cs index ada1040..2f33482 100755 --- a/ChatTwo/Util/ChunkUtil.cs +++ b/ChatTwo/Util/ChunkUtil.cs @@ -5,8 +5,10 @@ using System.Text; namespace ChatTwo.Util; -internal static class ChunkUtil { - internal static IEnumerable ToChunks(SeString msg, ChunkSource source, ChatType? defaultColour) { +internal static class ChunkUtil +{ + internal static IEnumerable ToChunks(SeString msg, ChunkSource source, ChatType? defaultColour) + { var chunks = new List(); var italic = false; @@ -14,8 +16,10 @@ internal static class ChunkUtil { var glow = new Stack(); Payload? link = null; - void Append(string text) { - chunks.Add(new TextChunk(source, link, text) { + void Append(string text) + { + chunks.Add(new TextChunk(source, link, text) + { FallbackColour = defaultColour, Foreground = foreground.Count > 0 ? foreground.Peek() : null, Glow = glow.Count > 0 ? glow.Peek() : null, @@ -23,29 +27,27 @@ internal static class ChunkUtil { }); } - foreach (var payload in msg.Payloads) { - switch (payload.Type) { + foreach (var payload in msg.Payloads) + { + switch (payload.Type) + { case PayloadType.EmphasisItalic: var newStatus = ((EmphasisItalicPayload) payload).IsEnabled; italic = newStatus; break; case PayloadType.UIForeground: var foregroundPayload = (UIForegroundPayload) payload; - if (foregroundPayload.IsEnabled) { + if (foregroundPayload.IsEnabled) foreground.Push(foregroundPayload.UIColor.UIForeground); - } else if (foreground.Count > 0) { + else if (foreground.Count > 0) foreground.Pop(); - } - break; case PayloadType.UIGlow: var glowPayload = (UIGlowPayload) payload; - if (glowPayload.IsEnabled) { + if (glowPayload.IsEnabled) glow.Push(glowPayload.UIColor.UIGlow); - } else if (glow.Count > 0) { + else if (glow.Count > 0) glow.Pop(); - } - break; case PayloadType.AutoTranslateText: chunks.Add(new IconChunk(source, link, BitmapFontIcon.AutoTranslateBegin)); @@ -86,7 +88,8 @@ internal static class ChunkUtil { } else if (rawPayload.Data.Length > 1 && rawPayload.Data[1] == 0x14) { - if (glow.Count > 0) { + if (glow.Count > 0) + { glow.Pop(); } else if (rawPayload.Data.Length > 6 && rawPayload.Data[2] == 0x05 && rawPayload.Data[3] == 0xF6) @@ -95,30 +98,34 @@ internal static class ChunkUtil { glow.Push(ColourUtil.ComponentsToRgba(r, g, b)); } } - else if (rawPayload.Data.Length > 7 && rawPayload.Data[1] == 0x27 && rawPayload.Data[3] == 0x0A) { + else if (rawPayload.Data.Length > 7 && rawPayload.Data[1] == 0x27 && rawPayload.Data[3] == 0x0A) + { // pf payload var reader = new BinaryReader(new MemoryStream(rawPayload.Data[4..])); var id = GetInteger(reader); link = new PartyFinderPayload(id); - } else if (rawPayload.Data.Length > 5 && rawPayload.Data[1] == 0x27 && rawPayload.Data[3] == 0x06) { + } + else if (rawPayload.Data.Length > 5 && rawPayload.Data[1] == 0x27 && rawPayload.Data[3] == 0x06) + { // achievement payload var reader = new BinaryReader(new MemoryStream(rawPayload.Data[4..])); var id = GetInteger(reader); link = new AchievementPayload(id); - } else if (rawPayload.Data.Length > 5 && rawPayload.Data[1] == 0x27 && rawPayload.Data[3] == 0x07) { + } + else if (rawPayload.Data.Length > 5 && rawPayload.Data[1] == 0x27 && rawPayload.Data[3] == 0x07) + { // uri payload var uri = new Uri(Encoding.UTF8.GetString(rawPayload.Data[4..])); link = new UriPayload(uri); - } else if (Equals(rawPayload, RawPayload.LinkTerminator)) { + } + else if (Equals(rawPayload, RawPayload.LinkTerminator)) + { link = null; } - break; default: - if (payload is ITextProvider textProvider) { + if (payload is ITextProvider textProvider) Append(textProvider.Text); - } - break; } } @@ -126,21 +133,18 @@ internal static class ChunkUtil { return chunks; } - internal static readonly RawPayload PeriodicRecruitmentLink = new(new byte[] { - 0x02, 0x27, 0x07, 0x08, 0x01, 0x01, 0x01, 0xFF, 0x01, 0x03, - }); + internal static readonly RawPayload PeriodicRecruitmentLink = new([0x02, 0x27, 0x07, 0x08, 0x01, 0x01, 0x01, 0xFF, 0x01, 0x03]); - private static uint GetInteger(BinaryReader input) { + private static uint GetInteger(BinaryReader input) + { var num1 = (uint) input.ReadByte(); - if (num1 < 208U) { + if (num1 < 208U) return num1 - 1U; - } var num2 = (uint) ((int) num1 + 1 & 15); var numArray = new byte[4]; - for (var index = 3; index >= 0; --index) { + for (var index = 3; index >= 0; --index) numArray[index] = (num2 & 1 << index) == 0L ? (byte) 0 : input.ReadByte(); - } return BitConverter.ToUInt32(numArray, 0); }