81 namespace declarations and 100 using directives converted via sed,
plus two FQN-aliases (ChatTwoPartyFinderPayload in PayloadHandler.cs and
ModifierFlag in KeybindManager.cs) updated. Critical: Language.Designer.cs
and HellionStrings.Designer.cs ResourceManager string arguments updated
synchronously — these are runtime reflection lookups not caught by the
C# compiler.
Two intentional ChatTwo references remain: the legacy migration path
'ChatTwo.json' in Plugin.cs (still points to upstream Chat 2's config
file by design) and the InternalsVisibleTo declaration in
AssemblyInfo.cs (handled in the upcoming repo-folder rename task).
The local alias names 'ChatTwoPartyFinderPayload' and 'ChatTwoConflictDetector'
are preserved as local symbols; only their target namespaces and references
changed.
async void Task.Run() is a no-op for awaiting purposes since the void
returns immediately. Switch LoadData to async Task and have the two
callers fire-and-forget the task directly. Exceptions still go through
the existing try/catch inside LoadData.
Mark Emote.Id, Top100.Id, Top100.Code and Top100.ImageType as required
so the JSON deserializer enforces the contract instead of relying on
default-null semantics. Removes the four CS8618 warnings the build has
been carrying since v0.4.0.
- Plugin.cs: mark RetentionSweepRunning volatile so the ImGui thread
reads the latest value without a stale register-cached copy
- EmoteCache.cs: reset State to Unloaded on exception so a later
trigger can retry instead of being blocked by the early-out
- Settings.cs: switch the SaveAndClose / Discard buttons to Allman
bracing for consistency with the rest of the file, and include the
ItemSpacing in the Ko-fi-button right-edge calculation
- Privacy.cs: add a saved-policy hint above the manual retention
Ctrl+Shift button so the existing Cleanup wording pattern is
matched here too
- HellionStrings: drop seven unreferenced keys (Theme_Heading,
Migration_Notification_*, Migration_Webinterface_Removed_*,
AutoTellTabs_Migration_*) and their EN/DE values, add the new
Retention_Help_SavedNote string
Audit finding H-1. Defense-in-depth fix for EmoteCache.LoadAsync,
which interpolated the BetterTTV-supplied Id and ImageType straight
into a Path.Join. HTTPS protects the wire today, but a compromised
upstream that hands back Id values like "../foo" would land outside
EmoteCacheV1, anywhere under pluginConfigs that the plugin can write.
Resolve the candidate path with Path.GetFullPath, then assert it
starts with the cache directory plus a directory separator (so
"EmoteCacheV1Sibling" cannot match "EmoteCacheV1"). Throw
InvalidOperationException on mismatch — the surrounding load
already swallows exceptions and logs them, so a tampered entry
becomes a visible error in the log instead of a silent miss.
Two long-standing upstream bugs surfaced in our distribution as
red error rows on every plugin load. Neither is caused by the
fork's own code, but both happen under our plugin name in the
log so they had to go before the plugin gets handed to anyone.
EmoteCache.LoadData fed BetterTTV's API responses straight into
Dictionary.TryAdd. The Top100 endpoint occasionally returns rows
with a null Code field, which tripped ArgumentNullException and
killed the entire emote load. Filter null/empty codes out
explicitly before insertion so a single bad row no longer breaks
the cache for everyone else.
FontManager.BuildFonts called fontId.AddToBuildToolkit without
guarding for the case where the configured SystemFontId points at
a font that isn't installed (e.g. "Crimson Text" on a Linux box,
or a font the user uninstalled after picking it). The atlas build
then crashed and dumped a Dalamud DelegateFontHandle error every
single load. Wrap the call in AddFontWithFallback: if the font
isn't found, log a warning, fall back to the bundled
NotoSansCjkRegular asset and continue. Applied to both the regular
and italic font handles.