chore(release): prepare v1.0.2 — polish patch

Four small backlog items bundled:

- New: hide chat (and every other plugin window) while the New Game+
  menu is open. Settings -> Window -> Frame, default off. Skips the
  whole WindowSystem.Draw() pass while QuestRedo is visible, mirroring
  the existing HideInLoadingScreens pattern.
- New: tint the channel selector button in the active channel colour.
  Settings -> Appearance -> Colours, default on. Reuses the existing
  inputColour computation (incl. ExtraChat override) and adds an
  ImGuiCol.Button push around the selector. New ColourUtil helper
  AdjustBrightness derives hover/active variants.
- Fix: PayloadHandler.InlineIcon hardcoded all hover icons to 32x32.
  Replaced with float-based aspect-ratio-preserving shrink, single
  scale-factor, zero-size guard, named MaxInlineIconSize constant.
  Affects six call sites (status, item, achievement and other inline
  hover paths).
- Diagnostic: HideState transitions log on Verbose level for both
  ChatLogWindow and Popout.

Manifest bumped to 1.0.2 across csproj, yaml, repo.json. CHANGELOG
entry added, README version line updated. yaml + repo.json changelog
trimmed to the slim 4-version window (1.0.2, 1.0.1, 1.0.0, 0.6.1).
This commit is contained in:
2026-05-04 15:57:52 +02:00
parent fcb72e2b78
commit 8e9332ac8c
17 changed files with 230 additions and 99 deletions
+4
View File
@@ -145,6 +145,7 @@ public class Configuration : IPluginConfiguration
public bool HideWhenUiHidden = true;
public bool HideInLoadingScreens;
public bool HideInBattle;
public bool HideInNewGamePlusMenu;
public bool HideWhenInactive;
public int InactivityHideTimeout = 10;
public bool InactivityHideActiveDuringBattle = true;
@@ -221,6 +222,7 @@ public class Configuration : IPluginConfiguration
public float TooltipOffset;
public float WindowAlpha = 100f;
public Dictionary<ChatType, uint> ChatColours = new();
public bool ColorSelectedInputChannelButton = true;
public List<Tab> Tabs = [];
public bool OverrideStyle;
@@ -241,6 +243,7 @@ public class Configuration : IPluginConfiguration
HideWhenUiHidden = other.HideWhenUiHidden;
HideInLoadingScreens = other.HideInLoadingScreens;
HideInBattle = other.HideInBattle;
HideInNewGamePlusMenu = other.HideInNewGamePlusMenu;
HideWhenInactive = other.HideWhenInactive;
InactivityHideTimeout = other.InactivityHideTimeout;
InactivityHideActiveDuringBattle = other.InactivityHideActiveDuringBattle;
@@ -288,6 +291,7 @@ public class Configuration : IPluginConfiguration
TooltipOffset = other.TooltipOffset;
WindowAlpha = other.WindowAlpha;
ChatColours = other.ChatColours.ToDictionary(entry => entry.Key, entry => entry.Value);
ColorSelectedInputChannelButton = other.ColorSelectedInputChannelButton;
// Hellion Chat — Auto-Tell-Tabs are session-only and therefore
// never present in a disk-loaded copy. Keep the live temp tabs of
@@ -20,6 +20,8 @@ namespace HellionChat.GameFunctions;
internal unsafe class GameFunctions : IDisposable
{
internal const string NewGamePlusAddonName = "QuestRedo";
#region Hooks
[Signature("E8 ?? ?? ?? ?? 48 85 C0 0F 84 ?? ?? ?? ?? 48 8B D0 49 8D 4F", DetourName = nameof(ResolveTextCommandPlaceholderDetour))]
private Hook<ResolveTextCommandPlaceholderDelegate>? ResolveTextCommandPlaceholderHook = null!;
+1 -1
View File
@@ -4,7 +4,7 @@
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
derives from. -->
<Version>1.0.1</Version>
<Version>1.0.2</Version>
<ImplicitUsings>enable</ImplicitUsings>
<!-- Honor packages.lock.json on restore so floating version ranges
don't silently drift between machines or CI runs. -->
+18 -70
View File
@@ -49,6 +49,24 @@ tags:
- Replacement
- Privacy
changelog: |-
**Hellion Chat 1.0.2 — Polish patch**
- New: optionally hide chat (and every other plugin window) while the
New Game+ menu is open. Toggle in Settings → Window → Frame, default
off. Closing the menu restores all windows.
- New: optionally tint the channel selector button next to the input
field with the currently active channel's colour. Toggle in
Settings → Appearance → Colours, default on. Matches the existing
input-text tint and respects ExtraChat overrides.
- Fix: status, item and other inline hover icons keep their original
aspect ratio. Debuff icons with non-square dimensions are no longer
visually squished into a 32×32 box.
- Diagnostic: hide-state transitions (battle, cutscene, user-hide,
cutscene override) are now logged on Verbose level for easier bug
reports — off by default, enable with `/xllog set HellionChat verbose`.
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
**Hellion Chat 1.0.1 — Window Position Recovery**
- Automatic bounds check on the first draw after plugin load.
@@ -214,76 +232,6 @@ changelog: |-
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
**Hellion Chat 0.6.0 — UX Polish: Pop-Out Input + Colour Presets**
Two opt-in UX features land in the same release. Existing users see
no change unless they enable the new toggles.
Pop-out input bar:
- New global master switch in Settings → Window → Frame: "Enable input
in pop-outs". Default OFF so existing behaviour is preserved
- When enabled, every pop-out window grows a compact input bar at the
bottom (channel-coloured icon button left, text input right). The
auto-translate picker is intentionally not part of the compact bar
in v0.6.0 — typical pop-out workflows (FC greeter, club hostess)
rarely need it there
- Each pop-out keeps an independent text buffer and history cursor;
channel changes still apply globally because that is how the FFXIV
channel API works
- Up/Down navigates a shared input history singleton across the main
window and every open pop-out
- First pop-out opening after the upgrade shows a one-time hint
banner pointing users to the new toggle
Chat colour presets:
- Seven built-in presets above the per-channel colour list in
Settings → Appearance → Colours: ChatTwo Default, High-Contrast,
Pastell, Dark-Mode-Tuned, Hellion (brand-coloured, blue/orange
Arctic Cyan + Ember Glow palette from the Hellion Online Media
branding spec), plus two bonus mood presets — Night Blue (royal
blue, classic-cool) and Indigo Violet (royal violet, glitter-mystic)
- Apply is immediate and overwrites the channels covered by the
preset; battle-channel colours are left alone so combat tuning
stays intact
Configuration migrates from v10 to v11 with a diagnostic log entry;
no data is reset. Bilingual (English/German) for both new sections.
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
**Hellion Chat 0.5.4 — WrapText hardening**
Replaces the unsafe pointer-arithmetic in ImGuiUtil.WrapText with
Span- and index-based control flow. Closes the persistent CodeQL
Critical alert "unvalidated local pointer arithmetic" that kept
re-firing on every shape of the previous fix.
Hardening:
- WrapText now allocates a buffer sized by Encoding.UTF8.GetMaxByteCount
via ArrayPool, validates the actual encoded length against that
ceiling, and threads the rest of the algorithm through int offsets
instead of raw byte pointers
- Pointer arithmetic only happens inside two small private helpers
(CalcWordWrap and DrawText) that take the pinned base pointer plus
int offsets sourced from the plugin's own logic, not from any
virtual-method return
- Added a 16 KiB upper bound on the buffer rent to prevent a
pathological input from triggering an unbounded ArrayPool allocation
No user-visible behaviour change. Word-wrap output is byte-identical
to v0.5.3.
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
**Hellion Chat 0.5.3 — Pointer arithmetic hardening**
Closed CodeQL Critical alert in ImGuiUtil.WrapText by validating the
encoded byte buffer length via GetByteCount before pointer
arithmetic. Single-fix patch on top of v0.5.2.
---
Earlier history: https://github.com/JonKazama-Hellion/HellionChat/releases
+10 -1
View File
@@ -332,10 +332,19 @@ public sealed class PayloadHandler
atkBase->SetPosition((short) x, (short) y);
}
private const float MaxInlineIconSize = 32f;
private static void InlineIcon(IDalamudTextureWrap icon)
{
if (icon.Size.X <= 0 || icon.Size.Y <= 0)
return;
var width = (float) icon.Size.X;
var height = (float) icon.Size.Y;
var scale = Math.Min(1f, Math.Min(MaxInlineIconSize / width, MaxInlineIconSize / height));
var size = ImGuiHelpers.ScaledVector2(width * scale, height * scale);
var cursor = ImGui.GetCursorPos();
var size = ImGuiHelpers.ScaledVector2(32, 32);
ImGui.Image(icon.Handle, size);
ImGui.SameLine();
ImGui.SetCursorPos(cursor + new Vector2(size.X + 4, size.Y - ImGui.GetTextLineHeightWithSpacing()));
+10
View File
@@ -571,6 +571,16 @@ public sealed class Plugin : IDalamudPlugin
return;
}
// v1.0.2 — global skip while the New Game+ menu (QuestRedo addon) is
// open. Hides every plugin window in one shot (chat log, pop-outs,
// settings, db viewer, etc.), matching the LoadingScreens pattern.
if (Config.HideInNewGamePlusMenu && GameFunctions.GameFunctions.IsAddonInteractable(GameFunctions.GameFunctions.NewGamePlusAddonName))
{
ChatLogWindow.FinalizeFrame();
TypingIpc.Update();
return;
}
ChatLogWindow.HideStateCheck();
Interface.UiBuilder.DisableUserUiHide = !Config.HideWhenUiHidden;
+37 -1
View File
@@ -2148,6 +2148,24 @@ namespace HellionChat.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to The channel selector button next to the input field is tinted with the currently active channel's colour. Matches the tinting of the input text itself..
/// </summary>
internal static string Options_ColorSelectedInputChannelButton_Description {
get {
return ResourceManager.GetString("Options_ColorSelectedInputChannelButton_Description", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Tint channel selector with channel colour.
/// </summary>
internal static string Options_ColorSelectedInputChannelButton_Name {
get {
return ResourceManager.GetString("Options_ColorSelectedInputChannelButton_Name", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Chat colours.
/// </summary>
@@ -2660,7 +2678,25 @@ namespace HellionChat.Resources {
return ResourceManager.GetString("Options_HideInBattle_Name", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Hide the chat while the New Game+ menu is open. Closing the menu shows the chat again..
/// </summary>
internal static string Options_HideInNewGamePlusMenu_Description {
get {
return ResourceManager.GetString("Options_HideInNewGamePlusMenu_Description", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Hide while New Game+ menu is open.
/// </summary>
internal static string Options_HideInNewGamePlusMenu_Name {
get {
return ResourceManager.GetString("Options_HideInNewGamePlusMenu_Name", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Hide {0} during loading screens..
/// </summary>
+12
View File
@@ -208,6 +208,12 @@
<data name="Options_ChatColours_Import">
<value>Vom Spiel importieren</value>
</data>
<data name="Options_ColorSelectedInputChannelButton_Name" xml:space="preserve">
<value>Channel-Auswahl-Knopf in Channel-Farbe</value>
</data>
<data name="Options_ColorSelectedInputChannelButton_Description" xml:space="preserve">
<value>Der Channel-Auswahl-Knopf neben dem Eingabefeld bekommt die Farbe des aktuell aktiven Channels. Konsistent zur Färbung des Eingabetextes selbst.</value>
</data>
<data name="Options_Tabs_Tab">
<value>Kanäle</value>
</data>
@@ -1190,6 +1196,12 @@ Sie wurden gewarnt.</value>
<data name="Options_HideInBattle_Description" xml:space="preserve">
<value>Blende den Chat während der Kämpfe aus.</value>
</data>
<data name="Options_HideInNewGamePlusMenu_Name" xml:space="preserve">
<value>Während des New-Game+ Menüs ausblenden</value>
</data>
<data name="Options_HideInNewGamePlusMenu_Description" xml:space="preserve">
<value>Blendet den Chat aus, solange das New-Game+ Menü geöffnet ist. Schließen des Menüs blendet den Chat wieder ein.</value>
</data>
<data name="Options_Emote_EmoteStats" xml:space="preserve">
<value>Emote-Statistik</value>
</data>
+12
View File
@@ -208,6 +208,12 @@
<data name="Options_ChatColours_Import">
<value>Import from game</value>
</data>
<data name="Options_ColorSelectedInputChannelButton_Name" xml:space="preserve">
<value>Tint channel selector with channel colour</value>
</data>
<data name="Options_ColorSelectedInputChannelButton_Description" xml:space="preserve">
<value>The channel selector button next to the input field is tinted with the currently active channel's colour. Matches the tinting of the input text itself.</value>
</data>
<data name="Options_Tabs_Tab">
<value>Tabs</value>
</data>
@@ -1189,6 +1195,12 @@
<data name="Options_HideInBattle_Description" xml:space="preserve">
<value>Hide the chat during battles.</value>
</data>
<data name="Options_HideInNewGamePlusMenu_Name" xml:space="preserve">
<value>Hide while New Game+ menu is open</value>
</data>
<data name="Options_HideInNewGamePlusMenu_Description" xml:space="preserve">
<value>Hide the chat while the New Game+ menu is open. Closing the menu shows the chat again.</value>
</data>
<data name="Options_Emote_EmoteStats" xml:space="preserve">
<value>Emote Stats</value>
</data>
+54 -22
View File
@@ -278,9 +278,11 @@ public sealed class ChatLogWindow : Window
{
case "hide":
CurrentHideState = HideState.User;
Plugin.Log.Verbose("HideState: → User (chat hide command)");
break;
case "show":
CurrentHideState = HideState.None;
Plugin.Log.Verbose("HideState: → None (chat show command)");
break;
case "toggle":
CurrentHideState = CurrentHideState switch
@@ -290,6 +292,7 @@ public sealed class ChatLogWindow : Window
HideState.None => HideState.User,
_ => CurrentHideState,
};
Plugin.Log.Verbose($"HideState: → {CurrentHideState} (chat toggle command)");
break;
}
}
@@ -406,30 +409,48 @@ public sealed class ChatLogWindow : Window
{
// if the chat has no hide state set, and the player has entered battle, we hide chat if they have configured it
if (Plugin.Config.HideInBattle && CurrentHideState == HideState.None && Plugin.InBattle)
{
CurrentHideState = HideState.Battle;
Plugin.Log.Verbose("HideState: None → Battle");
}
// If the chat is hidden because of battle, we reset it here
if (CurrentHideState is HideState.Battle && !Plugin.InBattle)
{
CurrentHideState = HideState.None;
Plugin.Log.Verbose("HideState: Battle → None");
}
// if the chat has no hide state and in a cutscene, set the hide state to cutscene
if (Plugin.Config.HideDuringCutscenes && CurrentHideState == HideState.None && (Plugin.CutsceneActive || Plugin.GposeActive))
{
if (Plugin.Functions.Chat.CheckHideFlags())
{
CurrentHideState = HideState.Cutscene;
Plugin.Log.Verbose("HideState: None → Cutscene");
}
}
// if the chat is hidden because of a cutscene and no longer in a cutscene, set the hide state to none
if (CurrentHideState is HideState.Cutscene or HideState.CutsceneOverride && !Plugin.CutsceneActive && !Plugin.GposeActive)
{
Plugin.Log.Verbose($"HideState: {CurrentHideState} → None (cutscene/gpose ended)");
CurrentHideState = HideState.None;
}
// if the chat is hidden because of a cutscene and the chat has been activated, show chat
if (CurrentHideState == HideState.Cutscene && Activate)
{
CurrentHideState = HideState.CutsceneOverride;
Plugin.Log.Verbose("HideState: Cutscene → CutsceneOverride (user activate)");
}
// if the user hid the chat and is now activating chat, reset the hide state
if (CurrentHideState == HideState.User && Activate)
{
CurrentHideState = HideState.None;
Plugin.Log.Verbose("HideState: User → None (activate)");
}
if (CurrentHideState is HideState.Cutscene or HideState.User or HideState.Battle || (Plugin.Config.HideWhenNotLoggedIn && !Plugin.ClientState.IsLoggedIn))
{
@@ -600,9 +621,40 @@ public sealed class ChatLogWindow : Window
DrawChannelName(activeTab);
}
// v1.0.2 — compute inputColour up front so the channel selector button
// can also tint with it (existing input-text push remains below).
var inputType = activeTab.CurrentChannel.UseTempChannel ? activeTab.CurrentChannel.TempChannel.ToChatType() : activeTab.CurrentChannel.Channel.ToChatType();
var isCommand = Chat.Trim().StartsWith('/');
if (isCommand)
{
var command = Chat.Split(' ')[0];
if (TextCommandChannels.TryGetValue(command, out var channel))
inputType = channel;
if (!IsValidCommand(command))
inputType = ChatType.Error;
}
var inputColour = Plugin.Config.ChatColours.TryGetValue(inputType, out var inputCol) ? inputCol : inputType.DefaultColor();
if (!isCommand && Plugin.ExtraChat.ChannelOverride is var (_, overrideColour))
inputColour = overrideColour;
if (isCommand && Plugin.ExtraChat.ChannelCommandColours.TryGetValue(Chat.Split(' ')[0], out var ecColour))
inputColour = ecColour;
var beforeIcon = ImGui.GetCursorPos();
if (ImGuiUtil.IconButton(FontAwesomeIcon.Comment) && activeTab.Channel is null)
ImGui.OpenPopup(ChatChannelPicker);
var tintSelector = Plugin.Config.ColorSelectedInputChannelButton && inputColour.HasValue;
var selectorAbgr = tintSelector ? ColourUtil.RgbaToAbgr(inputColour!.Value) : 0u;
using (ImRaii.PushColor(ImGuiCol.Button, selectorAbgr, tintSelector))
using (ImRaii.PushColor(ImGuiCol.ButtonHovered, ColourUtil.AdjustBrightness(selectorAbgr, 1.15f), tintSelector))
using (ImRaii.PushColor(ImGuiCol.ButtonActive, ColourUtil.AdjustBrightness(selectorAbgr, 0.85f), tintSelector))
{
if (ImGuiUtil.IconButton(FontAwesomeIcon.Comment) && activeTab.Channel is null)
ImGui.OpenPopup(ChatChannelPicker);
}
if (activeTab.Channel is not null && ImGui.IsItemHovered())
ImGuiUtil.Tooltip(Language.ChatLog_SwitcherDisabled);
@@ -626,27 +678,7 @@ public sealed class ChatLogWindow : Window
var buttonsRight = (showNovice ? 1 : 0) + (Plugin.Config.ShowHideButton ? 1 : 0);
var inputWidth = ImGui.GetContentRegionAvail().X - buttonWidth * (1 + buttonsRight);
var inputType = activeTab.CurrentChannel.UseTempChannel ? activeTab.CurrentChannel.TempChannel.ToChatType() : activeTab.CurrentChannel.Channel.ToChatType();
var isCommand = Chat.Trim().StartsWith('/');
if (isCommand)
{
var command = Chat.Split(' ')[0];
if (TextCommandChannels.TryGetValue(command, out var channel))
inputType = channel;
if (!IsValidCommand(command))
inputType = ChatType.Error;
}
var normalColor = ImGui.GetColorU32(ImGuiCol.Text);
var inputColour = Plugin.Config.ChatColours.TryGetValue(inputType, out var inputCol) ? inputCol : inputType.DefaultColor();
if (!isCommand && Plugin.ExtraChat.ChannelOverride is var (_, overrideColour))
inputColour = overrideColour;
if (isCommand && Plugin.ExtraChat.ChannelCommandColours.TryGetValue(Chat.Split(' ')[0], out var ecColour))
inputColour = ecColour;
var push = inputColour != null;
using (ImRaii.PushColor(ImGuiCol.Text, push ? ColourUtil.RgbaToAbgr(inputColour!.Value) : 0, push))
{
+18
View File
@@ -229,30 +229,48 @@ internal class Popout : Window
{
// if the chat has no hide state set, and the player has entered battle, we hide chat if they have configured it
if (Tab.HideInBattle && CurrentHideState == HideState.None && Plugin.InBattle)
{
CurrentHideState = HideState.Battle;
Plugin.Log.Verbose($"Popout HideState [{Tab.Name}]: None → Battle");
}
// If the chat is hidden because of battle, we reset it here
if (CurrentHideState is HideState.Battle && !Plugin.InBattle)
{
CurrentHideState = HideState.None;
Plugin.Log.Verbose($"Popout HideState [{Tab.Name}]: Battle → None");
}
// if the chat has no hide state and in a cutscene, set the hide state to cutscene
if (Tab.HideDuringCutscenes && CurrentHideState == HideState.None && (Plugin.CutsceneActive || Plugin.GposeActive))
{
if (ChatLogWindow.Plugin.Functions.Chat.CheckHideFlags())
{
CurrentHideState = HideState.Cutscene;
Plugin.Log.Verbose($"Popout HideState [{Tab.Name}]: None → Cutscene");
}
}
// if the chat is hidden because of a cutscene and no longer in a cutscene, set the hide state to none
if (CurrentHideState is HideState.Cutscene or HideState.CutsceneOverride && !Plugin.CutsceneActive && !Plugin.GposeActive)
{
Plugin.Log.Verbose($"Popout HideState [{Tab.Name}]: {CurrentHideState} → None (cutscene/gpose ended)");
CurrentHideState = HideState.None;
}
// if the chat is hidden because of a cutscene and the chat has been activated, show chat
if (CurrentHideState == HideState.Cutscene && ChatLogWindow.Activate)
{
CurrentHideState = HideState.CutsceneOverride;
Plugin.Log.Verbose($"Popout HideState [{Tab.Name}]: Cutscene → CutsceneOverride (user activate)");
}
// if the user hid the chat and is now activating chat, reset the hide state
if (CurrentHideState == HideState.User && ChatLogWindow.Activate)
{
CurrentHideState = HideState.None;
Plugin.Log.Verbose($"Popout HideState [{Tab.Name}]: User → None (activate)");
}
return CurrentHideState is HideState.Cutscene or HideState.User or HideState.Battle || (Tab.HideWhenNotLoggedIn && !Plugin.ClientState.IsLoggedIn);
}
@@ -236,6 +236,10 @@ internal sealed class Appearance : ISettingsTab
ImGui.Separator();
ImGui.Spacing();
ImGui.Checkbox(Language.Options_ColorSelectedInputChannelButton_Name, ref Mutable.ColorSelectedInputChannelButton);
ImGuiUtil.HelpMarker(Language.Options_ColorSelectedInputChannelButton_Description);
ImGui.Spacing();
foreach (var (_, types) in ChatTypeExt.SortOrder)
{
foreach (var type in types)
+3
View File
@@ -56,6 +56,9 @@ internal sealed class Window : ISettingsTab
ImGui.Checkbox(Language.Options_HideInBattle_Name, ref Mutable.HideInBattle);
ImGuiUtil.HelpMarker(Language.Options_HideInBattle_Description);
ImGui.Checkbox(Language.Options_HideInNewGamePlusMenu_Name, ref Mutable.HideInNewGamePlusMenu);
ImGuiUtil.HelpMarker(Language.Options_HideInNewGamePlusMenu_Description);
}
}
+14
View File
@@ -48,4 +48,18 @@ internal static class ColourUtil {
internal static uint ComponentsToRgba(byte red, byte green, byte blue, byte alpha = 0xFF)
=> alpha | (uint) (red << 24) | (uint) (green << 16) | (uint) (blue << 8);
internal static uint AdjustBrightness(uint abgr, float factor)
{
var a = (byte) ((abgr & 0xFF000000) >> 24);
var b = (byte) ((abgr & 0x00FF0000) >> 16);
var g = (byte) ((abgr & 0x0000FF00) >> 8);
var r = (byte) (abgr & 0x000000FF);
var nr = (byte) Math.Clamp(r * factor, 0f, 255f);
var ng = (byte) Math.Clamp(g * factor, 0f, 255f);
var nb = (byte) Math.Clamp(b * factor, 0f, 255f);
return ((uint) a << 24) | ((uint) nb << 16) | ((uint) ng << 8) | nr;
}
}
+1 -1
View File
@@ -8,7 +8,7 @@
[![.NET](https://img.shields.io/badge/.NET-10.0-512BD4)](https://dotnet.microsoft.com/)
[![FFXIV](https://img.shields.io/badge/FFXIV-Dawntrail-c3a37f)](https://www.finalfantasyxiv.com/)
**Version 1.0.0** — DSGVO-bewusster Chat-Ersatz für FINAL FANTASY XIV / Dalamud, basierend auf [Chat 2](https://github.com/Infiziert90/ChatTwo) (EUPL-1.2).
**Version 1.0.2** — DSGVO-bewusster Chat-Ersatz für FINAL FANTASY XIV / Dalamud, basierend auf [Chat 2](https://github.com/Infiziert90/ChatTwo) (EUPL-1.2).
Hellion Chat ergänzt das ursprüngliche Chat-2-Fundament um Datenschutz- und Daten-Handling-Kontrollen, die mit den Datenschutz-Regeln in der EU, den USA und Japan im Einklang sind. Alle aus Chat 2 übernommenen Funktionen, Befehle und Tastenkürzel funktionieren unverändert. Eigenständiger Plugin-Slot, eigene Konfiguration, eigene Datenbank.
+27
View File
@@ -12,6 +12,33 @@ und verlinkt für Details auf die Release-Pages.
---
## [1.0.2] — 2026-05-04 — Polish patch
Vier kleine Polish-Items aus dem Backlog gebündelt:
- **Hide bei New Game+ Menü**: Optionaler globaler Toggle der Hellion
Chat (und alle weiteren Plugin-Fenster wie Settings, DB-Viewer,
Pop-Outs) ausblendet, solange das NG+-Menü offen ist. Settings →
Fenster → Rahmen, Default aus. Skipt analog zum bestehenden
LoadingScreens-Pattern den gesamten `WindowSystem.Draw()`-Pfad.
- **Channel-Selector-Färbung**: Optionales Tinting des
Channel-Auswahl-Knopfs (Comment-Icon) neben dem Eingabefeld in der
aktuellen Channel-Farbe. Settings → Aussehen → Chat-Farben, Default
an. Konsistent zur bestehenden Eingabetext-Färbung, ExtraChat-Override
wird übernommen.
- **(De)Buff-Icon Aspect-Ratio-Fix**: `PayloadHandler.InlineIcon` quetschte
alle Hover-Icons auf 32×32. Status-Icons mit nicht-quadratischen
Dimensionen (Debuffs mit Pfeil-Indikator) sind jetzt aspekt-erhaltend
geshrinkt. Eigenständige Float-Math-Implementierung mit Zero-Size-Guard
statt Cherry-Pick aus dem offenen ChatTwo PR #157 (der hatte eine
int-Division-Falle).
- **HideState-Logging-Sweep**: Alle HideState-Transitions
(Battle/Cutscene/User/Override plus die Pop-Out-Spiegelung) loggen sich
auf Verbose-Level. Aus by default, Aktivierung via
`/xllog set HellionChat verbose` für Bug-Report-Diagnose.
[Release-Notes 1.0.2](https://github.com/JonKazama-Hellion/HellionChat/releases/tag/v1.0.2)
## [1.0.1] — 2026-05-04 — Window Position Recovery
Fixes an off-screen-window scenario the user could end up in after a
+3 -3
View File
File diff suppressed because one or more lines are too long