One request, one toggle. Manifests, changelog, roadmap and the Forge post for v2.0.6; the v2.0.2 block leaves the yaml to keep it at four.
1480 lines
84 KiB
Markdown
1480 lines
84 KiB
Markdown
# Changelog — Hellion Chat
|
||
|
||
All user-facing changes to Hellion Chat. Format follows
|
||
[Keep a Changelog](https://keepachangelog.com/en/1.0.0/), version numbers follow
|
||
[Semantic Versioning](https://semver.org/).
|
||
|
||
Detailed release notes per version are available directly on the
|
||
[Gitea Release page](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases) and
|
||
in the plugin changelog block (`HellionChat/HellionChat.yaml` → `changelog:`). This file summarises
|
||
releases as an overview and links to the release pages for details.
|
||
|
||
---
|
||
|
||
## [2.0.6] — 2026-09-20
|
||
|
||
One question from the Discord, small enough to ship on its own: are the pills
|
||
along the bottom edge fixed in the code? They were.
|
||
|
||
### Added
|
||
|
||
- "Show status bar" under Window → Window style. Off, the bottom row of pills
|
||
(channel, privacy state, counts, tells, clock, version) is gone and the chat
|
||
body takes the space. On by default, so nothing changes until you flip it.
|
||
With the bar hidden, screenshot mode and the privacy filter have no visible
|
||
indicator; that is the trade the toggle makes. Suggested by Ashy.
|
||
- A "Suggested by …" credit line under settings rows that came from a tester
|
||
request, translated into all 25 languages. First used on the toggle above.
|
||
|
||
---
|
||
|
||
## [2.0.5] — 2026-08-23
|
||
|
||
Two tester reports about the same corner of the plugin: what an incoming tell does
|
||
to what you were doing, and what you can do about a tab once it exists.
|
||
|
||
### Fixed
|
||
|
||
- A tell arriving while you were typing took the keyboard focus, which in this game
|
||
means the next keystrokes reach the character rather than the chat. It could also
|
||
send the half-typed line to the wrong person: the text belongs to the window, the
|
||
recipient is read off whichever tab is active at Enter. Nothing is revealed now
|
||
while an input is in use, in any mode.
|
||
- Tell tabs could not be closed at all. The context menu lost its close entry in the
|
||
2.0.0 window rebuild, and the settings editor excludes tell tabs by design.
|
||
- Closing a tab re-anchored on the first tab in the list even when that tab was open
|
||
in a pop-out, stripping its tell binding. With every tab popped out, the seed and
|
||
the re-anchor contradicted each other on every frame.
|
||
- The pinned-tab limit message pointed at a feature removed in May. Spanish carried a
|
||
non-existent word, Greek an untranslated one, and European Portuguese used a verb
|
||
that contradicted its own button.
|
||
- Segmented settings rows measured a flat 200px and cut off longer labels.
|
||
|
||
### Changed
|
||
|
||
- Where a tell opens is one setting now. "Open new /tell tabs as a pop-out" and the
|
||
tell-open mode both decided it, and the former won every time because it fired at
|
||
tab creation. Config schema 28 carries the existing choice forward.
|
||
- The tell-open mode dropped its "Off" option, which never prevented tell tabs — that
|
||
is the auto-tell switch — and only suppressed the jump to them, which the switch
|
||
below it already does.
|
||
- "Pop Out" in the tab context menu and the tell-open mode names were hardcoded
|
||
English on every client. They are translated into all 25 languages.
|
||
- `Metrics.Scale` no longer calls the obsolete `GlobalScaleSafe`. The project builds
|
||
without compiler warnings.
|
||
|
||
---
|
||
|
||
## [2.0.4] — 2026-08-20
|
||
|
||
Housekeeping. Nothing changes in how the plugin behaves.
|
||
|
||
### Changed
|
||
|
||
- The installer description is shorter and leads with what the plugin does
|
||
rather than what category it belongs to: 367 characters instead of 908. Two
|
||
things in it were also wrong rather than merely long — it claimed 24
|
||
interface languages when there are 25, and `repo.json` and the plugin yaml
|
||
carried different one-line summaries, so the store listing and the plugin
|
||
details showed different sentences.
|
||
|
||
### Removed
|
||
|
||
- 30 translation keys belonging to the webinterface, across all 25 languages,
|
||
plus the generated property for each. The feature itself, its HTTP routes and
|
||
its frontend went out in May; only the strings were left behind. Every key was
|
||
matched on word boundaries against the whole repository before removal, and
|
||
the build proves the rest: a key still in use would have failed to compile.
|
||
|
||
## [2.0.3] — 2026-08-20
|
||
|
||
### Fixed
|
||
|
||
- The context menu never opened in a pop-out window. Right-clicking a name or an
|
||
item there did nothing at all. One payload handler is shared by the main
|
||
window, every pop-out and the input preview, and it carries a single popup
|
||
state. The main window draws first, found no open popup in its own scope, read
|
||
that as closed and cleared the state before the pop-out had drawn. A popup now
|
||
belongs to the surface that opened it and the others leave it alone.
|
||
- Screenshot mode could not be turned off. The setting is persisted, but neither
|
||
of its two toggles saved the config, so turning it on only stuck when an
|
||
unrelated save happened to follow — and once stored, turning it off never
|
||
reached the file, so it returned at every plugin load. Both toggles save now;
|
||
an install currently stuck on it needs one click.
|
||
- Text the game colours itself could render invisible. Some of those colours
|
||
arrive without an alpha byte, and the byte order swap left them fully
|
||
transparent. A colour that carries no value at all still resolves to the
|
||
colour already in effect rather than to opaque black.
|
||
|
||
## [2.0.2] — 2026-08-19
|
||
|
||
### Removed
|
||
|
||
- BetterTTV emote support, in full. The shared-emote endpoint went behind
|
||
authentication and it supplied nearly all of them; what was left is a 65-entry
|
||
global set, eleven of those on the known-broken list, so 54 largely static
|
||
images. One was animated — 492 frames at 140x140, which is 37 MB of texture
|
||
memory for a single emote. Gone with it: the download path, the on-disk cache,
|
||
the GIF renderer, the settings section, the block list, and 13 translation
|
||
keys across 50 resource files. The plugin makes no outbound network calls at
|
||
all now.
|
||
- `EmotePayload` and its MessagePack type byte deliberately stay. Messages
|
||
stored before this release carry them, and removing the type would make those
|
||
rows fail to deserialise. Nothing writes one any more; a stored emote renders
|
||
as the code that was typed. `0x53` and `PayloadMessagePackType.Emote` must
|
||
never be reassigned.
|
||
|
||
### Fixed
|
||
|
||
- Five descriptions in the Window settings tab printed `{0}` where the plugin
|
||
name belonged. They were handed to the widget directly instead of through
|
||
`string.Format`, which the neighbouring rows do correctly. Every language was
|
||
affected including English, where it read less obviously — German puts the
|
||
placeholder at the start of the sentence, which is why it surfaced there.
|
||
|
||
### Added
|
||
|
||
- A test that walks every resource string containing a placeholder, finds each
|
||
use of it in the sources, and fails if one reaches a widget unformatted. It
|
||
was verified by falsification: reintroducing the defect turns it red.
|
||
- New preview images for the plugin installer. The previous set was from
|
||
2026-05-08 and showed the interface as it looked before the window rebuilds.
|
||
Taken with screenshot mode on, so no character names are in them.
|
||
|
||
---
|
||
|
||
## [2.0.1] — 2026-08-19
|
||
|
||
A same-day hotfix on 2.0.0 with nothing user-facing in it.
|
||
|
||
### Changed
|
||
|
||
- MessagePack from 3.1.4 to 3.1.7. The range in the csproj already allowed it;
|
||
NuGet resolves the lower bound of a range and so does trivy, so the floor is
|
||
the version that actually ships. The advisories cover recursion depth in
|
||
`MessagePackReader.Skip` and a fault in LZ4 decompression — both need crafted
|
||
input, and this plugin serialises its own payloads into a local database and
|
||
reads its own bytes back. Practical exposure requires write access to that
|
||
file. Lifted because it is free and a scan left red for a known-harmless
|
||
reason is how a real finding gets missed later.
|
||
|
||
### Fixed
|
||
|
||
- The release workflow attaches its archive again. `gitea.com/actions/release-action`
|
||
declares `using: go` and has to be compiled by the runner, which act cannot do
|
||
here — the 2.0.0 build went green and then died on the publish step with
|
||
exit 127, leaving an announced release with no download. Publishing runs
|
||
through the Gitea API with curl now, and is idempotent so a recovery run
|
||
replaces the asset instead of tripping over it.
|
||
|
||
---
|
||
|
||
## [2.0.0] — 2026-08-19
|
||
|
||
Rebuilt, repaired, reset. Everything developed as v1.6.0 through v1.15.0 ships
|
||
here: those versions were never published on their own, because the whole window
|
||
layer was being rewritten from ImGui defaults to custom drawing and shipping it
|
||
half-done would have been worse than shipping nothing.
|
||
|
||
**This release resets your configuration.** Nine cycles of window rebuilds left
|
||
saved values pointing at surfaces that no longer exist, and starting over is the
|
||
only way to be sure every install is on the same defaults. The message database is
|
||
untouched — it lives in its own file. The previous config is kept alongside it as
|
||
`HellionChat.json.pre-2.0.0.bak`.
|
||
|
||
### Added
|
||
|
||
- An Emote tab in the default layout, requested by a tester: custom emotes,
|
||
standard emotes and echo, which is where emote-adjacent output lands.
|
||
- `/hellion wizard` reopens the first-run wizard. It had no way back into it at
|
||
all — the reopen button lost its call site in the four-step rewrite and nothing
|
||
replaced it, so the only route was closing the game and editing the config.
|
||
- The plugin notice on the welcome page: plugins are a grey area in this game and
|
||
do not belong in public channels.
|
||
|
||
### Changed
|
||
|
||
- The first-run wizard is drawn like the rest of the plugin. Profile cards are
|
||
tiles in the row language, sized to their own text so a privacy description is
|
||
never cut off mid-sentence, and their emoji are icon-font glyphs.
|
||
- The welcome page is opaque, unlike every other window here. It is read once and
|
||
carries a privacy decision; the game showing through it was noise.
|
||
- Config version 27 replaces the config instead of migrating it.
|
||
|
||
### Fixed
|
||
|
||
- The GDPR notice for the full-history profile is shown again. It had been
|
||
translated into 25 languages and drawn nowhere since 2026-05-18.
|
||
- Two profile cards claimed to be recommended at once: the badge sat on one while
|
||
the other still said "(recommended)" in its heading, in every language.
|
||
- Reopening the wizard no longer carries staged choices from a previous run.
|
||
|
||
---
|
||
|
||
## [1.14.0] — unreleased (local only)
|
||
|
||
The input row. It was the one surface a user actually works in and it spoke three
|
||
shape languages at once — a rounded pill, a square field, five filled default
|
||
buttons — sitting directly above a status bar that is rounded throughout. This
|
||
release makes the row one thing, and it teaches the popups the window's own
|
||
shapes while it is in there. **Not published** — the public release stays at
|
||
v1.5.6.
|
||
|
||
### Added
|
||
|
||
- A style lab under `/hellion lab`: variants of UI elements side by side, drawn
|
||
in real ImGui against the live theme. Permanent, as a dev playground — its
|
||
radio buttons default to whatever shipped, so the window doubles as a record
|
||
of which variant won. Every decision in this release was made by looking at it
|
||
in-game rather than at a drawing.
|
||
- `PopupRow`, the row a popup is made of: soft hover fill, a two-pixel accent
|
||
bar on the active entry — the sidebar row's shape, which is also exactly what
|
||
Character Select+ draws for its own popup entries. The channel picker and the
|
||
new input-row menu are built from it.
|
||
- A colour-channel guard in preflight (Block G). `EnsureContrast` works in ABGR,
|
||
theme colours are RGBA, both are `uint`, and the mistake of feeding one into
|
||
the other happened six times in a single day — each found only by a human
|
||
staring at unreadable text. The guard flags any raw theme member reaching the
|
||
helper; on its first real run it caught three cases a hand-written search had
|
||
missed minutes earlier.
|
||
|
||
### Changed
|
||
|
||
- The five filled buttons in the input row are two ghost buttons and a menu.
|
||
Symbols stay outside because they are used mid-sentence; theme, settings,
|
||
screenshot mode and hide moved in. The ghosts are flat at rest and glow on
|
||
hover — the first caller `DrawGlowBorder` ever had.
|
||
- The screenshot toggle was allowed into the menu only because its state moved
|
||
to the status bar first, as an accent camera pill that shows while the mode is
|
||
on. Knowing what the screen shows before the screenshot key is pressed is the
|
||
entire point of the mode; a state behind a closed menu answers nothing.
|
||
- The input field paints its own rounded surface and hands ImGui a transparent
|
||
frame, so the widget draws only text and caret. Focus is a two-pixel accent
|
||
rail on the left edge — the same mark rows and popups use. The field is about
|
||
a hundred pixels wider, reclaimed from the button reserve.
|
||
- The channel pill is chamfered, the corner language of the segmented control,
|
||
with a faint white depth gradient.
|
||
- The channel header traded its surface plate for a tenth-opacity accent wash.
|
||
The plate was the exact shape the settings window abandoned in v1.11.0 — it
|
||
reads fine on blue themes and vanishes on violet ones.
|
||
- The sidebar softened, on tester feedback that the transition to the chat field
|
||
was too hard: the full-width border line under every row is a fading rule now,
|
||
the gap between list and messages carries a surface wash instead of two hard
|
||
edges, and the selected tab bridges across it so it touches the conversation
|
||
it selects.
|
||
- Hover fades run at a quarter of their old speed with a smoothstep curve —
|
||
soft start, soft landing. 14/s in was judged light speed; it is 3/s now, and
|
||
a test guards against drifting back. Every hover in the plugin inherits both
|
||
changes through the one shared code path.
|
||
|
||
### Fixed
|
||
|
||
- Popups size themselves from their widest visible entry. Both new popups
|
||
carried a guessed minimum width, and German outran it within a day —
|
||
`Schnellauswahl` and `Chat ausblenden` were clipped mid-word.
|
||
- Popup entry text was unreadable at rest on several themes and only became
|
||
legible on hover: the RGBA-into-ABGR mistake again, in `PopupRow` and three
|
||
spots in the lab. Fixed, and the new preflight guard exists so the seventh
|
||
occurrence dies in CI rather than in a screenshot.
|
||
- The pill label was raw theme text on an accent fill with no contrast check.
|
||
|
||
### Known issues
|
||
|
||
- The channel header still recomputes its widths every frame rather than on the
|
||
status bar's one-second tick.
|
||
- `Metrics.Scale` still calls a Dalamud property that is marked obsolete.
|
||
- The first-run wizard is now the last surface drawn in ImGui defaults. It is
|
||
the next cycle.
|
||
|
||
---
|
||
|
||
## [1.13.0] — unreleased (local only)
|
||
|
||
Typography. The message list was the last surface still drawn in ImGui defaults,
|
||
and it is the only one a reader looks at line by line rather than in glances. It
|
||
now has named type roles instead of a single size, a header above the
|
||
conversation, and rows that read as rows. **Not published** — the public release
|
||
stays at v1.5.6.
|
||
|
||
### Added
|
||
|
||
- A header above the conversation: the channel name in tracked small caps with
|
||
the tab's own icon, and the home world on the right. It stays out of the way
|
||
where the name is already on screen — the top-tab strip carries it, and so does
|
||
a pop-out's title bar — and disappears entirely when the window is too short to
|
||
leave room for readable chat.
|
||
- Timestamps sit in a column of their own, so sender names line up underneath
|
||
each other instead of starting wherever the previous stamp happened to end.
|
||
- Local and server time in the status bar, in the game's own LT/ST notation.
|
||
Server time comes from the game rather than from a local UTC conversion, so it
|
||
follows whatever Square Enix does with it.
|
||
- Rows have a surface: a wash from the left and a two-pixel accent bar, fading in
|
||
and out rather than snapping.
|
||
- The sender is set in a heavier cut of the same face. There is no bold in the
|
||
plugin, so the weight comes from a denser rasterisation — which means it has no
|
||
effect when both font settings are off and the game's own face draws.
|
||
- System messages are italic. Nobody said them; it is the game talking.
|
||
- Card density finally differs from compact: the sender on its own line, the body
|
||
indented onto the text column, and air between messages.
|
||
- A camera button in the input row for screenshot mode, lit while active. The
|
||
setting had only ever existed in the right-click menu on a player name, which
|
||
for a privacy feature is close to not existing at all.
|
||
- `Hide timestamps when redundant` is reachable. It has shipped with translations
|
||
since 1.5.6 and never had a control.
|
||
|
||
### Fixed
|
||
|
||
- **Screenshot mode reached one surface out of four.** An auto-tell tab is named
|
||
`Player@World`, and the sidebar, the tab strip and a pop-out's window title all
|
||
drew that untouched — so a screenshot of the default view named the
|
||
conversation partner while every message below it was anonymised. All four
|
||
surfaces now share one rule, and the placeholder is re-salted on every plugin
|
||
load so two screenshots taken weeks apart cannot be tied together by it.
|
||
- `Show timestamps` in the tab editor does something again. It had two readers in
|
||
1.5.6 and lost both when the old chat window was retired in May.
|
||
- Four settings could always leave the row-height cache stale and never did: the
|
||
italic size, the italic toggle, and the two font toggles. The last two were the
|
||
quiet ones — both size fields default to the same value, so nothing in the
|
||
cache key moved while the glyph widths underneath it did. The clock format and
|
||
the per-tab timestamp switch join them.
|
||
- The word-wrap calculation was handed the UI scale where ImGui wanted the ratio
|
||
between rendered and baked size. The two are the same number until a second
|
||
size enters a line, which is exactly what this release introduces.
|
||
- Emoji and other characters outside the basic plane no longer break a tab name
|
||
drawn in tracked caps.
|
||
|
||
### Changed
|
||
|
||
- **Config version 26.** The migration marks existing tell tabs as
|
||
partner-named, which is what screenshot mode reads. Tabs promoted to permanent
|
||
before this version cannot be recovered — promotion clears every marker and
|
||
keeps the name — but renaming one has the same effect.
|
||
- The header replaced the pop-out's plain title row. With the title bar on it
|
||
shows only the world, because the title already carries the name.
|
||
- The channel header gave up its clock when both times moved to the status bar.
|
||
Three copies of the same number on one screen is two too many.
|
||
- All three custom font handles now rasterise the full glyph range. The smaller
|
||
one started with an ASCII-sized range on the assumption it would only draw
|
||
clocks and world names; a single umlaut in a tab name would have broken it.
|
||
|
||
### Known issues
|
||
|
||
- The channel header recomputes its widths every frame rather than on the status
|
||
bar's one-second tick. Measurable, not measured.
|
||
- `Metrics.Scale` still calls a Dalamud property that is marked obsolete.
|
||
- The database viewer and the emoji picker are still English on every client.
|
||
- 245 orphaned resource keys remain as the inventory of what the v1.6.0 rebuild
|
||
lost.
|
||
|
||
---
|
||
|
||
## [1.12.0] — unreleased (local only)
|
||
|
||
The reconnection cycle. A commit during the v1.6.0 window layer rebuild removed the old tab system,
|
||
and the rebuild wired back roughly two thirds of it — 433 of 824 translation keys reached no line of
|
||
code, and four whole features had a saved setting but no way in. This release puts them back and
|
||
translates the settings window. **Not published** — the public release stays at v1.5.6.
|
||
|
||
### Added
|
||
|
||
- Message export is reachable again. Markdown, JSON and CSV, per channel or the whole database,
|
||
written atomically so a failed write cannot leave half a file behind.
|
||
- Retroactive cleanup is back, with a preview that counts what a run would delete before anything
|
||
is removed, and the Ctrl+Shift confirm in front of the actual delete.
|
||
- Database maintenance — integrity check, VACUUM, index rebuild — and the manual retention run
|
||
both have a control again.
|
||
- The tab editor returns: create, rename, reorder and delete tabs, with the channel selector and
|
||
the activity filter attached to each one.
|
||
- Pinning has a way in and a way back out. A pinned tab survives a restart and reopens with its
|
||
history.
|
||
- Eleven settings that steered real behaviour and had no control at all are reachable again.
|
||
- The settings window is translated into all 25 languages: 435 keys, held against the glossary the
|
||
plugin already used, with the game client's own word for a tell in each locale rather than a new
|
||
invention.
|
||
- Map flags and item links can be inserted into the input again, and the right-click menu is back
|
||
on the input field.
|
||
|
||
### Fixed
|
||
|
||
- **The channel grid now decides what is stored.** Until this release the unknown-channel failsafe
|
||
was applied to known channels as well, so a channel the user had unticked was still written when
|
||
that failsafe was on. See the note under _Changed_ — this is a behaviour change, not only a fix.
|
||
- The retroactive cleanup could never be applied. The preview takes the database lock itself, and
|
||
its release was counted as a mutation, so every preview was stale the instant it finished and the
|
||
apply button never appeared.
|
||
- VACUUM ran against an open reader on the primary connection and failed, after which the plugin
|
||
reported that nothing had been deleted — while everything had. The reader sits on its own
|
||
connection now.
|
||
- Deleting messages left the full-text index behind, so search kept returning rows that no longer
|
||
existed.
|
||
- A tell arriving from a popped-out partner hijacked the main window's active tab.
|
||
- The arrow keys walk the sent-message history again.
|
||
- The export wrote a UTF-8 BOM into JSON, which strict parsers reject; CSV keeps it, because
|
||
without it Excel guesses the code page. Enum values interpolated into JSON wrote the member name
|
||
and produced invalid output.
|
||
- Five strings in the settings and privacy tabs were still drawn as English literals.
|
||
|
||
### Changed
|
||
|
||
- **Behaviour change in storage.** Anyone who had unticked channels and left the unknown-channel
|
||
failsafe on was storing more than the channel grid said. From v1.12.0 the grid is authoritative,
|
||
so those installations store less. Nothing already in the database is touched.
|
||
- Every long-running database operation now goes through one gate instead of seven near-identical
|
||
background workers, each of which had to remember to take the lock. One of them did not.
|
||
- The export reads message text from the chunk lists rather than the flattened field, so links and
|
||
formatted segments survive the round trip.
|
||
- Config version 25. There is no migration step behind it: the v24 migration switched the privacy
|
||
filter off where it was on with nothing selected, and 25 only records that the storage rule
|
||
changed shape.
|
||
|
||
### Known issues
|
||
|
||
- The database viewer (`/hellionView`) and the emoji picker are still English on every client, and
|
||
one export dialog still carries the old Chat 2 branding in its title.
|
||
- 145 `Language.*` and 100 `HellionStrings` keys still have no caller. That is an inventory of
|
||
features lost in the v1.6.0 rebuild, not a delete list — timestamp layouts, duplicate-message
|
||
collapsing, the About texts, the novice network button and the honorific glow are all in there.
|
||
- `AboutTab` states GPL-3.0-or-later while the translated resources say EUPL-1.2.
|
||
- The full-text index is emptied on every deletion and only rebuilt at the next plugin start; until
|
||
then the database viewer searches more slowly.
|
||
- The first-run wizard, the input bar buttons and the message list itself are still stock ImGui.
|
||
|
||
---
|
||
|
||
## [1.11.0] — unreleased (local only)
|
||
|
||
The settings window, rebuilt on the widgets v1.10.0 introduced, plus the defects the rebuild kept
|
||
turning up. **Not published** — the public release stays at v1.5.6.
|
||
|
||
### Added
|
||
|
||
- Every settings tab now draws the same way: section headings as tracked small caps with a rule
|
||
that fades out, rows with the label left and the control right-aligned, sliding switches instead
|
||
of checkboxes, and a segmented control where two radio buttons used to pretend to be two
|
||
settings.
|
||
- Explanations moved out of the help markers and onto the rows. Many were translated into 25
|
||
languages and had never appeared on screen.
|
||
- Surfaces have depth: a gradient, an accent wash from the top edge, and slow drifting motes. The
|
||
chat log and the pop-outs stand on the same floor, at a fraction of the intensity — a settings
|
||
page is read in glances, a chat log line by line. `Reduce motion` turns the motes off entirely.
|
||
- Foreground colours are chosen by measured WCAG contrast against the surface they land on rather
|
||
than taken from the theme unchanged, so a pale accent cannot swallow white iconography.
|
||
- The settings window is opaque, unlike the chat window. Contrast cannot be computed against a
|
||
background that is the game world.
|
||
- Three settings that steered real behaviour and had no control at all are reachable again:
|
||
interface language, the global sound toggle, and the keybind mode.
|
||
- Whether the log shows history from before the current session now has a control. It was written
|
||
only by the first-run wizard, and only if the user reached step 3.
|
||
- Per-channel retention is visible in Data & Privacy. Three of the four wizard profiles write one
|
||
and switch the sweep on, and the window only ever showed the global default.
|
||
|
||
### Fixed
|
||
|
||
- Pinned tell tabs came up empty for the whole session. The history query runs at plugin start,
|
||
where no character is logged in yet, so it looked up tells for character zero and never tried
|
||
again. It defers to the login now.
|
||
- Every enum dropdown listed eight rows regardless of how many values it had, several of them
|
||
blank. The fourth argument of the binding is the popup height, not the item count.
|
||
- Six settings had a control, a saved value and no reader anywhere in the plugin. Three sat
|
||
together under timestamps, where only the 24-hour clock actually works. Removed rather than
|
||
wired up: their own strings disagree about what they were meant to do.
|
||
- The same privacy grid was drawn in two tabs, all 89 entries of it.
|
||
- Descriptions were sized as one line while being drawn with a wrap width — clipped in a setting
|
||
row, overflowing in a section heading.
|
||
- Row separators used an unscaled offset with a scaled stroke, so at UI scale 2 half the line
|
||
landed in the next row.
|
||
- A pop-out with its title bar on could not be closed at all. Pop-in now sits in the input row.
|
||
- BetterTTV's shared-emote endpoint went behind authentication; the 403 response was handed to a
|
||
list deserializer and took the 65 working global emotes down with it on every start.
|
||
|
||
### Changed
|
||
|
||
- Thirteen labels that had translated resources but were drawn as English literals now use them,
|
||
including all seven tab names in the sidebar.
|
||
- Twelve duplicated per-tab helpers merged into one place. The enum combos were calling
|
||
`Enum.GetValues` inside their draw call, allocating five arrays per frame while the window was
|
||
open.
|
||
|
||
### Known issues
|
||
|
||
- Around 270 visible strings across the plugin are still English on non-English clients, most of
|
||
them in the settings window: section headings, keybind labels, and the descriptions written
|
||
during this cycle. They have no resource key yet. Translation is planned as its own pass before the tester beta; new strings
|
||
ship translated from here on.
|
||
- The first-run wizard, the input bar buttons and the message list itself are still stock ImGui.
|
||
|
||
---
|
||
|
||
## [1.10.0] — unreleased (local only)
|
||
|
||
The style foundation the v2.x plan has been carrying since May. Custom-drawn chrome instead of
|
||
ImGui defaults, and a layout layer that survives display scaling. **Not published** — the public
|
||
release stays at v1.5.6.
|
||
|
||
### Added
|
||
|
||
- Sidebar rows now have surfaces: the active tab gets a raised fill and a 2px accent bar, hover
|
||
fades in and back out, and rows sit flush with separators between them.
|
||
- Top tabs are drawn rather than borrowed from ImGui selectables: their own height, an accent
|
||
underline on the active one, and three text states.
|
||
- Unread markers are count badges in the accent colour rather than a red dot. Red reads as an
|
||
error; an unread message is not one.
|
||
- Status bar slots are pills — channel with its status dot, privacy with its lock, counts, tells,
|
||
and the version right-aligned. Each slot drops out on its own when the window gets too narrow.
|
||
- Widget gallery under `/hellion widgets` (debug builds only) showing every drawn widget in its
|
||
states.
|
||
|
||
### Fixed
|
||
|
||
- Compact message rows assumed a constant height and were clipped with a fixed 18px. They wrap, so
|
||
they are not constant, and the real single line is 17px at the default font — the list drifted
|
||
against the scrollbar. Both densities now plan from measured heights.
|
||
- The message height cache ignored display scaling, which feeds word wrapping. Changing the scale
|
||
left every cached row stale.
|
||
- Layout constants across the sidebar, input bar, honorific header and message list did not scale.
|
||
At 150% the text grew and the boxes did not; the quick buttons stopped fitting their column.
|
||
- Vertical offsets were frozen values that only centred correctly at one font size. They are
|
||
measured now.
|
||
- The hover sheen kept its own timestamp map and only cleared it on un-hover, so a row that
|
||
disappeared while hovered leaked its entry until the plugin reloaded.
|
||
- Quick-button tooltips rendered inside the icon font, which has no ASCII glyphs, and came out as
|
||
empty boxes. They are also localised now.
|
||
- The theme preview in settings had been showing surfaces, an accent bar and an unread marker that
|
||
the real sidebar never drew. Both sides match now, and the preview reads the same colour tokens.
|
||
|
||
### Changed
|
||
|
||
- Hover is a held value that rises at 14/s and falls at 8/s, rather than a one-shot sweep that
|
||
stopped after 0.65s while the pointer was still there.
|
||
- The active surface token went from 10% to 25% toward the primary colour. At 10% it was
|
||
indistinguishable from an idle row.
|
||
- Row fills follow the window's own opacity, so the sidebar no longer sits as a solid block inside
|
||
a translucent window.
|
||
|
||
### Internal
|
||
|
||
- New style layer: `Metrics` (scale-aware layout values), `HoverState` (held hover per element),
|
||
and five drawn widgets — Row, Badge, IconButton, LineDivider, Pill.
|
||
- Pure halves split out for the build suite: `MetricsMath`, `HoverMath`, `WidgetGeometry`,
|
||
`LayoutFingerprint`.
|
||
- Test suite 829 → 892, and `StatusBarCacheTests` is back in the build after sitting in the
|
||
exclusion block.
|
||
|
||
## [1.9.0] — unreleased (local only)
|
||
|
||
Polish, tester-beta preparation and a concurrency hardening pass. **Not published** — the public
|
||
release stays at v1.5.6, so the download links in `repo.json` deliberately still point there while
|
||
the assembly version reads 1.9.0.
|
||
|
||
### Fixed
|
||
|
||
- Incoming messages could be dropped without a trace. The worker walked the tab list while another
|
||
thread rewrote it, the resulting exception was swallowed by the surrounding error handler, and the
|
||
message ended up nowhere: no tab entry, no notification sound, no tell routing.
|
||
- Clicking a tab could open a different one, or crash the render loop, when tabs appeared or were
|
||
evicted in the same frame. The window now renders from one consistent snapshot per frame.
|
||
- An open tab context menu could silently re-bind to a different tab. Widget identity is derived
|
||
from the tab itself now, not from its position in the list.
|
||
- `Tab.Clone()` dropped the tab icon and legacy channel data.
|
||
|
||
### Changed
|
||
|
||
- Settings sliders write the configuration once, on release, instead of on every frame while
|
||
dragging. Renaming a tab writes once when you finish, including when the context menu is
|
||
dismissed by clicking elsewhere.
|
||
- Tell history loads through a dedicated `(Receiver, Date)` index (schema 5). Opening a tell tab no
|
||
longer sorts the entire conversation history first.
|
||
- Pinning, unpinning and promoting tabs no longer write to disk while holding the tab lock.
|
||
|
||
### Internal
|
||
|
||
- New `ConfigMapsLock` guards the config maps the settings UI edits while a background save may be
|
||
serialising them.
|
||
- Removed `DeferredSaveFrames`: the debounce was fully wired but never armed.
|
||
- Test suite 812 → 829, including migration and query-plan coverage.
|
||
|
||
## Hellion Chat 1.5.6 — Settings Overhaul + Filter & Notification Polish (2026-05-23)
|
||
|
||
- Settings window reorganised: ten tabs down to seven (General, Appearance, Chat, Window, Channels, Data & Privacy, About). Each tab now uses collapsible sections grouped by control type. Sections start collapsed every time you open a tab — less noise, easier to find what you need.
|
||
- New sender-name display options under Chat → Messages: separate world-suffix and name-format modes (Full name / First name only / Initials × Never / Other worlds only / Always).
|
||
- Plugin-only symbols now show a pre-send warning so other players do not get empty boxes (Chat → Messages → "Warn before sending plugin-only symbols").
|
||
- Separate window opacity for focused vs. inactive chat window (Appearance → Window style → "Inactive window opacity"). The slider above sets the focused value.
|
||
- Custom notification sound volume slider (General → Sound, and mirrored in Channels → per-tab → Notification). Affects only the three bundled custom sounds; the 16 game sounds are unaffected.
|
||
- The per-tab regex filter that briefly shipped earlier in this cycle has been removed — FFXIV's built-in blackword filter covers the same need.
|
||
- All 24 locale files updated for the new section labels and the v1.5.6 control labels (machine translation; native review continues via the Hellion Forge Discord).
|
||
|
||
---
|
||
|
||
## Hellion Chat 1.5.5 — Upstream-Sync Tab-Features (2026-05-21)
|
||
|
||
A backlog-sync cycle. Inherited tab items: a failed-tell warning toast, per-tab
|
||
notification sounds (16 game sounds or three bundled Hellion sounds with a
|
||
preview button), an auto-focusing 512-character tab rename, a jump-to-latest
|
||
button in the chat log header, and map-flag / item-link insertion from the chat
|
||
input. Plus the Hellion Forge fox banner becomes a real image. Schema bumped to
|
||
v18, additive fields only, no data migration.
|
||
|
||
---
|
||
|
||
## Hellion Chat 1.5.4 — Polish and Motion (2026-05-20)
|
||
|
||
A polish cycle of three P3 items. Theme switches now crossfade smoothly over ~300 ms
|
||
across every Hellion-rendered surface; the window background snaps deliberately so the
|
||
per-window opacity override from Dalamud's pinning menu stays intact. A new header
|
||
quick-picker — a palette button left of the cog — opens a compact popup for switching
|
||
themes and tabs without opening Settings. Sidebar icons and card-mode message borders
|
||
gain framerate-independent hover animations. A new "Reduce motion" toggle in Theme &
|
||
Layout disables the crossfade, hover animations and unread-tab pulse for accessibility.
|
||
No schema bump, migration v17 stays.
|
||
|
||
## Hellion Chat 1.5.3 — Localisation Wave + Bundled-Font Overhaul (2026-05-19)
|
||
|
||
Multi-language pass plus a long-standing first-frame HITCH lands as a side effect of a font-stack
|
||
rewrite. The bundled UI font swaps from Exo 2 to Inter Light. HellionChat now ships strings and
|
||
renderable glyph coverage for 24 languages.
|
||
|
||
### User-visible
|
||
|
||
- Twenty-four selectable UI languages: Catalan, Czech, Danish, Dutch, English, Finnish, French,
|
||
German, Greek, Hungarian, Italian, Japanese, Korean, Norsk bokmål, Polish, Portuguese (Brazil),
|
||
Portuguese (Portugal), Romanian, Russian, Spanish, Swedish, Turkish, Ukrainian, Simplified
|
||
Chinese, Traditional Chinese. The dropdown sorts alphabetically by endonym, "None" pinned first.
|
||
Non-native translations are AI-assisted and flagged for community native-speaker review via the
|
||
Hellion Forge Discord.
|
||
- Bundled **Inter Light** replaces Exo 2 as the in-plugin font. Wider European coverage (Latin
|
||
Extended-A/B, Greek polytonic, Cyrillic Supplement) so Czech, Polish, Romanian, Turkish,
|
||
Hungarian, Greek and Ukrainian render without manual font configuration. SIL OFL 1.1, 343 KB.
|
||
- **NotoSansCjkRegular fallback** layer added as a merge-on-top so Hangul, Simplified-Chinese
|
||
characters specific to the post-1956 reform, and other CJK glyphs the FFXIV Japanese game font
|
||
does not ship now render correctly inside the HellionChat UI.
|
||
- First-frame **HITCH dropped from ~74 ms** (the v1.5.2 baseline that has held since v1.4.x) to a
|
||
**median of ~20 ms** (5-reload sample: 23.6 / 20.4 / 17.9 / 20.1 / 19.2 ms, Linux/Wine; Windows
|
||
baseline pending Jin's verification per the cross-platform-pflicht). The bundled-font path
|
||
silently fell back to the FFXIV Axis game font for the entire v1.5.x series because of an
|
||
early-return in the draw loop. The fix that routes `RegularFont` through draw also lands the
|
||
defer-pattern win the v1.5.1 cycle was reaching for.
|
||
- **ExtraGlyphRanges activates automatically** when the user picks a language that needs a non-Latin
|
||
script. Selecting Korean enables the Korean glyph range and rebuilds the atlas without a manual
|
||
toggle in Fonts & Colours.
|
||
- New **WarningText under the language dropdown** notes that FFXIV's own chat input only fully
|
||
supports EN, DE, FR and JA character sets. Other languages render inside HellionChat but may
|
||
garble when typed into in-game chat or sent as messages.
|
||
|
||
### Under the hood
|
||
|
||
- Three-layer font stack in `FontManager.BuildRegularFontHandle` and `BuildItalicFontHandle`:
|
||
Inter Light (or the user-selected global font) as primary, FFXIV JapaneseFont as merge 1 for
|
||
native FFXIV kana/kanji style, NotoSansCjkRegular as merge 2 for everything else CJK.
|
||
- Two new `ExtraGlyphRanges` flags: `LatinExtended` (U+0100-U+024F) and `Greek` (U+0370-U+03FF +
|
||
U+1F00-U+1FFF). Implemented as `builder.AddChar` pair lists in `SetUpRanges` (no managed-pointer
|
||
pinning needed).
|
||
- `LanguageOverride` enum gains ten locales (Catalan, Czech, Danish, Finnish, Hungarian,
|
||
Norwegian, Polish, Portuguese (Portugal), Turkish, Ukrainian) plus three previously
|
||
commented-out entries (Italian, Korean, Norwegian re-enabled with code `nb` instead of `no`).
|
||
New values are appended to the enum to keep existing user-config integer serialisation stable.
|
||
- **Crowdin gap closed:** four ChatTwo keys added after the last community sync
|
||
(`Options_ColorSelectedInputChannelButton_Name` / `_Description`,
|
||
`Options_HideInNewGamePlusMenu_Name` / `_Description`) are now backfilled into the thirteen
|
||
legacy Crowdin locales with per-key AI-translated markers.
|
||
- Plugin init runs a one-shot migration that ORs in the matching `ExtraGlyphRanges` flag based on
|
||
the user's current `LanguageOverride`. An update from v1.5.2 picks up the new coverage without
|
||
the user having to toggle the language twice.
|
||
- `Plugin.cs:937` draw-path fixed: `RegularFont` is now pushed whenever **either** `FontsEnabled`
|
||
**or** `UseHellionFont` is on. The previous `Config.FontsEnabled`-only check meant the bundled
|
||
font path was silently dead whenever `FontsAndColours.cs:50` force-set `FontsEnabled = false` on
|
||
the UseHellionFont-toggle. Source of the HITCH win.
|
||
- `ExtraGlyphRanges` settings panel is now reachable in **all** UseHellionFont / FontsEnabled
|
||
combinations. The bundled-font branch used to short-circuit past it.
|
||
- **Resource bundle split:** fork-added strings live in `HellionStrings.resx` (24 locales, 328
|
||
keys each) alongside the ChatTwo-Crowdin-heritage `Language.resx` (24 locales, 456 keys each).
|
||
The `Language` siblings for the ten brand-new locales and Greek carry a Hellion Forge maintainer
|
||
header that points reviewers at the Discord rather than the standalone-hosted Gitea.
|
||
- **Em-dash sweep** across the EN source and 18 translations: in-prose em-dashes replaced with
|
||
period or colon per the house style guide. Russian and Ukrainian keep their typographic norm
|
||
where the em-dash is orthographically required (subject-predicate separator).
|
||
- **Bundled font asset rotation:** `HellionFont.ttf` (Exo 2) plus its OFL notice removed from
|
||
`Resources/`. `Inter-Light.ttf` plus `Inter-OFL.txt` take their place. `FontManager`
|
||
references rename to `BundledFontBytes` / `TryGetBundledFontBytes()` for clarity (config field
|
||
`UseHellionFont` keeps its name so existing user configs deserialize cleanly).
|
||
|
||
### Migration
|
||
|
||
- Migration v17 stays (no schema bump).
|
||
- Existing `UseHellionFont = true` users transition transparently from Exo 2 to Inter Light on
|
||
first reload.
|
||
- Existing users with `LanguageOverride != None` get their matching `ExtraGlyphRanges` flag set
|
||
on the first plugin init after the v1.5.3 update (Plugin.cs LoadAsync migration step).
|
||
|
||
### Reserved for follow-up cycles
|
||
|
||
- Native-speaker review pass for AI-assisted translations in the 13 legacy Crowdin locales (ca,
|
||
es, fr, it, ja, ko, nl, pt-BR, ro, ru, sv, zh-Hans, zh-Hant) — corrections via the Hellion
|
||
Forge Discord.
|
||
|
||
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
||
|
||
---
|
||
|
||
## Hellion Chat 1.5.2 — First-Run Wizard Rework (2026-05-18)
|
||
|
||
UX patch. The single-page first-run wizard becomes a four-step staged-commit flow, the privacy
|
||
profile catalogue gains a fourth entry "Roleplay", and a new power-settings stage surfaces six
|
||
previously-hidden Configuration defaults. Existing v1.5.1 users see the new wizard once on first
|
||
v1.5.2 boot via a new `WizardLastShownVersion` config marker.
|
||
|
||
User-visible:
|
||
|
||
- Wizard layout: Welcome → Privacy profile → Power settings → Done. Forge-Bronze pagination dots,
|
||
per-step Back / Decide later / Next footer. Decide-later and X-close both leave the existing
|
||
config untouched; only the Finish ✓ click commits pending choices.
|
||
- Fourth privacy profile "Roleplay": Privacy-First whitelist plus `Say` and both emote types, with a
|
||
30-day retention window for `Say` and 90 days for the two emote channels. `Shout`, `Yell` and
|
||
`NoviceNetwork` stay out — public-distance noise from strangers is not story content.
|
||
- Privacy picker becomes a 2×2 grid. Casual stays the recommended option with a ★ marker.
|
||
- Power-settings stage surfaces six existing `Configuration` fields in one place: Load Previous
|
||
Session, Filter Include Previous Sessions, Auto-Tell-Tabs History Preload, Compact Density,
|
||
Prettier Timestamps, plus a built-in theme picker. No new settings are introduced — the stage just
|
||
collects what was previously buried in Settings → Privacy / Chat / Data Management / Appearance.
|
||
- Inline test hint on the done stage: `type /tell <Player Name> into chat` surfaces the auto-tell-tab
|
||
spawn mechanism for new users.
|
||
- Wizard window starts at 720×480 (was 900×560) and can shrink to 600×400. Step 1 wraps the fox
|
||
banner in a collapsible TreeNode, folded by default — onboarding copy stays primary.
|
||
- Existing v1.5.1 users get the new wizard surfaced once on first v1.5.2 boot. A new
|
||
`WizardLastShownVersion` config field tracks the most recent version whose wizard was shown;
|
||
Plugin.LoadAsync resets `FirstRunCompleted` once when the constant `1.5.2` doesn't match.
|
||
|
||
Under the hood:
|
||
|
||
- `WizardStateSmokeStep` registered with `/xlperf`. Variant 1 walks the four steps with empty
|
||
pending state to pin the no-op CommitPending path. Variant 2 picks Roleplay on Step 2, skips
|
||
Step 3, commits, and asserts `LoadPreviousSession` / `FilterIncludePreviousSessions` stayed on
|
||
their pre-test value — pinning the null-semantics contract. The step snapshots six privacy /
|
||
retention fields before Variant 2 and `CleanUp()` restores them, so back-to-back runs don't drift
|
||
the active profile.
|
||
- Twelve pure-helper xUnit Facts in the Build Suite (`Privacy/PrivacyDefaultsTests.cs`) cover all
|
||
four profile whitelists plus the new Roleplay retention overrides.
|
||
- `Configuration` grows one optional string field `WizardLastShownVersion` (default empty). No
|
||
schema bump — migration v17 still applies.
|
||
|
||
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
||
|
||
[Full release notes on the Gitea release page.](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/tag/v1.5.2)
|
||
|
||
---
|
||
|
||
## Hellion Chat 1.5.1 — FontAtlas Refactor and Hellion Forge Signature (2026-05-17)
|
||
|
||
Hybrid FontManager refactor plus an embedded Hellion Forge provenance mark.
|
||
|
||
- FontManager handle creation moves into the ctor inside a single `atlas.SuppressAutoRebuild()`
|
||
block — the font atlas now builds once per plugin load instead of four to five times.
|
||
- Hybrid property model: `Axis`, `AxisItalic` and `FontAwesome` become init-only handles;
|
||
`RegularFont` and `ItalicFont` stay mutable because the eight font settings still need to replace
|
||
them at runtime via the renamed `RebuildDelegateFonts()` path, without a plugin reload.
|
||
- `FontAwesome` reuses Dalamud's `UiBuilder.IconFontFixedWidthHandle` instead of building its own
|
||
atlas slot.
|
||
- `BuildFontsAsync` and `BuildFonts` are removed; the live mutation path is `RebuildDelegateFonts()`
|
||
now.
|
||
- Two new self-test steps register with `/xlperf`: FontManager ctor smoke (every handle non-null, no
|
||
atlas load-exception) and push smoke (`Push()` returns without throwing).
|
||
- Hellion Forge signature embedded in the plugin DLL: a fox-head ASCII silhouette is prepended to
|
||
the `/xllog` bootstrap banner on every plugin load, and a full fox banner with "Hellion Forge" set
|
||
inside the body is available as a folded `TreeNode` in the First-Run Wizard and Settings →
|
||
Information tab. Drawn by Julia Moon.
|
||
- Honorific full-gradient port (originally scheduled for this cycle) was dropped: Honorific 3.2
|
||
exposes no IPC for the rendered gradient frame, and an in-plugin port of the colour palette was
|
||
declined. The integration stays at the v1.4.7 glow-only shape.
|
||
|
||
The 10× HITCH cut targeted from the v1.5.0 cross-plugin baseline did not land — HITCH stays around
|
||
80 ms because the cost lives in the UiBuilder first-frame render path, not in the atlas build (which
|
||
this cycle did reduce from 4-5 builds per load to 1). A first-frame render investigation is reserved
|
||
for a later cycle. No settings changes, no migration. v17 stays.
|
||
|
||
[Full release notes on the Gitea release page.](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/tag/v1.5.1)
|
||
|
||
---
|
||
|
||
## Hellion Chat 1.5.0 — DI Foundation and Service Refactor (2026-05-17)
|
||
|
||
Major architecture cycle. The plugin bootstrap moves to a generic-host DI container
|
||
(`Microsoft.Extensions.Hosting` + `IServiceCollection`) modelled on Lightless Sync. Service logging
|
||
migrates from a static `Plugin.LogProxy` locator to typed `Microsoft.Extensions.Logging.ILogger<T>`
|
||
via constructor injection, bridged over Dalamud's `IPluginLog` by a custom `DalamudLogger` trio.
|
||
|
||
### Under the hood
|
||
|
||
- 18 instance-class services migrate to `ILogger<T>` via constructor injection across four slices:
|
||
data layer (`MessageStore`, `MessageManager`, `AutoTellTabsService`), IPC and integrations
|
||
(`HonorificService`, `IpcManager`, `TypingIpc`, `ExtraChat`, three `GameFunctions` classes), UI
|
||
window layer (`ChatLogWindow`, `DbViewer`, `Popout`, three settings tabs), and root (`Commands`,
|
||
`ThemeRegistry`, `PayloadHandler`).
|
||
- `Plugin.LogProxy` stays in place for the eight buckets ctor injection cannot reach: static helpers
|
||
(`EmoteCache`, `AutoTranslate`, `MemoryUtil`, `WrapperUtil`), Dalamud-reflected types
|
||
(`Configuration`), the `Message` data class, and instance classes that only log from static
|
||
methods (`FontManager`, one `GameFunctions` site).
|
||
- Plugin.cs finishes at 1012 lines — virtually identical to the pre-cycle 1013. The new Phase-1 host
|
||
build and `Plugin.X` bridge wiring trade out exactly the service and window allocations that
|
||
previously lived in `LoadAsync`.
|
||
- Cross-plugin baseline confirms no performance penalty against Chat 2: HellionChat first-frame
|
||
HITCH 77 ms median, Chat 2 74 ms median. Lightless and XIVInstantMessenger sit around 7 ms by
|
||
deferring their font-atlas build past `Finished loading` — that pattern is the v1.5.1 follow-up
|
||
item.
|
||
|
||
### User-visible
|
||
|
||
- Slash-command insert fix: pasting a slash command into the chat input (Friend List "/tell" action,
|
||
plugin-driven inserts from Artisan, AllaganTools etc.) now replaces the existing input instead of
|
||
concatenating onto whatever the user was typing. Cherry-picked from ChatTwo upstream `ee7768ac`
|
||
with namespace adaptation.
|
||
|
||
Migration v17 stays (no schema bump).
|
||
|
||
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
||
|
||
---
|
||
|
||
## Hellion Chat 1.4.10 — Symbol-Picker and Tell-History Fix (2026-05-16)
|
||
|
||
Eleventh and final sub-patch of the v1.4.x Polish-Sweep series. Symbol picker for the chat input, a
|
||
tell-history reload fix for users with many active partners, and a closing cleanup sweep before
|
||
v1.5.0 picks up the DI-container adoption.
|
||
|
||
- Symbol picker for the chat input: smile-icon button left of the channel indicator opens a popup
|
||
with two tabs — 161 FFXIV PUA glyphs (Dalamud's SeIconChar enum) and 97 server-verified BMP
|
||
symbols round-tripped through `/echo` and `/say` in a four-round probe. Cursor-aware splice,
|
||
multi-insert keeps the popup open, recent-used strip floats the last sixteen picks across both
|
||
tabs. Toggle in Settings → Chat → Message behaviour, default on.
|
||
- Pinned auto-tell tabs reload their full history again. PreloadHistory had a hidden 500-row scan
|
||
cap that overrode the user-configurable `AutoTellTabsHistoryPreload` setting whenever you chatted
|
||
with many partners; less-frequent pinned partners lost their backlog. The cap is removed.
|
||
- Slash-command teardown cleanup: `/hellion`, `/hellionView`, `/hellionDebugger` (and
|
||
`#if DEBUG /hellionSeString`) wrappers are now cached as private fields so plugin teardown
|
||
detaches the live registration instead of re-Register'ing with identical args (latent maintenance
|
||
hazard from v1.4.9).
|
||
- v1.4.x Polish-Sweep wraps up here. The ImGuiListClipper render refactor that was on the v1.4.10
|
||
reserve list got dropped after cross-platform smoke showed the scroll rubber-band is a Wine/Linux
|
||
render-pipeline quirk, not universal — Windows users never saw it. It will get its own
|
||
platform-targeted spike in a later patch. Next major cycle is v1.5.0 with the DI-container
|
||
adoption (Microsoft.Extensions.Hosting + ILogger<T>) modelled on Lightless.
|
||
- Migration v17 stays (no schema bump).
|
||
|
||
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
||
|
||
---
|
||
|
||
## Hellion Chat 1.4.9 — Plugin-Load Render Polish (2026-05-15)
|
||
|
||
Tenth sub-patch of the v1.4.x polish-sweep series. First-frame render cost drops from ~127 ms median
|
||
down to ~76 ms median — comfortably under Dalamud's 100 ms HITCH warning threshold. The remaining
|
||
~13 ms gap to ChatTwo upstream (~63 ms median) is the cost of HellionChat-only features (sidebar tab
|
||
view, custom status bar, Honorific integration).
|
||
|
||
- First-frame defer: six non-essential rendering sections inside `ChatLogWindow` skip their first
|
||
Draw and run one frame later. Covered sections are the bottom status bar, channel-name SeString
|
||
chunks, window bounds check, v0.6.1 hint banner, autocomplete and input-preview calculation. At 60
|
||
fps the user sees those sections ~17 ms after plugin reload — invisible inside the ~2.5 s
|
||
font-atlas build window every reload runs through anyway. Frame 1 stays well under 100 ms too (~40
|
||
ms), so no secondary HITCH warning appears.
|
||
- Slash-command centralisation: `/hellion`, `/hellionView`, `/hellionSeString` and
|
||
`/hellionDebugger` are now registered during `LoadAsync` instead of inside the corresponding
|
||
window constructors. The commands work before their target window is opened the first time, and
|
||
Dalamud's plugin-manager configuration / open buttons (`UiBuilder.OpenConfigUi` / `OpenMainUi`)
|
||
hang on the same path.
|
||
- Plugin-load profiling logs stay on: `MessageStore.Connect`, `MessageStore.Migrate`,
|
||
`FilterAllTabs` and the auto-translate warm-up timing log are now Information level rather than
|
||
Debug. They serve as a tripwire so a future regression past 100 ms shows up directly in `/xllog`
|
||
without re-enabling Debug.
|
||
- ChatTwo IPC compatibility layer: HellionChat now mirrors ChatTwo's full IPC surface
|
||
(`GetChatInputState`, `ChatInputStateChanged`, `Register`, `Unregister`, `Available`, `Invoke`)
|
||
under the `ChatTwo.*` namespace in addition to our existing `HellionChat.*` provider gates.
|
||
Third-party integrations that historically only subscribe to ChatTwo's IPC — for example Artisan's
|
||
and AllaganTools' context-menu hooks — keep working without requiring a code change on their side.
|
||
Conflict detection prevents ChatTwo from loading in parallel with HellionChat, so there is no
|
||
slot-collision risk at runtime.
|
||
- Migration v17 stays (no schema bump).
|
||
- Internal: hypothesis-triage during the R2 cycle falsified three of the four candidate root causes
|
||
(font-atlas sync, theme-apply ABGR-cache init, multiple-window render). Actual cause is `DrawList`
|
||
setup cost distributed across ~10 ImGui sections inside ChatLogWindow (5-20 ms each). The six
|
||
selective defers above are the pragmatic fix — a clean structural rewrite would belong in the
|
||
v1.5.x DI-container cycle.
|
||
|
||
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
||
|
||
---
|
||
|
||
## Hellion Chat 1.4.8 — Hook-Layer and Polish Quick-Wins (2026-05-14)
|
||
|
||
Ninth sub-patch of the v1.4.x polish-sweep series. Hook-layer cluster (FTS5 full-text search,
|
||
ad-block foundation investigation) plus three polish quick-wins.
|
||
|
||
- DbViewer full-text search: optional FTS5 index across the full chat history. Built asynchronously
|
||
on first run after the update with a progress toast (UI stays responsive, the toggle is disabled
|
||
until the build completes). The local page-filter remains the default mode. Multi-word queries
|
||
match as exact phrases; power users can opt into raw FTS5 `MATCH` syntax by wrapping their own
|
||
double-quotes around the term.
|
||
- Custom theme files now auto-reload when edited while the theme is active. Save the JSON in your
|
||
editor and the live render picks up the change within a second — no need to re-click the theme in
|
||
the picker. Disk-stat is throttled to 1 Hz so per-frame cost stays free.
|
||
- Retention sweep no longer blocks the framework thread. `Framework.Run(...).Wait()` is replaced by
|
||
`Framework.RunOnTick(...)`, which removes the ~194 ms hitch the sweep used to add per run.
|
||
- Status bar height is derived from `GetTextLineHeightWithSpacing()` plus a DPI-aware spacer so the
|
||
bar renders correctly at Windows display scaling above 100 %. Linux/Wayland default of 100 % is
|
||
unaffected.
|
||
- Receive-suppressed-tells routing was investigated this cycle and **postponed to v1.5.x**. When
|
||
other plugins suppress tells via `CheckMessageHandled`, FFXIV's chat pipeline skips the
|
||
`RaptureLogModule.AddMsgSourceEntry` path, which means HellionChat's `ContentIdResolverHook` does
|
||
not fire and tell-partner identification breaks for AutoTellTab routing. The proper fix sits next
|
||
to the planned ad-block hook layer (`RaptureLogModule.ShowMiniTalkPlayer` and friends) where the
|
||
same patch surface comes up anyway.
|
||
- Internal: storage form of `messages.Id` clarified (declared BLOB but Microsoft.Data.Sqlite stores
|
||
Guid parameters as TEXT). FTS bulk insert and `LoadByGuids` join now match the TEXT storage form
|
||
on both sides. Migration v17 stays (no schema bump).
|
||
|
||
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
||
|
||
---
|
||
|
||
## Hellion Chat 1.4.7 — Backlog Cleanup and Mid-Features (2026-05-13)
|
||
|
||
Eighth sub-patch of the v1.4.x polish-sweep series. First user-visible feature bundle since v1.4.5 —
|
||
pinned tell tabs that survive relog, opt-in Honorific glow rendering, a configurable sidebar, plus a
|
||
Settings-Save channel-preservation fix surfaced during smoke testing.
|
||
|
||
- TempTell Pin: right-click a TempTell tab in the sidebar and choose "Pin Tab" / "Tab anpinnen".
|
||
Pinned tabs survive plugin reload and character logout, keep their conversation history (loaded on
|
||
demand from the message store on rehydrate), and stay bound to the same `/tell` partner. Hard cap
|
||
of 5 pinned tabs in a pool separate from the 15-tab auto-tell pool — total ceiling is 20 tabs. The
|
||
sidebar groups pinned tabs into their own section with a divider header
|
||
- Honorific glow outlines now render via an 8-direction DrawList pre-pass when the title carries a
|
||
Glow colour. Opt-in via **Settings → Integrations → Render glow outlines (Honorific)** (default
|
||
off). Honorific's gradient surface (`Color3`, `GradientColourSet`, `GradientAnimationStyle`) is
|
||
parsed and stashed for a later cycle but renders as the primary colour until then — the v1.4.7 DTO
|
||
already mirrors all four extra fields so the JSON roundtrip doesn't silent-drop them
|
||
- Sidebar width configurable in **Theme & Layout** (44–160 px, default 44 stays icon-only). The icon
|
||
button stretches with the configured width so a widened sidebar looks intentional, not a 36 px
|
||
icon floating in empty space
|
||
- `Configuration.UpdateFrom` now preserves the runtime `CurrentChannel` across the persistent-tab
|
||
merge alongside `Messages` and `LastSendUnread`. `TabSwitched` deep-clones the seeded channel from
|
||
the previous tab instead of sharing the same `UsedChannel` instance. Together these fix a
|
||
regression where Settings-Save on a Party or Linkshell tab popped the chat input back to
|
||
`/tell <pinned-partner>` on the next interaction
|
||
- `Util/ImGuiUtil.cs` `DrawArrows` IconButton id uses `(id + 1).ToString()` with explicit
|
||
parentheses instead of the operator-precedence quirk `id + 1.ToString()` (which resolved to
|
||
`id.ToString() + "1"`). Single live caller is `Ui/DbViewer.cs:227` page-navigation
|
||
- Internal: `IPluginLogProxy` indirection over Dalamud's `IPluginLog` routes all ~91 `Plugin.Log`
|
||
call sites through a testable proxy. `MessageStore.Migrate0` can now run in xUnit without loading
|
||
`Dalamud.dll`, closing the gap F12.1 left in v1.4.6. Production wrapper `DalamudPluginLogProxy`
|
||
and Build-Suite `FakePluginLogProxy` mirror the full `IPluginLog` surface
|
||
(`Verbose`/`Debug`/`Information`/`Info`/`Warning`/`Error`/`Fatal`) with single-string,
|
||
`Exception+string`, and `params object[]` overloads
|
||
- Internal: TempTab counter switched from an `Interlocked` cached field to a derived
|
||
`Tabs.Count(predicate)`. Pin-state transitions (TryPin / Unpin / Promote) are cold-path and don't
|
||
need lock-free reads; counter mutation surface dropped from 5 to 0 sites. Build-Suite floor 688 →
|
||
710 (+22)
|
||
- Schema bump v16 → v17 is additive: new `Tab.IsPinned` bool, default false. Existing v16 configs
|
||
load cleanly and get their `Version` stamp bumped after the gate check
|
||
|
||
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
||
|
||
---
|
||
|
||
## Hellion Chat 1.4.6 — Code Hygiene and Refactor (2026-05-12)
|
||
|
||
Maintenance patch. No user-visible behaviour changes; tightens the development feedback loop, fixes
|
||
two upstream-inherited bugs from ChatTwo `f35b7d3`, and prepares the code for the v1.4.7 backlog
|
||
cleanup.
|
||
|
||
- `scripts/preflight.sh` gains Block E (`dotnet csharpier check`) and Block F (`markdownlint-cli2`)
|
||
so reflow drift and markdown violations are caught at the pre-push gate. `.markdownlint.json` adds
|
||
`MD024 siblings_only` and disables `MD036` so the bilingual forge-post bold-emphasis headings pass
|
||
linting; the `.claude/` directory is excluded from the scan
|
||
- `FontManager.AddFontWithFallback` catch-filter now covers `InvalidOperationException` and
|
||
`ArgumentException` on top of the existing IO triad. The warning log carries the exception type
|
||
name, so the diagnostic path knows which class of atlas-toolkit throw triggered the
|
||
NotoSansCjkRegular fallback
|
||
- `BrandingLinks` (5 URLs) and `Integrations/IntegrationLinks` (2 URLs) validate themselves on first
|
||
module load via `[ModuleInitializer]` + a shared `UrlValidation.ValidateAll` helper. A malformed
|
||
URL now throws `InvalidOperationException` at plugin load with the source class and the broken URL
|
||
in the message
|
||
- Cherry-picked from ChatTwo upstream `f35b7d3`: `Chat.SetChannel` no longer leaks the native
|
||
`Utf8String` when the linkshell check rejects the channel. The validity check is now wrapped
|
||
around the `ChangeChatChannel` call instead of short-circuiting before `Dtor`. `ValidAnyLinkshell`
|
||
is renamed to `IsChannelOrExistingLinkshell` and the `ChatLogWindow` call-site follows the rename
|
||
- Cherry-picked from ChatTwo upstream `f35b7d3`: `Tab.Clone` now deep-clones `UsedChannel` and
|
||
`TellTarget`. The old `CurrentChannel = CurrentChannel` was a reference copy, so PopOut and Temp
|
||
tabs mutated each other's channel state (incl. tell target). `TellTarget.From(t)` static factory
|
||
is replaced with an instance `Clone()`; `UsedChannel.Clone()` is new and runs deep-clone on both
|
||
TellTarget references
|
||
- `ChatLogWindow` active-tab underline pill now scales with `ImGuiHelpers.GlobalScale` and rounds
|
||
its DrawList coordinates to physical pixels via `MathF.Round`, so the 2 px line stays crisp on 125
|
||
% and 150 % DPI setups instead of bleeding into a sub-pixel blur
|
||
- `ImGuiUtil.IconButton` width parameter no longer subtracts HUD-scaled `CellPadding.X * 2` from the
|
||
raw `int` width. `ImGui.Button` handles its own frame padding internally, so the measured
|
||
`buttonWidth` now passes through verbatim (inspired-by upstream `f35b7d3`, but our two call-sites
|
||
need the parameter, so the param itself stays)
|
||
- Internal: `HellionStyle` ChildBgAlpha threshold logic extracted to
|
||
`HellionStyleHelpers.ResolveChildBgAlpha` with a build-suite mirror test that pins the 0.999f
|
||
cutoff. `Plugin.SaveConfig` clones only the temp-tab subset in the pre-serialization snapshot
|
||
instead of the full tab list. `SettingsOverview` caches `ImGui.GetWindowDrawList()` once per frame
|
||
and passes the pointer down to `DrawCard`
|
||
- Internal: `Dalamud.Utility.Util` static surface (`IsWine`, `OpenLink`) routed through a new
|
||
`IPlatformUtil` indirection. `MessageStore`'s `IsWine` probe is now reachable from the xUnit
|
||
AppDomain via a `FakePlatformUtil` fixture (full isolated MessageStore construction still pending
|
||
— `Plugin.Log.Information` in `Migrate0` is a separate Dalamud-static surface, slated for v1.4.7)
|
||
- Built-in themes: Crystal Nocturne (royal sapphire and electric magenta over obsidian, by
|
||
CRYSTALLITE) replaces Moonlit Bloom in the built-in roster. Users who had Moonlit Bloom selected
|
||
fall back to the default Hellion Arctic on the first plugin load; an existing custom JSON copy of
|
||
Moonlit Bloom under `pluginConfigs/HellionChat/themes/` keeps working unchanged
|
||
|
||
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.4.5 — UX and Robustness (2026-05-12)
|
||
|
||
Sixth sub-patch of the v1.4.x polish-sweep series. User-visible robustness fixes plus two doc/test
|
||
polish items from the audit backlog. No schema bump, no migration.
|
||
|
||
- `ChatLogWindow.Draw` now surfaces a one-shot warning notification when the draw path throws. The
|
||
stack trace still goes to `/xllog` via `Plugin.Log.Error`; the notification is suppressed for the
|
||
rest of the plugin session so a recurring failure can't spam the notification stack
|
||
frame-by-frame. Pattern-match to the existing `Plugin.cs:505-516` migration-blocker notification
|
||
- `FirstRunWizard` splits accept from close. `OnClose` no longer silently sets `FirstRunCompleted`,
|
||
so closing the X leaves the wizard pending and it reopens on the next plugin load. A new footer
|
||
"Later — keep defaults" button is the explicit path to dismiss without picking a profile.
|
||
Bilingual strings (EN + DE) plus a tooltip
|
||
- `InputHistoryService.Reset` is wired into `Plugin.DisposeAsync` alongside the existing pure-memory
|
||
cleanups. Static state used to survive a plugin reload — the next load now starts with an empty
|
||
history
|
||
- `FontManager.GetHellionFontBytes` becomes `TryGetHellionFontBytes` with a nullable return. On miss
|
||
(broken csproj, hand-rolled dev build) the caller falls back to the system-font path that
|
||
`UseHellionFont=false` already uses, plus a `Plugin.Log.Warning`. The whole UiBuilder no longer
|
||
throws if the embedded font resource is absent
|
||
- `Plugin.cs:167-168` gets a 4-line reasoning comment around the session-only
|
||
`RemoveAll(IsTempTab)`: tells are usually privacy-filtered, resurrecting an empty crashed-session
|
||
tab would trigger DB reconstruction on the next load. `TempTabCounter.InitFromList` mirrors the
|
||
post-strip semantic in the Build-Suite with a pinning test
|
||
- `StatusBar.cs` drops the version slot when the chat window's content width minus the version text
|
||
is below 200 px. The right-aligned version used to clip into the four left-side slots in narrow
|
||
windows
|
||
|
||
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.4.4 — Threading and IPC Safety Polish (2026-05-12)
|
||
|
||
Fifth sub-patch of the v1.4.x polish-sweep series. Threading assumptions are documented per-method,
|
||
a hot-path lock falls away in `AutoTellTabsService`, IPC-cleanup failures become visible, and the
|
||
privacy filter now speaks up when an unknown ChatType shows up.
|
||
|
||
- `AutoTellTabsService.ActiveTempTabCount` switches from a lock-protected LINQ `Count` to an
|
||
`Interlocked` counter kept in sync with `Config.Tabs` from inside the existing mutation paths.
|
||
`Initialize()` seeds the counter from the persisted Tabs list, and `SaveConfig`'s snapshot-restore
|
||
path calls a new `ResyncTempTabCounter()` so the mid-step `RemoveAll` doesn't leave the counter
|
||
drifting. Pure-helper test mirror lives in the Build-Suite repo
|
||
- `HonorificService` per-method threading banners replace the block comment at the bottom of the
|
||
file. Each IPC callback (`TryInitialPull`, `OnTitleChanged`, `OnReady`, `OnDisposing`,
|
||
`TryUnsubscribe`) and the `CurrentTitle` field carry a one-line `// Thread:` annotation so the
|
||
framework-thread invariant is visible at the call site
|
||
- `TryUnsubscribe` log-level upgraded from `Debug` to `Warning`. A silent unsubscribe failure leaks
|
||
a live subscription across plugin reloads, which is exactly the kind of issue that should not be
|
||
at Debug
|
||
- `AutoTranslate.PreloadCache` thread now has `IsBackground = true` and a thread name. Without
|
||
`IsBackground` the warmup blocks plugin unload (typically 100-300 ms). Pattern-match to
|
||
`MessageManager` (F6.1) and `Plugin.RetentionSweep` (F9.3), both since v1.4.0
|
||
- `Configuration.IsAllowedForStorage` adds a one-line `Plugin.Log.Warning` for the first occurrence
|
||
of any ChatType that isn't in `PrivacyPersistChannels`. Dedup via a `NonSerialized`
|
||
`HashSet<ChatType>`, so the warning fires once per runtime — not once per frame, not once per
|
||
install. Failsafe routing through `PrivacyPersistUnknownChannels` is unchanged
|
||
- `PrivacyPersistUnknownChannels` field default flipped from `false` to `true` for new installs via
|
||
a constant in `PrivacyDefaults`. Existing configs keep their explicit choice — the deserializer
|
||
overrides the initializer. No schema bump, no migration, no first-run banner
|
||
|
||
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.4.3 — Plugin-Load Async-Init + Repo-Cutover (2026-05-08)
|
||
|
||
Plugin lifecycle migrated to Dalamud's `IAsyncDalamudPlugin` API. The constructor now does only the
|
||
bootstrap-essentials (config load, language init, conflict detection); migrations, service
|
||
allocations, window construction and hook subscription move to `LoadAsync`. Dalamud can keep its UI
|
||
responsive while the heavy work runs.
|
||
|
||
- `IAsyncDalamudPlugin` two-phase load with per-line `CaptureFailure` in `DisposeAsync` (mirrors
|
||
LightlessSync's pattern); idempotency guard protects against reload races
|
||
- Schema-gate replaces the v9 → v16 migration chain. Configs on schema v16+ load directly; older
|
||
configs trigger an "install v1.4.2 first" error so the historic migration path stays intact
|
||
- `AutoTranslate.PreloadCache` moved off the load path. First use may have a sub-second hitch
|
||
instead of every-load; the upstream chose differently, we accept first-use latency
|
||
- `FontManager.BuildFonts` is called sync at the start of `LoadAsync`; Dalamud rebuilds the font
|
||
atlas on its own pipeline so the custom Hellion-Exo2 font appears with a brief font-pop after load
|
||
(matches ChatTwo's behaviour)
|
||
- Custom-repo URL moved to `gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat`. GitHub repo
|
||
stays as a frozen v1.4.2 snapshot; new releases ship from Gitea. Existing testers need to update
|
||
the custom-repo URL once
|
||
- Plugin-load time in this release sits at ~3.7 s median (5 reloads), comparable to v1.4.2. Async
|
||
migration is foundational for v1.4.4 Lazy-Init optimisations rather than an immediate
|
||
user-perceived win
|
||
|
||
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.4.2 — ChatLog Frame-Hot-Path
|
||
|
||
Third sub-patch of the v1.4.x Polish Sweep series. Per-frame allocations from the chat-log render
|
||
path eliminated.
|
||
|
||
- `DrawMessages` card-mode hoists `theme`/`drawList`/`winLeft`/`winRight`/`borderColorAbgr` out of
|
||
the per-message loop. About 500 redundant calls per frame at 100 visible messages, multiplied by
|
||
every pop-out window
|
||
- Auto-tell tab tint and icon use a per-tab cache. Hash computation and string allocation only
|
||
happen when the tell target name or world drifts. `AutoTellTabTint` stays a pure hash helper;
|
||
cache lives in a thin `TabTintCache` wrapper
|
||
- Status bar gates its tab aggregation behind the same one-second cache it already used for the
|
||
format strings. LINQ `Sum` and `Count` replaced with a single `foreach` pass that runs on roughly
|
||
1 % of frames
|
||
|
||
Realistic frame-time recovery: 2-5 % in typical scenes, more on pop-out-heavy setups because the
|
||
card-border hoist scales per window.
|
||
|
||
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.4.1 — Theme Engine Performance
|
||
|
||
Second sub-patch of the v1.4.x Polish Sweep series. Heap pressure from the theme engine's per-frame
|
||
render path removed, plus a tenth built-in theme and hardening for the custom-theme hot-reload.
|
||
|
||
- Theme records carry a pre-computed ABGR-packed cache for every color slot; cache is filled when
|
||
the theme is registered and refreshed defensively on every `Switch()`
|
||
- `HellionStyle.PushGlobal` reads ABGR values from the cache instead of calling
|
||
`ColourUtil.RgbaToAbgr` per slot per frame; ~13 % render-time recovery measured in typical scenes
|
||
(plan estimate was 2–6 %, real ~10–15 %)
|
||
- `ThemeRegistry` custom-theme reload distinguishes a recoverable file lock (editor mid-save) from a
|
||
permanent IO failure; locked themes keep their last-known-good snapshot and retry on the next
|
||
lookup instead of dropping out of the picker
|
||
- New built-in: **Synthwave Sunset** — Hot Magenta + Cyan on midnight violet, 80s neon-grid vibes;
|
||
tenth theme in the picker
|
||
- Author credits refreshed: brand themes are credited as "Hellion Forge"; **Mint Grove** and **Forge
|
||
Merchantman** now credited to **Carla Beleandis** as a community thanks
|
||
|
||
No schema bump, no user-visible behaviour change other than smoother frames on GC-sensitive setups
|
||
and one additional colour option.
|
||
|
||
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.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
|
||
|
||
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 & support: join Hellion Forge — <https://discord.gg/X9V7Kcv5gR>
|
||
|
||
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
||
|
||
---
|
||
|
||
## v1.2.3 — Theme Expansion (2026-05-06)
|
||
|
||
### Added
|
||
|
||
- Four new built-in themes:
|
||
- **Night Blue** — Royal Blue on deep marine, cool tech-dashboard mood
|
||
- **Indigo Violet** — Royal Violet on deep indigo with a turquoise-mint counter (aurora glitter
|
||
feel)
|
||
- **Forge Merchantman** — Patina bronze on workshop slate with warm amber counter (Hellion Forge
|
||
identity)
|
||
- **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) preserved while
|
||
keeping every channel separable under red-green colour vision deficiency
|
||
- Built-in theme catalogue grown from five to nine
|
||
|
||
### Notes
|
||
|
||
- No engine changes, no settings touched, no migration
|
||
- Default theme unchanged (Hellion Arctic). Existing custom themes keep working.
|
||
- Hellion Spectrum covers the ~99 % of CVD cases that are red-green; a Tritan-safe variant could
|
||
follow in a later cycle if there is demand.
|
||
|
||
---
|
||
|
||
## v1.2.1 — Settings Cleanup (2026-05-06)
|
||
|
||
### Changed
|
||
|
||
- Settings cards re-sorted thematically: 9 cards remain, each card has one clear job and a one-line
|
||
subtitle.
|
||
- **Theme & Layout** (new) collects the theme picker, window frame style (title bar, sidebar, hide
|
||
button, pop-out title bar) and the timestamp style options.
|
||
- **Fonts & Colours** (new) houses font choice, font size and per-channel chat colours.
|
||
- **Data Management** (new) collects retention windows, cleanup, export, the database viewer and the
|
||
shift-click advanced tools.
|
||
- **Privacy** is now focused on the privacy filter alone.
|
||
- **Chat** absorbs the Auto-Tell-Tabs history-preload slider that used to live under Privacy.
|
||
- **General** groups the keybind mode under Input.
|
||
|
||
### Removed
|
||
|
||
- Legacy "Style override" option and the unused style-name field — both obsolete since the v1.1.0
|
||
themes engine.
|
||
- Legacy `WindowAlpha` slider — if you had it set, the value is auto-migrated to Theme & Layout →
|
||
Window Style → Window Transparency.
|
||
- Unused `ShowThemeQuickPicker` schema field.
|
||
|
||
### Migration
|
||
|
||
- v15 → v16 with backup at `pluginConfigs/HellionChat.json.pre-v16-backup`.
|
||
- All other settings preserved unchanged.
|
||
- One-time toast on first start if Style override was previously active.
|
||
|
||
---
|
||
|
||
## v1.2.0 — Layout Refresh (2026-05-05)
|
||
|
||
### Added
|
||
|
||
- Sidebar tab modernization: icon-only at fixed 44 px, tooltip on hover, vertical accent pill for
|
||
active tab
|
||
- Top tabs: accent underline pill replaces background fill on active tab
|
||
- Per-tab custom icons in Settings → Tabs (15-glyph FontAwesome picker)
|
||
- Bottom status bar (22 px): channel indicator, privacy badge, counters, tells, version — updates
|
||
1×/sec
|
||
- Card rows as default message render: sender header in channel color, subtle border between cards
|
||
- Compact-Density toggle in Appearance: switches back to single-line `[HH:mm] Sender: Text` layout
|
||
- Auto-Tell tabs: per-partner hashed icon (7-glyph pool:
|
||
envelope/star/heart/bell/bookmark/flag/fire) plus hashed color (12-color palette) — 84 distinct
|
||
icon+color combinations
|
||
- Unread indicator: pulsing red dot in the top-right corner of any sidebar tab icon with unread
|
||
messages, 2-second sine-wave pulse, respects `Configuration.ReduceMotion`
|
||
|
||
### Changed
|
||
|
||
- Migration v14 → v15: deprecated Configuration fields `HellionThemeEnabled` and
|
||
`HellionThemeWindowOpacity` removed
|
||
- Appearance settings cleaned: legacy theme-engine bindings replaced by Themes tab (introduced in
|
||
v1.1.0)
|
||
|
||
### Fixed
|
||
|
||
- Settings save no longer wipes chat history by default — the heavy
|
||
`ClearAllTabs + FilterAllTabsAsync` cycle now only runs when a filter-relevant setting actually
|
||
changed (Privacy filter, persisted channels, per-tab channel selection). Cosmetic changes keep the
|
||
in-session chat intact
|
||
- Identifier-based `MessageList` restore in `Configuration.UpdateFrom` plus TempTab skip in
|
||
`ClearAllTabs`/`FilterAllTabs` ensure persistent tabs and Auto-Tell tabs both survive the save
|
||
- Sidebar buttons now align vertically with the first message row (top padding mirrors the chat
|
||
header toolbar height)
|
||
- Sidebar child window no longer paints the top padding area with its frame background
|
||
- Status bar version slot (`vX.Y.Z · Hellion`) no longer clips its rightmost character
|
||
|
||
### Notes
|
||
|
||
- Polish phase (animations, theme crossfade, header quick-picker) follows in v1.3.0
|
||
- Top-Tab icon prefixes were considered but dropped: Dalamud's default font atlas does not include
|
||
FontAwesome codepoints, so mixed-font in a single TabItem label renders as tofu. Underline pill
|
||
alone is the v1.2.0 visual treatment for top tabs. Resolution would require Font-Atlas merge at
|
||
FontManager level — out of scope.
|
||
|
||
---
|
||
|
||
## [1.1.0] — 2026-05-05 — Theme Foundation
|
||
|
||
First major UI cycle after v1.0.0. Theme engine, five built-in themes, custom themes via JSON,
|
||
settings card grid.
|
||
|
||
### Added
|
||
|
||
- **Theme engine** with five built-in themes: Hellion Arctic (default), Chat 2 Classic, Event
|
||
Horizon, Moonlit Bloom, Mint Grove.
|
||
- **Settings → Themes** with mini mockup preview per theme. Clicking a card instantly switches the
|
||
entire plugin (chat, settings, pop-outs).
|
||
- **Custom themes via JSON** in `pluginConfigs/HellionChat/themes/`. On first start,
|
||
`example-theme.json` is placed there as a template.
|
||
- **Optional theme chat channel colours**: themes can ship their own channel colours. On switch, a
|
||
banner appears with _Apply / Keep current_ — never applied automatically.
|
||
- **Settings card grid**: new overview on open, clicking a card navigates into the section's detail
|
||
view. Breadcrumb + ESC navigate back.
|
||
- **`docs/THEME-AUTHORING.md`** as a guide for writing custom themes, with Hellion Forge branding.
|
||
|
||
### Changed
|
||
|
||
- **Plugin icon** updated to Hellion Forge hammer (previously a ChatTwo derivative).
|
||
- **Settings detail view** uses the full width — the second tab list on the left is gone because the
|
||
card overview handles navigation.
|
||
- **`HellionStyle.PushGlobal`** is now theme-driven (`PushGlobal(theme, opacity)`) instead of
|
||
const-palette-driven.
|
||
- **Configuration v13 → v14**: all users land on `hellion-arctic`. Those who prefer the upstream
|
||
look can select `chat2-classic` in Settings → Themes.
|
||
|
||
### Deprecated
|
||
|
||
- `Configuration.HellionThemeEnabled` and `HellionThemeWindowOpacity` remain readable for one
|
||
release as a safety net but are no longer evaluated. Removal planned for v1.2.0.
|
||
|
||
### Security
|
||
|
||
- Custom theme JSON loader validates `schemaVersion`, required fields and hex format. Invalid themes
|
||
are skipped with a warning; the plugin continues loading with built-ins.
|
||
|
||
### Internal
|
||
|
||
- 51 local unit tests (theme records, registry, JSON round-trip, sanity per built-in theme). Tests
|
||
are gitignored.
|
||
|
||
---
|
||
|
||
## [1.0.3] — 2026-05-04 — Polish Patch
|
||
|
||
Four small polish items from the backlog bundled together:
|
||
|
||
- **Hide on New Game+ menu**: optional global toggle that hides Hellion Chat (and all other plugin
|
||
windows such as Settings, DB Viewer, pop-outs) while the NG+ menu is open. Settings → Window →
|
||
Frame, default off. Skips the entire `WindowSystem.Draw()` path analogous to the existing
|
||
LoadingScreens pattern.
|
||
- **Channel selector colouring**: optional tinting of the channel-select button (comment icon) next
|
||
to the input field in the current channel colour. Settings → Appearance → Chat Colours, default
|
||
on. Consistent with the existing input text colouring; ExtraChat override is carried over.
|
||
- **(De)buff icon aspect-ratio fix**: `PayloadHandler.InlineIcon` was squashing all hover icons to
|
||
32×32. Status icons with non-square dimensions (debuffs with an arrow indicator) are now shrunk
|
||
aspect-preserving. Standalone float-math implementation with zero-size guard instead of a
|
||
cherry-pick from the open ChatTwo PR #157 (which had an int-division trap).
|
||
- **HideState logging sweep**: all HideState transitions (Battle/Cutscene/User/Override plus pop-out
|
||
mirroring) log at verbose level. Off by default; enable via `/xllog set HellionChat verbose` for
|
||
bug-report diagnostics.
|
||
|
||
[Release Notes 1.0.3](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/tag/v1.0.3)
|
||
|
||
---
|
||
|
||
## [1.0.1] — 2026-05-04 — Window Position Recovery
|
||
|
||
Fixes an off-screen-window scenario the user could end up in after a monitor disconnect or display
|
||
layout change between sessions. An automatic one-shot bounds check on the first draw after plugin
|
||
load snaps the window back into the visible viewport, and a new "Reset Window Position" button in
|
||
Settings → Window → Frame serves as the manual escape hatch for edge cases.
|
||
|
||
Bundled housekeeping since v1.0.0: documentation restructured into `docs/`, stale ChatTwo/\* paths
|
||
in repo configs cleaned up, Pidgin parser library bumped from 3.3.0 to 3.5.1, GitHub Actions bumps
|
||
for `actions/setup-dotnet` (4 → 5) and `github/codeql-action` (3 → 4).
|
||
|
||
[Release Notes 1.0.1](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/tag/v1.0.1)
|
||
|
||
---
|
||
|
||
## [1.0.0] — 2026-05-03 — Standalone Major Release
|
||
|
||
First fully independent release. Code namespace, IPC channels and source tree structure consolidated
|
||
under `HellionChat.*`. Plugin refuses to start alongside an active upstream Chat 2 (bilingual
|
||
conflict message). SQLite native pinned to 3.50.3 (CVE-2025-6965, CVE-2025-7709). Tab layout default
|
||
for new installs and users on config version 12 or older restructured (5 thematic tabs instead of 6+
|
||
kitchen-sink). Sweep of critical and major findings from the codebase audit incorporated.
|
||
|
||
[Release Notes 1.0.0](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/tag/v1.0.0)
|
||
|
||
---
|
||
|
||
## [0.6.1] — 2026-05-03 — Pop-Out Discoverability & /tell Auto-Pop-Out
|
||
|
||
Pop-out button visible in the chat header, one-time hint banner for the pop-out feature. New setting
|
||
"Open new /tell tabs directly as pop-out". Pop-out input is now active by default. Bug fixes: ghost
|
||
windows on LRU-drop / logout, dead zone below the input bar when the hint banner is active.
|
||
|
||
[Release Notes 0.6.1](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/tag/v0.6.1)
|
||
|
||
---
|
||
|
||
## [0.6.0] — 2026-05-03 — UX Polish: Pop-Out Input + Colour Presets
|
||
|
||
Two opt-in UX features. Pop-out windows optionally get a compact input bar with a channel-coloured
|
||
icon button and an independent text buffer per pop-out. Seven built-in colour presets (Classic, High
|
||
Contrast, Pastel, Dark Mode Tuned, Hellion, Night Blue, Indigo Violet) for one-click apply.
|
||
Configuration migration v10 → v11.
|
||
|
||
[Release Notes 0.6.0](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/tag/v0.6.0)
|
||
|
||
---
|
||
|
||
## [0.5.4] — 2026-05-02 — WrapText Hardening
|
||
|
||
`ImGuiUtil.WrapText` rewritten from pointer arithmetic to Span- and index-based control flow.
|
||
Permanently closes the recurring CodeQL critical alert "unvalidated local pointer arithmetic". No
|
||
user-visible behaviour change — word-wrap output is byte-identical to 0.5.3.
|
||
|
||
[Release Notes 0.5.4](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/tag/v0.5.4)
|
||
|
||
---
|
||
|
||
## [0.5.3] — 2026-05-02 — Pointer Arithmetic Hardening
|
||
|
||
First attempt at closing the CodeQL critical alert in `ImGuiUtil.WrapText`. Encoded byte buffer
|
||
length is validated via `GetByteCount` before pointer arithmetic.
|
||
|
||
[Release Notes 0.5.3](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/tag/v0.5.3)
|
||
|
||
---
|
||
|
||
## Earlier Versions
|
||
|
||
Releases before 0.5.3 (bootstrap phase 0.1.0 to 0.5.2) are available directly on the Gitea release
|
||
stream:
|
||
|
||
[All Releases](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases)
|
||
|
||
---
|
||
|
||
## Maintenance Note
|
||
|
||
The source of truth for the user-facing changelog is the `changelog:` block in
|
||
`HellionChat/HellionChat.yaml`. `repo.json` and the GitHub release body are fed from there. This
|
||
file (`docs/CHANGELOG.md`) is a curated summary with links to the release pages and is updated
|
||
manually on each version bump.
|