diff --git a/ChatTwo/EmoteCache.cs b/ChatTwo/EmoteCache.cs index 05cbe95..634927d 100644 --- a/ChatTwo/EmoteCache.cs +++ b/ChatTwo/EmoteCache.cs @@ -78,7 +78,7 @@ public static class EmoteCache var globalList = await global.Content.ReadAsStringAsync(); foreach (var emote in JsonSerializer.Deserialize(globalList)!) - if (!NotWorking.Contains(emote.Code)) + if (!string.IsNullOrEmpty(emote.Code) && !NotWorking.Contains(emote.Code)) Cache.TryAdd(emote.Code, emote); var lastId = string.Empty; @@ -88,8 +88,13 @@ public static class EmoteCache var topList = await top.Content.ReadAsStringAsync(); var jsonList = JsonSerializer.Deserialize>(topList)!; + // BetterTTV occasionally returns entries with a null Code; the + // upstream code passed those straight into Dictionary.TryAdd + // and tripped ArgumentNullException, killing the whole emote + // load. Skip them defensively so a single bad row no longer + // breaks the cache for everyone else. foreach (var emote in jsonList) - if (!NotWorking.Contains(emote.Emote.Code)) + if (!string.IsNullOrEmpty(emote.Emote.Code) && !NotWorking.Contains(emote.Emote.Code)) Cache.TryAdd(emote.Emote.Code, emote.Emote); lastId = jsonList.Last().Id; diff --git a/ChatTwo/FontManager.cs b/ChatTwo/FontManager.cs index 4bd4742..3f9c2e2 100644 --- a/ChatTwo/FontManager.cs +++ b/ChatTwo/FontManager.cs @@ -1,4 +1,6 @@ -using Dalamud.Interface; +using Dalamud; +using Dalamud.Interface; +using Dalamud.Interface.FontIdentifier; using Dalamud.Interface.GameFonts; using Dalamud.Interface.ManagedFontAtlas; using Dalamud.Interface.Utility; @@ -119,11 +121,11 @@ public class FontManager tk => { var config = new SafeFontConfig {SizePt = Plugin.Config.GlobalFontV2.SizePt, GlyphRanges = Ranges}; - config.MergeFont = Plugin.Config.GlobalFontV2.FontId.AddToBuildToolkit(tk, config); + config.MergeFont = AddFontWithFallback(tk, Plugin.Config.GlobalFontV2.FontId, config, "global"); config.SizePt = Plugin.Config.JapaneseFontV2.SizePt; config.GlyphRanges = JpRange; - Plugin.Config.JapaneseFontV2.FontId.AddToBuildToolkit(tk, config); + AddFontWithFallback(tk, Plugin.Config.JapaneseFontV2.FontId, config, "japanese"); config.SizePt = Plugin.Config.SymbolsFontSizeV2; tk.AddGameSymbol(config); @@ -139,11 +141,11 @@ public class FontManager tk => { var config = new SafeFontConfig {SizePt = Plugin.Config.ItalicFontV2.SizePt, GlyphRanges = Ranges}; - config.MergeFont = Plugin.Config.ItalicFontV2.FontId.AddToBuildToolkit(tk, config); + config.MergeFont = AddFontWithFallback(tk, Plugin.Config.ItalicFontV2.FontId, config, "italic"); config.SizePt = Plugin.Config.JapaneseFontV2.SizePt; config.GlyphRanges = JpRange; - Plugin.Config.JapaneseFontV2.FontId.AddToBuildToolkit(tk, config); + AddFontWithFallback(tk, Plugin.Config.JapaneseFontV2.FontId, config, "japanese"); config.SizePt = Plugin.Config.SymbolsFontSizeV2; tk.AddGameSymbol(config); @@ -158,6 +160,27 @@ public class FontManager } } + /// + /// Try to add a user-configured font to the build toolkit, falling back to + /// the bundled NotoSansCjkRegular asset if the configured font isn't + /// available on the system. Without this guard a stale SystemFontId + /// pointing at a font the user uninstalled or that never existed on + /// Linux (e.g. "Crimson Text") tears down the entire font atlas build. + /// + private static ImFontPtr AddFontWithFallback(IFontAtlasBuildToolkitPreBuild tk, IFontId fontId, SafeFontConfig config, string slot) + { + try + { + return fontId.AddToBuildToolkit(tk, config); + } + catch (Exception e) when (e is FileNotFoundException or DirectoryNotFoundException or IOException) + { + Plugin.Log.Warning(e, $"Configured {slot} font unavailable, falling back to NotoSansCjkRegular"); + var fallback = new DalamudAssetFontAndFamilyId(DalamudAsset.NotoSansCjkRegular); + return fallback.AddToBuildToolkit(tk, config); + } + } + public static float SizeInPt(float px) => (float) (px * 3.0 / 4.0); public static float SizeInPx(float pt) => (float) (pt * 4.0 / 3.0); public static float GetFontSize() => Plugin.Config.FontsEnabled ? Plugin.Config.GlobalFontV2.SizePx : SizeInPx(Plugin.Config.FontSizeV2);