Compare commits

...

11 Commits

Author SHA1 Message Date
JonKazama-Hellion de9d1ac60b Merge branch 'feature/v1.4.0-critical-lifecycle-fixes'
Hellion Chat 1.4.0 — Critical Lifecycle Fixes

Seven P0 lifecycle and race bugs eliminated before any performance refactor.
Plus version bump, manifest sync, changelog, forge-post.
2026-05-07 19:06:56 +02:00
JonKazama-Hellion 19f7099af0 docs: add v1.4.0 forge-post 2026-05-07 19:04:24 +02:00
JonKazama-Hellion f8a734d93f chore: bump version to 1.4.0 and document Critical Lifecycle Fixes 2026-05-07 19:04:20 +02:00
JonKazama-Hellion 3f7e86b32e fix(migration): pull HellionThemeWindowOpacity from pre-v13 backup in v13->v14 2026-05-07 08:03:57 +02:00
JonKazama-Hellion e5bf375b42 fix(plugin): flush DeferredSaveFrames in Dispose before service teardown 2026-05-07 07:53:52 +02:00
JonKazama-Hellion 93329087a9 fix(messagemanager): warn loudly when DisposeAsync 10s timeout hits 2026-05-07 07:52:14 +02:00
JonKazama-Hellion 72d568e5b3 fix(emotecache): replace async void Load with async Task tracker 2026-05-07 07:41:50 +02:00
JonKazama-Hellion c9dfd024b2 docs(comments): trim verbose dispose and thread rationale
Match the new HellionChat comment-length convention: 1-3 lines for
standard pitfall notes, 5+ only for non-trivial workarounds. The
previous Dispose comment was 14 lines of textbook prose, which veered
into AI-slop territory and would rot on the next refactor.
2026-05-07 01:10:50 +02:00
JonKazama-Hellion 8c624a0032 fix(threads): mark PendingMessage thread as background, document RetentionSweep rationale 2026-05-07 00:54:43 +02:00
JonKazama-Hellion 079e280226 fix(messagestore): drop GC.Collect from Dispose, rely on Pooling=false 2026-05-07 00:42:26 +02:00
JonKazama-Hellion 3bdf45c29c Datein in falschen ordner verschoben xD 2026-05-06 22:32:01 +02:00
13 changed files with 247 additions and 80 deletions
+32
View File
@@ -0,0 +1,32 @@
---
subtitle: Critical Lifecycle Fixes
versionsnatur: Stability-Hotfix
---
**Hellion Chat 1.4.0 — Critical Lifecycle Fixes**
Erster Sub-Patch der v1.4.x Polish-Sweep-Serie. Sieben
bekannte Lifecycle- und Race-Bugs aus den Audit-Pässen
abgearbeitet, bevor Performance- und Architektur-Refactors
draufkommen.
- **SQLite-Dispose** lehnt sich nicht mehr an GC-Druck zur
Datei-Freigabe an, Pooling=false auf der Connection macht
den manuellen GC.Collect überflüssig
- **Worker-Threads** (PendingMessage, RetentionSweep) sind
jetzt explizit IsBackground=true, das Plugin-Domain kann
sauber unloaden bei XIVLauncher-Reload ohne darauf zu warten
- **EmoteCache-Loader** von async-void auf async-Task mit
shared Task-Tracker, drain-on-Dispose. Kein Schreib-Risiko
mehr auf disposed EmoteImages-Einträge nach Plugin-Reload
- **DisposeAsync-Timeout** (10s) warnt jetzt laut statt silent
zu failen
- **Plugin-Dispose** flushed pending DeferredSave bevor Services
abgebaut werden, Settings-Änderungen aus den letzten Frames
vor Disable überleben jetzt zuverlässig
- **v13→v14 Config-Migration** liest pre-v13-Backup und überträgt
HellionThemeWindowOpacity in das neue WindowOpacity-Feld statt
auf 0.85 zurückzufallen
Keine Schema-Bumps, keine User-sichtbaren Funktions-Änderungen
außer dass Reload und Shutdown spürbar sauberer laufen.
+32 -9
View File
@@ -1,4 +1,5 @@
using System.Numerics; using System.Collections.Concurrent;
using System.Numerics;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using Dalamud.Interface.Textures; using Dalamud.Interface.Textures;
@@ -73,6 +74,19 @@ public static class EmoteCache
private static CancellationTokenSource Cts = new(); private static CancellationTokenSource Cts = new();
internal static CancellationToken Token => Cts.Token; internal static CancellationToken Token => Cts.Token;
// Drain target for in-flight loads on Dispose; without this an orphan
// continuation could still write to a torn-down Texture/Frames field.
private static readonly ConcurrentBag<Task> PendingLoads = new();
internal static void TrackLoad(Task loadTask, string emoteCode)
{
PendingLoads.Add(loadTask.ContinueWith(t =>
{
if (t.IsFaulted)
Plugin.Log.Error(t.Exception!, $"EmoteCache load failed for {emoteCode}");
}, TaskScheduler.Default));
}
public static async Task LoadData() public static async Task LoadData()
{ {
if (State is not LoadingState.Unloaded) if (State is not LoadingState.Unloaded)
@@ -135,10 +149,20 @@ public static class EmoteCache
public static void Dispose() public static void Dispose()
{ {
// Cancel in-flight downloads / texture creates so the async-void
// Load methods bail out before they touch a disposed TextureProvider.
Cts.Cancel(); Cts.Cancel();
// 5s upper bound; anything still running gets abandoned.
try
{
Task.WaitAll(PendingLoads.ToArray(), TimeSpan.FromSeconds(5));
}
catch (AggregateException)
{
// Faults already logged in TrackLoad.
}
while (PendingLoads.TryTake(out _)) { }
foreach (var emote in EmoteImages.Values) foreach (var emote in EmoteImages.Values)
emote.InnerDispose(); emote.InnerDispose();
} }
@@ -233,11 +257,12 @@ public static class EmoteCache
public ImGuiEmote Prepare(Emote emote) public ImGuiEmote Prepare(Emote emote)
{ {
var ct = EmoteCache.Token; var ct = EmoteCache.Token;
Task.Run(() => Load(emote, ct), ct); // Task.Run keeps the sync prefix off the ImGui render thread.
EmoteCache.TrackLoad(Task.Run(() => LoadAsyncTracked(emote, ct), ct), emote.Code);
return this; return this;
} }
private async void Load(Emote emote, CancellationToken ct) private async Task LoadAsyncTracked(Emote emote, CancellationToken ct)
{ {
try try
{ {
@@ -251,8 +276,6 @@ public static class EmoteCache
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {
// Plugin disposed mid-load; the EmoteImages entry is also
// being torn down, no extra cleanup needed.
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -310,11 +333,11 @@ public static class EmoteCache
public ImGuiGif Prepare(Emote emote) public ImGuiGif Prepare(Emote emote)
{ {
var ct = EmoteCache.Token; var ct = EmoteCache.Token;
Task.Run(() => Load(emote, ct), ct); EmoteCache.TrackLoad(Task.Run(() => LoadAsyncTracked(emote, ct), ct), emote.Code);
return this; return this;
} }
private async void Load(Emote emote, CancellationToken ct) private async Task LoadAsyncTracked(Emote emote, CancellationToken ct)
{ {
try try
{ {
+1 -1
View File
@@ -4,7 +4,7 @@
0.1.0 is our bootstrap release; the underlying Chat 2 base is 0.1.0 is our bootstrap release; the underlying Chat 2 base is
called out in the yaml changelog so users can see what it called out in the yaml changelog so users can see what it
derives from. --> derives from. -->
<Version>1.3.0</Version> <Version>1.4.0</Version>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<!-- Honor packages.lock.json on restore so floating version ranges <!-- Honor packages.lock.json on restore so floating version ranges
+39
View File
@@ -45,6 +45,13 @@ description: |-
are shown in the chat header above the message log, with auto-detect are shown in the chat header above the message log, with auto-detect
and silent fallback when Honorific is not installed. and silent fallback when Honorific is not installed.
v1.4.0 — Critical Lifecycle Fixes. Plugin reload and shutdown
are cleaner: SQLite no longer leans on GC pressure to release
its file, worker threads are explicitly background, deferred
config saves no longer get lost mid-disable, and pre-v13 config
backups carry the user's custom theme opacity into the v14 schema
instead of falling back to the default.
Based on Chat 2 by Infi and Anna, licensed under EUPL-1.2. Based on Chat 2 by Infi and Anna, licensed under EUPL-1.2.
Modding & support: join the Hellion Forge Discord at Modding & support: join the Hellion Forge Discord at
@@ -64,6 +71,38 @@ tags:
- Replacement - Replacement
- Privacy - Privacy
changelog: |- changelog: |-
**Hellion Chat 1.4.0 — Critical Lifecycle Fixes**
First sub-patch of the v1.4.x Polish Sweep series. Seven
known lifecycle and race bugs eliminated before any
performance refactor sits on top.
- MessageStore disposal no longer triggers GC.Collect
globally; Pooling=false on the SQLite connection means
there's nothing left to clean up by hand
- PendingMessage and RetentionSweep worker threads are
explicitly marked IsBackground=true so the plugin domain
can unload during XIVLauncher reload without waiting
for them
- EmoteCache image and gif loaders moved from async-void
to async Task with a shared task tracker, draining
on Dispose so an in-flight load can no longer write
to a disposed EmoteImages entry
- DisposeAsync 10s timeout now warns loudly instead of
silently leaving the worker behind
- Plugin.Dispose flushes any pending DeferredSaveFrames
before tearing services down, so settings changes
made in the last few frames before disable are no
longer lost
- The v13→v14 config migration now reads the pre-v13
backup and carries HellionThemeWindowOpacity into the
new WindowOpacity field instead of falling back to
the default 0.85
Modding & support: join Hellion Forge — https://discord.gg/X9V7Kcv5gR
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
**Hellion Chat 1.3.0 - Plugin Integrations: Honorific** **Hellion Chat 1.3.0 - Plugin Integrations: Honorific**
First step on the plugin-integration roadmap. HellionChat now First step on the plugin-integration roadmap. HellionChat now
+19 -11
View File
@@ -66,7 +66,12 @@ internal class MessageManager : IAsyncDisposable
Store = new MessageStore(DatabasePath()); Store = new MessageStore(DatabasePath());
PendingMessageThread = new Thread(() => ProcessPendingMessages(PendingThreadCancellationToken.Token)); // IsBackground so a stuck worker never blocks plugin unload.
// Cooperative cancel via PendingThreadCancellationToken first, background flag is the safety net.
PendingMessageThread = new Thread(() => ProcessPendingMessages(PendingThreadCancellationToken.Token))
{
IsBackground = true,
};
PendingMessageThread.Start(); PendingMessageThread.Start();
ContentIdResolverHook = Plugin.GameInteropProvider.HookFromAddress<RaptureLogModule.Delegates.AddMsgSourceEntry>(RaptureLogModule.MemberFunctionPointers.AddMsgSourceEntry, ContentIdResolver); ContentIdResolverHook = Plugin.GameInteropProvider.HookFromAddress<RaptureLogModule.Delegates.AddMsgSourceEntry>(RaptureLogModule.MemberFunctionPointers.AddMsgSourceEntry, ContentIdResolver);
@@ -85,19 +90,22 @@ internal class MessageManager : IAsyncDisposable
Plugin.ChatGui.ChatMessageUnhandled -= ChatMessage; Plugin.ChatGui.ChatMessageUnhandled -= ChatMessage;
await PendingThreadCancellationToken.CancelAsync(); await PendingThreadCancellationToken.CancelAsync();
var timeout = 10_000; // 10s
while (timeout > 0)
{
if (!PendingMessageThread.IsAlive)
break;
timeout -= 100; // 10s cooperative window; Thread.Abort is gone since .NET 5, so a
// stuck worker has to ride out the next AppDomain unload.
var deadline = TimeSpan.FromSeconds(10);
var stopwatch = Stopwatch.StartNew();
while (stopwatch.Elapsed < deadline && PendingMessageThread.IsAlive)
await Task.Delay(100); await Task.Delay(100);
Plugin.Log.Debug("Sleeping because PendingMessageThread thread still alive");
}
// CancellationTokenSource owns an unmanaged WaitHandle; dispose after the if (PendingMessageThread.IsAlive)
// worker thread has drained, otherwise it leaks across plugin reloads. Plugin.Log.Warning(
"PendingMessageThread did not observe cancellation within 10s. " +
"Worker remains on a background thread; next plugin reload releases it. " +
"If this recurs, file a bug with /xllog after the previous reload.");
// CTS owns an unmanaged WaitHandle; dispose even if the worker is
// alive — it checks IsCancellationRequested via the linked token.
PendingThreadCancellationToken.Dispose(); PendingThreadCancellationToken.Dispose();
Store.Dispose(); Store.Dispose();
+4 -3
View File
@@ -131,11 +131,12 @@ internal class MessageStore : IDisposable
public void Dispose() public void Dispose()
{ {
// Pooling=false (set in Connect) avoids ClearAllPools, which is
// provider-wide and would touch other plugins' SQLite connections.
// GC.Collect was here as a defensive flush; removed because explicit
// Close already releases everything we hold.
Connection.Close(); Connection.Close();
Connection.Dispose(); Connection.Dispose();
// Closing the connection doesn't immediately release the file.
GC.Collect();
GC.WaitForPendingFinalizers();
} }
private SqliteConnection Connect() private SqliteConnection Connect()
+62 -2
View File
@@ -245,11 +245,24 @@ public sealed class Plugin : IDalamudPlugin
// HellionThemeEnabled-Flag wird deprecated und nur noch ein Release // HellionThemeEnabled-Flag wird deprecated und nur noch ein Release
// als Safety-Net im JSON behalten. Window-Opacity wandert von // als Safety-Net im JSON behalten. Window-Opacity wandert von
// HellionThemeWindowOpacity in das neue WindowOpacity-Feld. // HellionThemeWindowOpacity in das neue WindowOpacity-Feld.
//
// v1.4.0 (F5.4): Pre-v13-Backup wird gelesen, HellionThemeWindowOpacity
// ins neue Feld gezogen. Override nur wenn WindowOpacity noch beim
// Default sitzt — sonst hat der User in der Zwischenzeit (z.B. via
// WindowAlpha → WindowOpacity in v15→v16) explizit etwas gesetzt.
if (Config.Version < 14) if (Config.Version < 14)
{ {
Config.Theme = "hellion-arctic"; Config.Theme = "hellion-arctic";
// v1.2.0: alter Opacity-Wert wird nicht mehr migriert (Field entfernt).
// User die direkt v13 → v15 springen bekommen den Default 0.85. var oldThemeOpacity = TryReadPreV13ThemeOpacity();
if (oldThemeOpacity is { } legacy
&& Math.Abs(Config.WindowOpacity - 0.85f) < 0.001f)
{
Config.WindowOpacity = Math.Clamp(legacy, 0.5f, 1.0f);
Log.Information(
$"Migrated pre-v13 HellionThemeWindowOpacity {legacy} to WindowOpacity {Config.WindowOpacity}");
}
Config.ReduceMotion = false; Config.ReduceMotion = false;
Config.UseCompactDensity = false; Config.UseCompactDensity = false;
Config.Version = 14; Config.Version = 14;
@@ -536,6 +549,14 @@ public sealed class Plugin : IDalamudPlugin
Framework.Update -= FrameworkUpdate; Framework.Update -= FrameworkUpdate;
GameFunctions.GameFunctions.SetChatInteractable(true); GameFunctions.GameFunctions.SetChatInteractable(true);
// FrameworkUpdate would have fired the pending save in N frames,
// but we just unsubscribed it. -1 is the idle sentinel.
if (DeferredSaveFrames >= 0)
{
SaveConfig();
DeferredSaveFrames = -1;
}
HonorificService?.Dispose(); HonorificService?.Dispose();
WindowSystem?.RemoveAllWindows(); WindowSystem?.RemoveAllWindows();
@@ -560,6 +581,40 @@ public sealed class Plugin : IDalamudPlugin
EmoteCache.Dispose(); EmoteCache.Dispose();
} }
// Reads HellionThemeWindowOpacity from the pre-v13 backup the v12→v13
// block writes alongside the live config. Null when absent, unreadable,
// or schema-incompatible — all valid steady states (fresh install,
// backup pruned, pre-v12 config). Errors log at Warning so a corrupted
// backup stays visible in /xllog without breaking the migration.
private static float? TryReadPreV13ThemeOpacity()
{
var pluginConfigsDir = Interface.ConfigDirectory.Parent?.FullName;
if (pluginConfigsDir is null)
return null;
var backupPath = Path.Combine(pluginConfigsDir, $"{Interface.InternalName}.json.pre-v13-backup");
if (!File.Exists(backupPath))
return null;
try
{
using var stream = File.OpenRead(backupPath);
using var doc = System.Text.Json.JsonDocument.Parse(stream);
if (doc.RootElement.TryGetProperty("HellionThemeWindowOpacity", out var prop)
&& prop.ValueKind == System.Text.Json.JsonValueKind.Number
&& prop.TryGetSingle(out var value))
{
return value;
}
return null;
}
catch (Exception ex)
{
Log.Warning(ex, "HellionChat: pre-v13 backup lookup failed, defaulting WindowOpacity");
return null;
}
}
private static void MigrateFromChatTwoLayout() private static void MigrateFromChatTwoLayout()
{ {
var pluginConfigsDir = Interface.ConfigDirectory.Parent?.FullName; var pluginConfigsDir = Interface.ConfigDirectory.Parent?.FullName;
@@ -691,6 +746,11 @@ public sealed class Plugin : IDalamudPlugin
policy[(int)(ushort)type] = days; policy[(int)(ushort)type] = days;
var defaultDays = Config.RetentionDefaultDays; var defaultDays = Config.RetentionDefaultDays;
// IsBackground = true for the same reason as PendingMessageThread:
// a stuck sweep must never block plugin unload. RunRetentionSweepIfDue
// guards the run-frequency, and the sweep itself uses the framework's
// cooperative cancellation pattern. The background flag is the safety
// net if the sweep ever takes longer than expected.
new Thread(() => new Thread(() =>
{ {
// Bail out cheaply if a manual sweep is already in flight; the // Bail out cheaply if a manual sweep is already in flight; the
+2 -2
View File
@@ -12,7 +12,7 @@
<img src="docs/images/hellion-forge.png" alt="Hellion Forge" width="180" /> <img src="docs/images/hellion-forge.png" alt="Hellion Forge" width="180" />
</p> </p>
**Version 1.3.0** — Privacy-First-Chat-Plugin für FINAL FANTASY XIV / Dalamud, basierend auf [Chat 2](https://github.com/Infiziert90/ChatTwo) (EUPL-1.2). **Version 1.4.0** — Privacy-First-Chat-Plugin für FINAL FANTASY XIV / Dalamud, basierend auf [Chat 2](https://github.com/Infiziert90/ChatTwo) (EUPL-1.2).
Hellion Chat ist ein Privacy-First-Plugin auf dem Chat-2-Fundament. Der größte Teil der Engine kommt aus Chat 2 (Message-Store, Channel-Logik, Hook-System), die meisten Tastenkürzel funktionieren weiterhin wie gewohnt. Was sich ändert: schärfere Privacy-Defaults von Haus aus, eigene Slash-Commands unter `/hellionchat`, kein Webinterface mehr, und mit v1.1.0 eine Theme-Engine als Schritt in Richtung eigenes UI-Look-and-Feel. Hellion Chat ist ein Privacy-First-Plugin auf dem Chat-2-Fundament. Der größte Teil der Engine kommt aus Chat 2 (Message-Store, Channel-Logik, Hook-System), die meisten Tastenkürzel funktionieren weiterhin wie gewohnt. Was sich ändert: schärfere Privacy-Defaults von Haus aus, eigene Slash-Commands unter `/hellionchat`, kein Webinterface mehr, und mit v1.1.0 eine Theme-Engine als Schritt in Richtung eigenes UI-Look-and-Feel.
@@ -225,7 +225,7 @@ Eine optionale Submission ans Dalamud-Main-Plugin-Repo (zusätzlich zum eigenen
## Projektstatus ## Projektstatus
**Version 1.3.0** — Erster Plugin-Integrations-Cycle live (Honorific Custom-Titles im Chat-Header), Theme-Katalog auf neun Built-ins, Settings thematisch re-sortiert, Standalone-Cut abgeschlossen (Stand: 2026-05-06). **Version 1.4.0** — Critical Lifecycle Fixes: sieben Race- und Lifecycle-Bugs aus Audit-Pass-3 und Pass-4 abgearbeitet (GC.Collect aus SQLite-Dispose raus, Worker-Threads explizit IsBackground, EmoteCache async-void → async Task, DeferredSave-Race geschlossen, Pre-v13-Backup-Lookup für WindowOpacity-Migration). Erster Sub-Patch der v1.4.x Polish-Sweep-Serie (Stand: 2026-05-07).
Hellion Chat ist ein eigenständiges Plugin, kein Fork mehr im Repository-Sinne. Vollständig abgeschlossen: Hellion Chat ist ein eigenständiges Plugin, kein Fork mehr im Repository-Sinne. Vollständig abgeschlossen:
+34
View File
@@ -12,6 +12,40 @@ und verlinkt für Details auf die Release-Pages.
--- ---
## Hellion Chat 1.4.0 — Critical Lifecycle Fixes
First sub-patch of the v1.4.x Polish Sweep series. Seven
known lifecycle and race bugs eliminated before any
performance refactor sits on top.
- MessageStore disposal no longer triggers GC.Collect
globally; Pooling=false on the SQLite connection means
there's nothing left to clean up by hand
- PendingMessage and RetentionSweep worker threads are
explicitly marked IsBackground=true so the plugin domain
can unload during XIVLauncher reload without waiting
for them
- EmoteCache image and gif loaders moved from async-void
to async Task with a shared task tracker, draining
on Dispose so an in-flight load can no longer write
to a disposed EmoteImages entry
- DisposeAsync 10s timeout now warns loudly instead of
silently leaving the worker behind
- Plugin.Dispose flushes any pending DeferredSaveFrames
before tearing services down, so settings changes
made in the last few frames before disable are no
longer lost
- The v13→v14 config migration now reads the pre-v13
backup and carries HellionThemeWindowOpacity into the
new WindowOpacity field instead of falling back to
the default 0.85
Modding & support: join Hellion Forge — https://discord.gg/X9V7Kcv5gR
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
---
## Hellion Chat 1.3.0 - Plugin Integrations: Honorific ## Hellion Chat 1.3.0 - Plugin Integrations: Honorific
First step on the plugin-integration roadmap. HellionChat now First step on the plugin-integration roadmap. HellionChat now
+15 -6
View File
@@ -12,15 +12,24 @@ Privacy-First-Schnittmenge des Plugins erweisen.
--- ---
## Nächster Cycle (v1.4.0) ## Nächster Cycle (v1.4.1)
**Polish & Motion** - Theme-Crossfade, Header-Quick-Picker, **Theme Engine Performance** — HellionStyle Heap-Pressure
Lerp-Animationen, ggf. Theme-Family-Picker (Carls Grün-Familie eliminieren (StackHandle-Cache, ABGR-Cache auf Theme-Object,
mit Forest/Moss/Mint-Helligkeitsstufen). spart 47 Heap-Allocs pro Frame), ThemeRegistry File-Lock-
Härtung beim Custom-Theme-Load.
Spec wird im Brainstorming-Cycle vor Beginn der Phase ausgearbeitet. ## v1.4.0 — Critical Lifecycle Fixes (released <Datum>)
## v1.3.0 - Plugin Integrations: Honorific (geplant <Datum>) Erster Sub-Patch der v1.4.x Polish-Sweep-Serie. Sieben P0-
Findings aus Audit-Pass-3 und Pass-4 abgearbeitet:
async-void-Loads, fehlende IsBackground-Flags, GC.Collect
in Dispose, DeferredSave-Race und Pre-v13-Backup-Lookup für
WindowOpacity. Keine Schema-Bumps, keine Funktions-
Änderungen für den User außer dass Reload und Shutdown
spürbar sauberer laufen.
## v1.3.0 - Plugin Integrations: Honorific (released 2026-05-07)
Erster Cycle der Plugin-Integrations-Roadmap. Honorific-Custom- Erster Cycle der Plugin-Integrations-Roadmap. Honorific-Custom-
Titles werden im Chat-Header angezeigt, mit Auto-Detect und Titles werden im Chat-Header angezeigt, mit Auto-Detect und
-20
View File
@@ -1,20 +0,0 @@
**Hellion Chat 1.3.0 - Plugin Integrations: Honorific**
EN - First plugin-integration cycle:
- Honorific titles now show in the chat header above the message log
- Live updates, auto-hide when Honorific is not installed
- New "Integrations" settings tab with status indicator and toggle
- Maintainer attribution buttons for Honorific repo and Caraxi profile
- Coming soon: context menu actions, smart notifications, RP status block, ExtraChat channels, quick DMs
DE - Erste Plugin-Integration:
- Honorific-Titel jetzt im Chat-Header über dem Message-Log
- Live-Update, Auto-Hide wenn nicht installiert
- Neuer "Integrations"-Settings-Tab mit Status-Indikator und Toggle
- Maintainer-Attribution-Buttons für Honorific-Repo und Caraxi-Profil
- Bald: Kontextmenü, Notifications, RP-Block, ExtraChat, schnelle DMs
Got integration ideas? Hop on the Hellion Forge.
Idee für eine Integration? Schreib mir auf der Forge.
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
@@ -1,19 +0,0 @@
## Hellion Chat 1.3.0 - Plugin Integrations: Honorific
First step on the plugin-integration roadmap. HellionChat now
listens to Honorific and shows your custom title in the chat
header. The slot auto-hides when Honorific is not installed,
when no custom title is active, or when you are using the
original FFXIV title.
- New "Integrations" settings tab
- Honorific integration with auto-detection and live updates
- "Coming soon" preview of the next five planned integrations:
context menu actions, smart notifications, RP status block,
ExtraChat channels, and quick DM compose
- Maintainer attribution buttons for Honorific repo and Caraxi
- New service-class pattern under HellionChat/Integrations/
Modding and support: join Hellion Forge - https://discord.gg/X9V7Kcv5gR
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
+7 -7
View File
@@ -3,8 +3,8 @@
"Author": "JonKazama-Hellion", "Author": "JonKazama-Hellion",
"Name": "Hellion Chat", "Name": "Hellion Chat",
"InternalName": "HellionChat", "InternalName": "HellionChat",
"AssemblyVersion": "1.3.0.0", "AssemblyVersion": "1.4.0.0",
"Description": "Hellion Chat is a privacy-focused chat replacement for FINAL FANTASY XIV based on the Chat 2 codebase (EUPL-1.2). One feature is intentionally removed (the optional webinterface) and a stack of privacy controls is added on top. Tabs, channel filters, RGB colours, emotes, screenshot mode, IPC integration and the chat replacement window itself work the same. The webinterface is intentionally not part of Hellion Chat because it serves a different use case from the smaller default footprint this plugin is built around.\n\nOn top of that, Hellion Chat adds privacy and data-handling controls designed to align with the modern data protection rules that apply across the EU, the United States and Japan. By default only your own conversations are stored; messages from strangers, NPCs and system spam stay out of the database. Retention windows are configurable per channel, history can be wiped retroactively, and stored data can be exported on demand.\n\nKey privacy and data-handling features:\n\n- Channel whitelist with a Privacy-First default\n- Per-channel retention with a daily background sweep\n- Retroactive cleanup with a Ctrl+Shift confirm\n- Export to Markdown, JSON or CSV\n- First-run wizard with three preset profiles (Privacy-First, Casual, Full History)\n- Bilingual UI (English and German) with live language switching\n- Independent plugin state — own config file and database directory, so Hellion Chat does not share state with upstream Chat 2\n\nv1.1.0 — Theme engine with five built-in themes (Hellion Arctic, Chat 2 Klassik, Event Horizon, Moonlit Bloom, Mint Grove) plus JSON-based custom-theme authoring. Settings rebuilt around a card grid with section detail views. See docs/THEME-AUTHORING.md.\n\nv1.2.3 — Theme catalogue grown to nine built-in themes: Hellion Arctic, Hellion Spectrum (CVD-safe Deuteran/Protan), Chat 2 Klassik, Event Horizon, Moonlit Bloom, Mint Grove, Night Blue, Indigo Violet, Forge Merchantman.\n\nv1.3.0 First plugin integration cycle. Honorific custom titles are shown in the chat header above the message log, with auto-detect and silent fallback when Honorific is not installed.\n\nBased on Chat 2 by Infi and Anna, licensed under EUPL-1.2.\n\nModding & support: join the Hellion Forge Discord at https://discord.gg/X9V7Kcv5gR — community for Hellion Chat and other Hellion Online Media plugins/tools.", "Description": "Hellion Chat is a privacy-focused chat replacement for FINAL FANTASY XIV based on the Chat 2 codebase (EUPL-1.2). One feature is intentionally removed (the optional webinterface) and a stack of privacy controls is added on top. Tabs, channel filters, RGB colours, emotes, screenshot mode, IPC integration and the chat replacement window itself work the same. The webinterface is intentionally not part of Hellion Chat because it serves a different use case from the smaller default footprint this plugin is built around.\n\nOn top of that, Hellion Chat adds privacy and data-handling controls designed to align with the modern data protection rules that apply across the EU, the United States and Japan. By default only your own conversations are stored; messages from strangers, NPCs and system spam stay out of the database. Retention windows are configurable per channel, history can be wiped retroactively, and stored data can be exported on demand.\n\nKey privacy and data-handling features:\n\n- Channel whitelist with a Privacy-First default\n- Per-channel retention with a daily background sweep\n- Retroactive cleanup with a Ctrl+Shift confirm\n- Export to Markdown, JSON or CSV\n- First-run wizard with three preset profiles (Privacy-First, Casual, Full History)\n- Bilingual UI (English and German) with live language switching\n- Independent plugin state — own config file and database directory, so Hellion Chat does not share state with upstream Chat 2\n\nv1.1.0 — Theme engine with five built-in themes (Hellion Arctic, Chat 2 Klassik, Event Horizon, Moonlit Bloom, Mint Grove) plus JSON-based custom-theme authoring. Settings rebuilt around a card grid with section detail views. See docs/THEME-AUTHORING.md.\n\nv1.2.3 — Theme catalogue grown to nine built-in themes: Hellion Arctic, Hellion Spectrum (CVD-safe Deuteran/Protan), Chat 2 Klassik, Event Horizon, Moonlit Bloom, Mint Grove, Night Blue, Indigo Violet, Forge Merchantman.\n\nv1.3.0 First plugin integration cycle. Honorific custom titles are shown in the chat header above the message log, with auto-detect and silent fallback when Honorific is not installed.\n\nv1.4.0 — Critical Lifecycle Fixes. Plugin reload and shutdown are cleaner: SQLite no longer leans on GC pressure to release its file, worker threads are explicitly background, deferred config saves no longer get lost mid-disable, and pre-v13 config backups carry the user's custom theme opacity into the v14 schema instead of falling back to the default.\n\nBased on Chat 2 by Infi and Anna, licensed under EUPL-1.2.\n\nModding & support: join the Hellion Forge Discord at https://discord.gg/X9V7Kcv5gR — community for Hellion Chat and other Hellion Online Media plugins/tools.",
"ApplicableVersion": "any", "ApplicableVersion": "any",
"RepoUrl": "https://github.com/JonKazama-Hellion/HellionChat", "RepoUrl": "https://github.com/JonKazama-Hellion/HellionChat",
"Tags": [ "Tags": [
@@ -20,12 +20,12 @@
"CanUnloadAsync": false, "CanUnloadAsync": false,
"LoadPriority": 0, "LoadPriority": 0,
"Punchline": "Chat replacement with privacy controls aligned to EU, US and JP rules — based on Chat 2 (EUPL-1.2)", "Punchline": "Chat replacement with privacy controls aligned to EU, US and JP rules — based on Chat 2 (EUPL-1.2)",
"Changelog": "**Hellion Chat 1.3.0 - Plugin Integrations: Honorific**\n\nFirst step on the plugin-integration roadmap. HellionChat now listens to Honorific and shows your custom title in the chat header. The slot auto-hides when Honorific is not installed, when no custom title is active, or when you are using the original FFXIV title.\n\n- New \"Integrations\" settings tab\n- Honorific integration with auto-detection and live updates\n- \"Coming soon\" preview of the next five planned integrations: context menu actions, smart notifications, RP status block, ExtraChat channels, and quick DM compose\n- Maintainer attribution buttons for Honorific repo and Caraxi\n- New service-class pattern under HellionChat/Integrations/\n\nModding and support: join Hellion Forge - https://discord.gg/X9V7Kcv5gR\n\nBased on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).\n\n**Hellion Chat 1.2.3 — Theme Expansion**\n\nFour new built-in themes round out the picker. No engine changes, no settings touched — just more colour options.\n\n- **Night Blue** — Royal Blue on deep marine. Cool tech-dashboard mood, distinct from the brand themes.\n- **Indigo Violet** — Royal Violet on deep indigo with a turquoise-mint counter for an aurora glitter feel. Sister to Event Horizon but darker and denser; the turquoise accent keeps the two distinguishable.\n- **Forge Merchantman** — Patina bronze on workshop slate, warm amber counter. Hellion Forge given a theme of its own — sister to Hellion Arctic but greener and warmer instead of cold cyan.\n- **Hellion Spectrum** — Deuteran/Protan-safe channel colours using Wong/Okabe-Ito palette tones. Channel identity (Tell pink, Yell yellow, Shout orange, Party blue, FC green) is preserved; tones are chosen so each channel stays distinguishable under red-green colour vision deficiency. Covers the ~99% of CVD cases that are red-green.\n\nNo schema bump, no migration. Default theme is unchanged (Hellion Arctic). Existing custom themes keep working.\n\nBased on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).\n\n---\n\nEarlier history: https://github.com/JonKazama-Hellion/HellionChat/releases", "Changelog": "**Hellion Chat 1.4.0 — Critical Lifecycle Fixes**\n\nFirst sub-patch of the v1.4.x Polish Sweep series. Seven known lifecycle and race bugs eliminated before any performance refactor sits on top.\n\n- MessageStore disposal no longer triggers GC.Collect globally; Pooling=false on the SQLite connection means there's nothing left to clean up by hand\n- PendingMessage and RetentionSweep worker threads are explicitly marked IsBackground=true so the plugin domain can unload during XIVLauncher reload without waiting for them\n- EmoteCache image and gif loaders moved from async-void to async Task with a shared task tracker, draining on Dispose so an in-flight load can no longer write to a disposed EmoteImages entry\n- DisposeAsync 10s timeout now warns loudly instead of silently leaving the worker behind\n- Plugin.Dispose flushes any pending DeferredSaveFrames before tearing services down, so settings changes made in the last few frames before disable are no longer lost\n- The v13→v14 config migration now reads the pre-v13 backup and carries HellionThemeWindowOpacity into the new WindowOpacity field instead of falling back to the default 0.85\n\nModding & support: join Hellion Forge — https://discord.gg/X9V7Kcv5gR\n\nBased on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).\n\n**Hellion Chat 1.3.0 - Plugin Integrations: Honorific**\n\nFirst step on the plugin-integration roadmap. HellionChat now listens to Honorific and shows your custom title in the chat header. The slot auto-hides when Honorific is not installed, when no custom title is active, or when you are using the original FFXIV title.\n\n- New \"Integrations\" settings tab\n- Honorific integration with auto-detection and live updates\n- \"Coming soon\" preview of the next five planned integrations: context menu actions, smart notifications, RP status block, ExtraChat channels, and quick DM compose\n- Maintainer attribution buttons for Honorific repo and Caraxi\n- New service-class pattern under HellionChat/Integrations/\n\nModding and support: join Hellion Forge - https://discord.gg/X9V7Kcv5gR\n\nBased on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).\n\n**Hellion Chat 1.2.3 — Theme Expansion**\n\nFour new built-in themes round out the picker. No engine changes, no settings touched — just more colour options.\n\n- **Night Blue** — Royal Blue on deep marine. Cool tech-dashboard mood, distinct from the brand themes.\n- **Indigo Violet** — Royal Violet on deep indigo with a turquoise-mint counter for an aurora glitter feel. Sister to Event Horizon but darker and denser; the turquoise accent keeps the two distinguishable.\n- **Forge Merchantman** — Patina bronze on workshop slate, warm amber counter. Hellion Forge given a theme of its own — sister to Hellion Arctic but greener and warmer instead of cold cyan.\n- **Hellion Spectrum** — Deuteran/Protan-safe channel colours using Wong/Okabe-Ito palette tones. Channel identity (Tell pink, Yell yellow, Shout orange, Party blue, FC green) is preserved; tones are chosen so each channel stays distinguishable under red-green colour vision deficiency. Covers the ~99% of CVD cases that are red-green.\n\nNo schema bump, no migration. Default theme is unchanged (Hellion Arctic). Existing custom themes keep working.\n\nBased on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).\n\n---\n\nEarlier history: https://github.com/JonKazama-Hellion/HellionChat/releases",
"AcceptsFeedback": true, "AcceptsFeedback": true,
"DownloadLinkInstall": "https://github.com/JonKazama-Hellion/HellionChat/releases/download/v1.3.0/latest.zip", "DownloadLinkInstall": "https://github.com/JonKazama-Hellion/HellionChat/releases/download/v1.4.0/latest.zip",
"DownloadLinkUpdate": "https://github.com/JonKazama-Hellion/HellionChat/releases/download/v1.3.0/latest.zip", "DownloadLinkUpdate": "https://github.com/JonKazama-Hellion/HellionChat/releases/download/v1.4.0/latest.zip",
"DownloadLinkTesting": "https://github.com/JonKazama-Hellion/HellionChat/releases/download/v1.3.0/latest.zip", "DownloadLinkTesting": "https://github.com/JonKazama-Hellion/HellionChat/releases/download/v1.4.0/latest.zip",
"TestingAssemblyVersion": "1.3.0.0", "TestingAssemblyVersion": "1.4.0.0",
"IconUrl": "https://raw.githubusercontent.com/JonKazama-Hellion/HellionChat/main/HellionChat/images/icon.png", "IconUrl": "https://raw.githubusercontent.com/JonKazama-Hellion/HellionChat/main/HellionChat/images/icon.png",
"ImageUrls": [ "ImageUrls": [
"https://raw.githubusercontent.com/JonKazama-Hellion/HellionChat/main/HellionChat/images/chatWindow.png", "https://raw.githubusercontent.com/JonKazama-Hellion/HellionChat/main/HellionChat/images/chatWindow.png",