chore(linting): refresh configs and sweep auto-fix
Pull in the refreshed linter and tooling configs (editorconfig, gitignore, gitattributes, prettierignore, prettierrc, markdownlint, yamllint, env.example, dotnet-tools) and run prettier and markdownlint in --fix / --write mode across the repo so the existing tree matches the new rules. - prettier 2-space indent on yaml/yml and json overrides, asterisk strong, underscore emphasis, proseWrap always - markdownlint MD007 indent aligned to 2 and MD049 to underscore so prettier output stays passing - preflight Block F also ignores CLAUDE.md (gitignored personal file) - prettierignore extended to keep HellionChat.yaml manifest and the NuGet packages.lock.json out of the formatter No semantic content changed; csharpier, build, full build-suite (729/729) and the new prettier/markdownlint/yamllint checks all green.
This commit is contained in:
+237
-152
@@ -1,167 +1,252 @@
|
|||||||
[*]
|
# ##############################################################
|
||||||
indent_style=space
|
# #
|
||||||
tab_width=4
|
# # .editorconfig – Hellion Forge / Hellion Media
|
||||||
indent_size=4
|
# #
|
||||||
trim_trailing_whitespace=true
|
# # Überarbeitet: Mai 2026
|
||||||
insert_final_newline=false
|
# #
|
||||||
|
# # Strategie:
|
||||||
|
# # - Standard-.NET-Conventions (private Fields = _camelCase)
|
||||||
|
# # - CSharpier übernimmt die meiste Formatierung
|
||||||
|
# # - Hier: Naming, IDE-Hints, Backup-Format-Regeln
|
||||||
|
# #
|
||||||
|
# # ##############################################################
|
||||||
|
|
||||||
# JetBrains Rider custom properties for code formatting styles
|
root = true
|
||||||
resharper_csharp_brace_style=next_line
|
|
||||||
# Allman für standard Tooling (VS Code)
|
|
||||||
|
# =====================================================
|
||||||
|
# Defaults (alle Files)
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
tab_width = 4
|
||||||
|
indent_size = 4
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Markdown: Trailing Spaces erlaubt (2 Spaces = <br>)
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# JSON / YAML / Web-Configs: 2-Space-Indent
|
||||||
|
# Konsistent mit yamllint und Prettier-Override
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
[*.{yaml,yml}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.{json,jsonc,har,jsb2,jsb3,postman_collection,postman_environment}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[{.babelrc,.eslintrc,.prettierrc,.markdownlintrc,.stylelintrc,bowerrc}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# .NET / XAML / Razor / Resources: 4-Space-Indent
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
[*.{cs,csx,vb,fs,fsi,fsx}]
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.{xml,xsd,xaml,axaml,paml,resx,resw,nuspec,config}]
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.{cshtml,razor,aspx,ascx,asax,master,axaml}]
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
|
||||||
|
# ##############################################################
|
||||||
|
# #
|
||||||
|
# # C# Sektion: Style, Naming, Format
|
||||||
|
# #
|
||||||
|
# ##############################################################
|
||||||
|
|
||||||
|
[*.{cs,csx}]
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# C# Style – var-Präferenz
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
csharp_style_var_for_built_in_types = true:suggestion
|
||||||
|
csharp_style_var_when_type_is_apparent = true:suggestion
|
||||||
|
csharp_style_var_elsewhere = true:suggestion
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# C# Style – Sonstiges
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
# UTF-8 String Literals (C# 11+)
|
||||||
|
csharp_style_prefer_utf8_string_literals = true:suggestion
|
||||||
|
|
||||||
|
# Reihenfolge der Access-Modifier (Microsoft-Empfehlung)
|
||||||
|
csharp_preferred_modifier_order = public, private, protected, internal, file, new, static, abstract, virtual, sealed, readonly, override, extern, unsafe, volatile, async, required:suggestion
|
||||||
|
|
||||||
|
# Initializer: nicht alles auf eine Zeile
|
||||||
|
csharp_new_line_before_members_in_object_initializers = false
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# C# Format – Braces (Backup, falls CSharpier nicht läuft)
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
# Allman Style: Klammern auf neue Zeile
|
||||||
csharp_new_line_before_open_brace = all
|
csharp_new_line_before_open_brace = all
|
||||||
csharp_new_line_before_else = true
|
csharp_new_line_before_else = true
|
||||||
csharp_new_line_before_catch = true
|
csharp_new_line_before_catch = true
|
||||||
csharp_new_line_before_finally = true
|
csharp_new_line_before_finally = true
|
||||||
|
|
||||||
# Switch-Einrückung
|
|
||||||
|
# =====================================================
|
||||||
|
# C# Format – Switch-Einrückung
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
csharp_indent_case_contents = true
|
csharp_indent_case_contents = true
|
||||||
csharp_indent_switch_labels = true
|
csharp_indent_switch_labels = true
|
||||||
|
|
||||||
resharper_csharp_braces_for_foreach=not_required
|
|
||||||
resharper_csharp_braces_for_for=not_required
|
|
||||||
resharper_csharp_braces_for_while=not_required
|
|
||||||
charset=utf-8
|
|
||||||
end_of_line=lf
|
|
||||||
|
|
||||||
# Microsoft .NET properties
|
# =====================================================
|
||||||
csharp_new_line_before_members_in_object_initializers=false
|
# .NET Style – Qualification (kein "this." nötig)
|
||||||
csharp_preferred_modifier_order=public, private, protected, internal, file, new, static, abstract, virtual, sealed, readonly, override, extern, unsafe, volatile, async, required:suggestion
|
# =====================================================
|
||||||
csharp_style_prefer_utf8_string_literals=true:suggestion
|
|
||||||
csharp_style_var_elsewhere=true:suggestion
|
|
||||||
csharp_style_var_for_built_in_types=true:suggestion
|
|
||||||
csharp_style_var_when_type_is_apparent=true:suggestion
|
|
||||||
dotnet_naming_rule.private_constants_rule.import_to_resharper=True
|
|
||||||
dotnet_naming_rule.private_constants_rule.resharper_description=Constant fields (private)
|
|
||||||
dotnet_naming_rule.private_constants_rule.resharper_guid=236f7aa5-7b06-43ca-bf2a-9b31bfcff09a
|
|
||||||
dotnet_naming_rule.private_constants_rule.severity=warning
|
|
||||||
dotnet_naming_rule.private_constants_rule.style=upper_camel_case_style
|
|
||||||
dotnet_naming_rule.private_constants_rule.symbols=private_constants_symbols
|
|
||||||
dotnet_naming_rule.private_instance_fields_rule.import_to_resharper=True
|
|
||||||
dotnet_naming_rule.private_instance_fields_rule.resharper_description=Instance fields (private)
|
|
||||||
dotnet_naming_rule.private_instance_fields_rule.resharper_guid=4a98fdf6-7d98-4f5a-afeb-ea44ad98c70c
|
|
||||||
dotnet_naming_rule.private_instance_fields_rule.severity=warning
|
|
||||||
dotnet_naming_rule.private_instance_fields_rule.style=upper_camel_case_style
|
|
||||||
dotnet_naming_rule.private_instance_fields_rule.symbols=private_instance_fields_symbols
|
|
||||||
dotnet_naming_rule.private_instance_fields_rule_1.import_to_resharper=True
|
|
||||||
dotnet_naming_rule.private_instance_fields_rule_1.resharper_description=Instance fields (private)
|
|
||||||
dotnet_naming_rule.private_instance_fields_rule_1.resharper_guid=4a98fdf6-7d98-4f5a-afeb-ea44ad98c70c
|
|
||||||
dotnet_naming_rule.private_instance_fields_rule_1.severity=warning
|
|
||||||
dotnet_naming_rule.private_instance_fields_rule_1.style=upper_camel_case_style
|
|
||||||
dotnet_naming_rule.private_instance_fields_rule_1.symbols=private_instance_fields_symbols_1
|
|
||||||
dotnet_naming_rule.private_static_fields_rule.import_to_resharper=True
|
|
||||||
dotnet_naming_rule.private_static_fields_rule.resharper_description=Static fields (private)
|
|
||||||
dotnet_naming_rule.private_static_fields_rule.resharper_guid=f9fce829-e6f4-4cb2-80f1-5497c44f51df
|
|
||||||
dotnet_naming_rule.private_static_fields_rule.severity=warning
|
|
||||||
dotnet_naming_rule.private_static_fields_rule.style=upper_camel_case_style
|
|
||||||
dotnet_naming_rule.private_static_fields_rule.symbols=private_static_fields_symbols
|
|
||||||
dotnet_naming_rule.private_static_readonly_rule.import_to_resharper=True
|
|
||||||
dotnet_naming_rule.private_static_readonly_rule.resharper_description=Static readonly fields (private)
|
|
||||||
dotnet_naming_rule.private_static_readonly_rule.resharper_guid=15b5b1f1-457c-4ca6-b278-5615aedc07d3
|
|
||||||
dotnet_naming_rule.private_static_readonly_rule.severity=warning
|
|
||||||
dotnet_naming_rule.private_static_readonly_rule.style=upper_camel_case_style
|
|
||||||
dotnet_naming_rule.private_static_readonly_rule.symbols=private_static_readonly_symbols
|
|
||||||
dotnet_naming_rule.unity_serialized_field_rule.import_to_resharper=True
|
|
||||||
dotnet_naming_rule.unity_serialized_field_rule.resharper_description=Unity serialized field
|
|
||||||
dotnet_naming_rule.unity_serialized_field_rule.resharper_guid=5f0fdb63-c892-4d2c-9324-15c80b22a7ef
|
|
||||||
dotnet_naming_rule.unity_serialized_field_rule.severity=warning
|
|
||||||
dotnet_naming_rule.unity_serialized_field_rule.style=lower_camel_case_style_1
|
|
||||||
dotnet_naming_rule.unity_serialized_field_rule.symbols=unity_serialized_field_symbols
|
|
||||||
dotnet_naming_rule.unity_serialized_field_rule_1.import_to_resharper=True
|
|
||||||
dotnet_naming_rule.unity_serialized_field_rule_1.resharper_description=Unity serialized field
|
|
||||||
dotnet_naming_rule.unity_serialized_field_rule_1.resharper_guid=5f0fdb63-c892-4d2c-9324-15c80b22a7ef
|
|
||||||
dotnet_naming_rule.unity_serialized_field_rule_1.severity=warning
|
|
||||||
dotnet_naming_rule.unity_serialized_field_rule_1.style=lower_camel_case_style_1
|
|
||||||
dotnet_naming_rule.unity_serialized_field_rule_1.symbols=unity_serialized_field_symbols_1
|
|
||||||
dotnet_naming_style.lower_camel_case_style.capitalization=camel_case
|
|
||||||
dotnet_naming_style.lower_camel_case_style.required_prefix=_
|
|
||||||
dotnet_naming_style.lower_camel_case_style_1.capitalization=camel_case
|
|
||||||
dotnet_naming_style.upper_camel_case_style.capitalization=pascal_case
|
|
||||||
dotnet_naming_symbols.private_constants_symbols.applicable_accessibilities=private
|
|
||||||
dotnet_naming_symbols.private_constants_symbols.applicable_kinds=field
|
|
||||||
dotnet_naming_symbols.private_constants_symbols.required_modifiers=const
|
|
||||||
dotnet_naming_symbols.private_constants_symbols.resharper_applicable_kinds=constant_field
|
|
||||||
dotnet_naming_symbols.private_constants_symbols.resharper_required_modifiers=any
|
|
||||||
dotnet_naming_symbols.private_instance_fields_symbols.applicable_accessibilities=private
|
|
||||||
dotnet_naming_symbols.private_instance_fields_symbols.applicable_kinds=field
|
|
||||||
dotnet_naming_symbols.private_instance_fields_symbols.resharper_applicable_kinds=field,readonly_field
|
|
||||||
dotnet_naming_symbols.private_instance_fields_symbols.resharper_required_modifiers=instance
|
|
||||||
dotnet_naming_symbols.private_instance_fields_symbols_1.applicable_accessibilities=private
|
|
||||||
dotnet_naming_symbols.private_instance_fields_symbols_1.applicable_kinds=field
|
|
||||||
dotnet_naming_symbols.private_instance_fields_symbols_1.resharper_applicable_kinds=field,readonly_field
|
|
||||||
dotnet_naming_symbols.private_instance_fields_symbols_1.resharper_required_modifiers=instance
|
|
||||||
dotnet_naming_symbols.private_static_fields_symbols.applicable_accessibilities=private
|
|
||||||
dotnet_naming_symbols.private_static_fields_symbols.applicable_kinds=field
|
|
||||||
dotnet_naming_symbols.private_static_fields_symbols.required_modifiers=static
|
|
||||||
dotnet_naming_symbols.private_static_fields_symbols.resharper_applicable_kinds=field
|
|
||||||
dotnet_naming_symbols.private_static_fields_symbols.resharper_required_modifiers=static
|
|
||||||
dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities=private
|
|
||||||
dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds=field
|
|
||||||
dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers=readonly,static
|
|
||||||
dotnet_naming_symbols.private_static_readonly_symbols.resharper_applicable_kinds=readonly_field
|
|
||||||
dotnet_naming_symbols.private_static_readonly_symbols.resharper_required_modifiers=static
|
|
||||||
dotnet_naming_symbols.unity_serialized_field_symbols.applicable_accessibilities=*
|
|
||||||
dotnet_naming_symbols.unity_serialized_field_symbols.applicable_kinds=
|
|
||||||
dotnet_naming_symbols.unity_serialized_field_symbols.resharper_applicable_kinds=unity_serialised_field
|
|
||||||
dotnet_naming_symbols.unity_serialized_field_symbols.resharper_required_modifiers=instance
|
|
||||||
dotnet_naming_symbols.unity_serialized_field_symbols_1.applicable_accessibilities=*
|
|
||||||
dotnet_naming_symbols.unity_serialized_field_symbols_1.applicable_kinds=
|
|
||||||
dotnet_naming_symbols.unity_serialized_field_symbols_1.resharper_applicable_kinds=unity_serialised_field
|
|
||||||
dotnet_naming_symbols.unity_serialized_field_symbols_1.resharper_required_modifiers=instance
|
|
||||||
dotnet_style_parentheses_in_arithmetic_binary_operators=never_if_unnecessary:none
|
|
||||||
dotnet_style_parentheses_in_other_binary_operators=always_for_clarity:none
|
|
||||||
dotnet_style_parentheses_in_relational_binary_operators=never_if_unnecessary:none
|
|
||||||
dotnet_style_predefined_type_for_locals_parameters_members=true:suggestion
|
|
||||||
dotnet_style_predefined_type_for_member_access=true:suggestion
|
|
||||||
dotnet_style_qualification_for_event=false:suggestion
|
|
||||||
dotnet_style_qualification_for_field=false:suggestion
|
|
||||||
dotnet_style_qualification_for_method=false:suggestion
|
|
||||||
dotnet_style_qualification_for_property=false:suggestion
|
|
||||||
dotnet_style_require_accessibility_modifiers=for_non_interface_members:suggestion
|
|
||||||
|
|
||||||
# ReSharper properties
|
dotnet_style_qualification_for_field = false:suggestion
|
||||||
resharper_autodetect_indent_settings=true
|
dotnet_style_qualification_for_property = false:suggestion
|
||||||
resharper_cpp_insert_final_newline=true
|
dotnet_style_qualification_for_method = false:suggestion
|
||||||
resharper_csharp_insert_final_newline=false
|
dotnet_style_qualification_for_event = false:suggestion
|
||||||
resharper_formatter_off_tag=@formatter:off
|
|
||||||
resharper_formatter_on_tag=@formatter:on
|
|
||||||
resharper_formatter_tags_enabled=true
|
|
||||||
resharper_fsharp_insert_final_newline=false
|
|
||||||
resharper_html_insert_final_newline=false
|
|
||||||
resharper_resx_insert_final_newline=false
|
|
||||||
resharper_shaderlab_insert_final_newline=false
|
|
||||||
resharper_t4_insert_final_newline=false
|
|
||||||
resharper_use_indent_from_vs=false
|
|
||||||
resharper_vb_insert_final_newline=false
|
|
||||||
resharper_xmldoc_insert_final_newline=false
|
|
||||||
resharper_xml_insert_final_newline=false
|
|
||||||
|
|
||||||
# ReSharper inspection severities
|
|
||||||
resharper_arrange_redundant_parentheses_highlighting=hint
|
|
||||||
resharper_arrange_this_qualifier_highlighting=hint
|
|
||||||
resharper_arrange_type_member_modifiers_highlighting=hint
|
|
||||||
resharper_arrange_type_modifiers_highlighting=hint
|
|
||||||
resharper_built_in_type_reference_style_for_member_access_highlighting=hint
|
|
||||||
resharper_built_in_type_reference_style_highlighting=hint
|
|
||||||
resharper_razor_assembly_not_resolved_highlighting=warning
|
|
||||||
resharper_redundant_base_qualifier_highlighting=warning
|
|
||||||
resharper_suggest_var_or_type_built_in_types_highlighting=hint
|
|
||||||
resharper_suggest_var_or_type_elsewhere_highlighting=hint
|
|
||||||
resharper_suggest_var_or_type_simple_types_highlighting=hint
|
|
||||||
resharper_web_config_module_not_resolved_highlighting=warning
|
|
||||||
resharper_web_config_type_not_resolved_highlighting=warning
|
|
||||||
resharper_web_config_wrong_module_highlighting=warning
|
|
||||||
|
|
||||||
[{*.har,*.jsb2,*.jsb3,*.json,*.jsonc,*.postman_collection,*.postman_collection.json,*.postman_environment,*.postman_environment.json,.babelrc,.eslintrc,.prettierrc,.prettierrc.json,.markdownlint.json,.yamllint.json,.stylelintrc,bowerrc,jest.config}]
|
# =====================================================
|
||||||
indent_style=space
|
# .NET Style – Predefined Types (int statt Int32 etc.)
|
||||||
indent_size=2
|
# =====================================================
|
||||||
|
|
||||||
[{*.yaml,*.yml}]
|
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
|
||||||
indent_style=space
|
dotnet_style_predefined_type_for_member_access = true:suggestion
|
||||||
indent_size=2
|
|
||||||
|
|
||||||
[*.{appxmanifest,asax,ascx,aspx,axaml,build,c,c++,c++m,cc,ccm,cginc,compute,cp,cpp,cppm,cs,cshtml,cu,cuh,cxx,cxxm,dtd,fs,fsi,fsscript,fsx,fx,fxh,h,hh,hlsl,hlsli,hlslinc,hpp,hxx,inc,inl,ino,ipp,ixx,master,ml,mli,mpp,mq4,mq5,mqh,mxx,nuspec,paml,razor,resw,resx,shader,skin,tpp,usf,ush,uxml,vb,xaml,xamlx,xoml,xsd}]
|
|
||||||
indent_style=space
|
# =====================================================
|
||||||
indent_size=4
|
# .NET Style – Parentheses
|
||||||
tab_width=4
|
# =====================================================
|
||||||
[*.md]
|
|
||||||
trim_trailing_whitespace=false
|
dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none
|
||||||
|
dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none
|
||||||
|
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:none
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# .NET Style – Accessibility-Modifier erzwingen
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
|
||||||
|
|
||||||
|
|
||||||
|
# ##############################################################
|
||||||
|
# #
|
||||||
|
# # Naming Conventions (.NET-Standard)
|
||||||
|
# #
|
||||||
|
# # Private Instance Fields: _camelCase
|
||||||
|
# # Private Static Fields: _camelCase
|
||||||
|
# # Private Constants: PascalCase
|
||||||
|
# # Private Static Readonly: PascalCase
|
||||||
|
# #
|
||||||
|
# ##############################################################
|
||||||
|
|
||||||
|
# === Style: Underscore + camelCase ===
|
||||||
|
dotnet_naming_style.underscore_camel_case_style.capitalization = camel_case
|
||||||
|
dotnet_naming_style.underscore_camel_case_style.required_prefix = _
|
||||||
|
|
||||||
|
# === Style: PascalCase ===
|
||||||
|
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
|
||||||
|
|
||||||
|
|
||||||
|
# === Rule: Private Instance Fields → _camelCase ===
|
||||||
|
dotnet_naming_rule.private_instance_fields.severity = warning
|
||||||
|
dotnet_naming_rule.private_instance_fields.symbols = private_instance_fields_symbols
|
||||||
|
dotnet_naming_rule.private_instance_fields.style = underscore_camel_case_style
|
||||||
|
|
||||||
|
dotnet_naming_symbols.private_instance_fields_symbols.applicable_kinds = field
|
||||||
|
dotnet_naming_symbols.private_instance_fields_symbols.applicable_accessibilities = private
|
||||||
|
|
||||||
|
|
||||||
|
# === Rule: Private Static Fields → _camelCase ===
|
||||||
|
dotnet_naming_rule.private_static_fields.severity = warning
|
||||||
|
dotnet_naming_rule.private_static_fields.symbols = private_static_fields_symbols
|
||||||
|
dotnet_naming_rule.private_static_fields.style = underscore_camel_case_style
|
||||||
|
|
||||||
|
dotnet_naming_symbols.private_static_fields_symbols.applicable_kinds = field
|
||||||
|
dotnet_naming_symbols.private_static_fields_symbols.applicable_accessibilities = private
|
||||||
|
dotnet_naming_symbols.private_static_fields_symbols.required_modifiers = static
|
||||||
|
|
||||||
|
|
||||||
|
# === Rule: Private Constants → PascalCase ===
|
||||||
|
dotnet_naming_rule.private_constants.severity = warning
|
||||||
|
dotnet_naming_rule.private_constants.symbols = private_constants_symbols
|
||||||
|
dotnet_naming_rule.private_constants.style = pascal_case_style
|
||||||
|
|
||||||
|
dotnet_naming_symbols.private_constants_symbols.applicable_kinds = field
|
||||||
|
dotnet_naming_symbols.private_constants_symbols.applicable_accessibilities = private
|
||||||
|
dotnet_naming_symbols.private_constants_symbols.required_modifiers = const
|
||||||
|
|
||||||
|
|
||||||
|
# === Rule: Private Static Readonly → PascalCase ===
|
||||||
|
dotnet_naming_rule.private_static_readonly.severity = warning
|
||||||
|
dotnet_naming_rule.private_static_readonly.symbols = private_static_readonly_symbols
|
||||||
|
dotnet_naming_rule.private_static_readonly.style = pascal_case_style
|
||||||
|
|
||||||
|
dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field
|
||||||
|
dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private
|
||||||
|
dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static, readonly
|
||||||
|
|
||||||
|
|
||||||
|
# ##############################################################
|
||||||
|
# #
|
||||||
|
# # JetBrains Rider / ReSharper Settings
|
||||||
|
# #
|
||||||
|
# ##############################################################
|
||||||
|
|
||||||
|
# === Brace-Style (für ReSharper-spezifische Formatierung) ===
|
||||||
|
resharper_csharp_brace_style = next_line
|
||||||
|
|
||||||
|
# Kurze Statements ohne Klammern erlaubt (für 1-Zeiler)
|
||||||
|
resharper_csharp_braces_for_foreach = not_required
|
||||||
|
resharper_csharp_braces_for_for = not_required
|
||||||
|
resharper_csharp_braces_for_while = not_required
|
||||||
|
|
||||||
|
# === Auto-Detection und Formatter-Tags ===
|
||||||
|
resharper_autodetect_indent_settings = true
|
||||||
|
resharper_use_indent_from_vs = false
|
||||||
|
|
||||||
|
# Erlaubt @formatter:off / @formatter:on Kommentare im Code
|
||||||
|
resharper_formatter_off_tag = @formatter:off
|
||||||
|
resharper_formatter_on_tag = @formatter:on
|
||||||
|
resharper_formatter_tags_enabled = true
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# ReSharper Inspection Severities
|
||||||
|
# (Hints = blaue Wellen, Warnings = gelb, Errors = rot)
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
# Style-Suggestions: nur als Hint anzeigen
|
||||||
|
resharper_arrange_redundant_parentheses_highlighting = hint
|
||||||
|
resharper_arrange_this_qualifier_highlighting = hint
|
||||||
|
resharper_arrange_type_member_modifiers_highlighting = hint
|
||||||
|
resharper_arrange_type_modifiers_highlighting = hint
|
||||||
|
resharper_built_in_type_reference_style_for_member_access_highlighting = hint
|
||||||
|
resharper_built_in_type_reference_style_highlighting = hint
|
||||||
|
resharper_suggest_var_or_type_built_in_types_highlighting = hint
|
||||||
|
resharper_suggest_var_or_type_elsewhere_highlighting = hint
|
||||||
|
resharper_suggest_var_or_type_simple_types_highlighting = hint
|
||||||
|
|
||||||
|
# Echte Probleme: als Warning
|
||||||
|
resharper_redundant_base_qualifier_highlighting = warning
|
||||||
+47
-16
@@ -1,19 +1,50 @@
|
|||||||
# Local development environment template
|
##############################################################
|
||||||
#
|
##
|
||||||
# Copy this file to `.env` and adjust paths to your setup,
|
## .env.example – Hellion Forge / Hellion Media
|
||||||
# or run: bash scripts/setup-dev-env.sh
|
##
|
||||||
#
|
## Template für lokale Entwicklungsumgebung.
|
||||||
# `.env` is gitignored — never commit your local paths.
|
## Kopiere diese Datei nach `.env` und passe die Pfade
|
||||||
#
|
## an dein Setup an.
|
||||||
# Activate in shell:
|
##
|
||||||
# set -a; source .env; set +a
|
## ⚠️ `.env` ist gitignored – niemals lokale Pfade committen!
|
||||||
#
|
##
|
||||||
# Or use direnv (recommended):
|
##############################################################
|
||||||
# echo 'dotenv .env' > .envrc && direnv allow
|
##
|
||||||
|
## SETUP
|
||||||
|
##
|
||||||
|
## 1) Manuell:
|
||||||
|
## cp .env.example .env
|
||||||
|
## # Pfade in .env anpassen
|
||||||
|
##
|
||||||
|
## 2) Automatisch:
|
||||||
|
## bash scripts/setup-dev-env.sh
|
||||||
|
##
|
||||||
|
## AKTIVIERUNG IN DER SHELL
|
||||||
|
##
|
||||||
|
## Variante A – einmalig pro Shell:
|
||||||
|
## set -a; source .env; set +a
|
||||||
|
##
|
||||||
|
## Variante B – mit direnv (empfohlen):
|
||||||
|
## echo 'dotenv .env' > .envrc
|
||||||
|
## direnv allow
|
||||||
|
##
|
||||||
|
##############################################################
|
||||||
|
|
||||||
# Path to Dalamud development DLLs (Dalamud.dll, FFXIVClientStructs.dll,
|
|
||||||
# Lumina.dll, Lumina.Excel.dll). Required for building ChatTwo.Tests project.
|
# =====================================================
|
||||||
|
# Build & Development Paths
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
# Pfad zu den Dalamud-Development-DLLs:
|
||||||
|
# - Dalamud.dll
|
||||||
|
# - FFXIVClientStructs.dll
|
||||||
|
# - Lumina.dll
|
||||||
|
# - Lumina.Excel.dll
|
||||||
#
|
#
|
||||||
# XIVLauncher Core (Linux): ~/.xlcore/dalamud/Hooks/dev
|
# Wird zum Bauen des HellionChat.Tests-Projekts benötigt.
|
||||||
# XIVLauncher (Windows): %AppData%\XIVLauncher\addon\Hooks\dev
|
#
|
||||||
|
# Standardpfade je nach Plattform:
|
||||||
|
# XIVLauncher Core (Linux): ~/.xlcore/dalamud/Hooks/dev
|
||||||
|
# XIVLauncher (Windows): %AppData%\XIVLauncher\addon\Hooks\dev
|
||||||
|
# XIVLauncher (macOS): ~/Library/Application Support/XIV on Mac/dalamud/Hooks/dev
|
||||||
DALAMUD_HOME=/path/to/dalamud/dev/dlls
|
DALAMUD_HOME=/path/to/dalamud/dev/dlls
|
||||||
|
|||||||
+177
-7
@@ -1,8 +1,178 @@
|
|||||||
# Generated files
|
##############################################################
|
||||||
HellionChat/Resources/Language.*.resx linguist-generated=true
|
##
|
||||||
|
## .gitattributes – Hellion Forge / Hellion Media
|
||||||
|
##
|
||||||
|
## Setup: Linux-First Development
|
||||||
|
## (Hauptentwicklung auf Linux, Target = Dalamud/Windows)
|
||||||
|
## Überarbeitet: Mai 2026
|
||||||
|
##
|
||||||
|
## Strategie:
|
||||||
|
## - Default: Alles LF (Linux-Konvention)
|
||||||
|
## - Windows-Batch-Scripts: CRLF (technische Pflicht!)
|
||||||
|
## - PowerShell: CRLF (Sicherheit für Windows PS 5.1)
|
||||||
|
## - Binärdateien: explizit markiert (gegen Korruption)
|
||||||
|
##
|
||||||
|
## Hinweis:
|
||||||
|
## Moderne Visual-Studio- und MSBuild-Versionen kommen
|
||||||
|
## problemlos mit LF in .sln/.csproj klar.
|
||||||
|
## Falls jemals Probleme auftauchen: hier umstellen.
|
||||||
|
##
|
||||||
|
##############################################################
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Default: Auto-Detect, alles auf LF normalisieren
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
* text=auto eol=lf
|
* text=auto eol=lf
|
||||||
*.cs text eol=lf
|
|
||||||
*.yml text eol=lf
|
|
||||||
*.yaml text eol=lf
|
# =====================================================
|
||||||
*.md text eol=lf
|
# Source Code (LF)
|
||||||
*.json text eol=lf
|
# =====================================================
|
||||||
|
|
||||||
|
*.cs text eol=lf
|
||||||
|
*.csx text eol=lf
|
||||||
|
*.vb text eol=lf
|
||||||
|
*.fs text eol=lf
|
||||||
|
*.fsx text eol=lf
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Configs & Daten (LF)
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
*.json text eol=lf
|
||||||
|
*.yml text eol=lf
|
||||||
|
*.yaml text eol=lf
|
||||||
|
*.xml text eol=lf
|
||||||
|
*.md text eol=lf
|
||||||
|
*.txt text eol=lf
|
||||||
|
*.config text eol=lf
|
||||||
|
*.editorconfig text eol=lf
|
||||||
|
.gitignore text eol=lf
|
||||||
|
.gitattributes text eol=lf
|
||||||
|
.env.example text eol=lf
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Visual Studio / MSBuild Project Files (LF)
|
||||||
|
# Linux-first: moderne Tools kommen mit LF zurecht
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
*.sln text eol=lf
|
||||||
|
*.csproj text eol=lf
|
||||||
|
*.vbproj text eol=lf
|
||||||
|
*.fsproj text eol=lf
|
||||||
|
*.props text eol=lf
|
||||||
|
*.targets text eol=lf
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Resources & Lokalisierung (LF)
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
# Linguist soll generierte Sprachdateien nicht mitzählen
|
||||||
|
HellionChat/Resources/Language.*.resx linguist-generated=true
|
||||||
|
|
||||||
|
*.resx text eol=lf
|
||||||
|
*.resw text eol=lf
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Linux/Mac-Scripts (LF – Pflicht)
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
*.sh text eol=lf
|
||||||
|
*.bash text eol=lf
|
||||||
|
*.zsh text eol=lf
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# >>> AUSNAHMEN <<<
|
||||||
|
# Windows-Scripts brauchen ZWINGEND CRLF.
|
||||||
|
# Mit LF werden diese auf Windows nicht ausgeführt!
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
# Batch-Scripts (cmd.exe braucht CRLF)
|
||||||
|
*.bat text eol=crlf
|
||||||
|
*.cmd text eol=crlf
|
||||||
|
|
||||||
|
# PowerShell (PS 7+ wäre LF-tolerant,
|
||||||
|
# aber Windows PowerShell 5.1 zickt teilweise)
|
||||||
|
*.ps1 text eol=crlf
|
||||||
|
*.psm1 text eol=crlf
|
||||||
|
*.psd1 text eol=crlf
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Binäre Build-Artefakte
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
*.dll binary
|
||||||
|
*.exe binary
|
||||||
|
*.pdb binary
|
||||||
|
*.so binary
|
||||||
|
*.dylib binary
|
||||||
|
*.nupkg binary
|
||||||
|
*.snupkg binary
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Bilder (binary)
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
*.png binary
|
||||||
|
*.jpg binary
|
||||||
|
*.jpeg binary
|
||||||
|
*.gif binary
|
||||||
|
*.ico binary
|
||||||
|
*.bmp binary
|
||||||
|
*.tiff binary
|
||||||
|
*.webp binary
|
||||||
|
|
||||||
|
# SVG ist eigentlich XML – als Text behandeln
|
||||||
|
*.svg text eol=lf
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Fonts (binary)
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
*.ttf binary
|
||||||
|
*.otf binary
|
||||||
|
*.woff binary
|
||||||
|
*.woff2 binary
|
||||||
|
*.eot binary
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Archive (binary)
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
*.zip binary
|
||||||
|
*.7z binary
|
||||||
|
*.tar binary
|
||||||
|
*.gz binary
|
||||||
|
*.rar binary
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Audio / Video (binary)
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
*.wav binary
|
||||||
|
*.mp3 binary
|
||||||
|
*.ogg binary
|
||||||
|
*.mp4 binary
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# FFXIV / Dalamud spezifische Binär-Formate
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
*.tex binary
|
||||||
|
*.pap binary
|
||||||
|
*.avfx binary
|
||||||
|
*.shpk binary
|
||||||
|
*.scd binary
|
||||||
+27
-27
@@ -11,43 +11,43 @@ name: Build
|
|||||||
# Dalamud SDK 15 uses on Linux).
|
# Dalamud SDK 15 uses on Linux).
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
# Minimum permissions for a build-only workflow: read the repo, nothing
|
# Minimum permissions for a build-only workflow: read the repo, nothing
|
||||||
# else. Closes the CodeQL "Workflow does not contain permissions" alert
|
# else. Closes the CodeQL "Workflow does not contain permissions" alert
|
||||||
# and matches the principle-of-least-privilege the security guide
|
# and matches the principle-of-least-privilege the security guide
|
||||||
# recommends for workflows that don't push or create releases.
|
# recommends for workflows that don't push or create releases.
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Build (Release)
|
name: Build (Release)
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 15
|
timeout-minutes: 15
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
|
|
||||||
- name: Setup .NET 10
|
- name: Setup .NET 10
|
||||||
uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5
|
uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5
|
||||||
with:
|
with:
|
||||||
dotnet-version: 10.0.x
|
dotnet-version: 10.0.x
|
||||||
|
|
||||||
- name: Download Dalamud staging
|
- name: Download Dalamud staging
|
||||||
run: |
|
run: |
|
||||||
hooks="$HOME/.xlcore/dalamud/Hooks/dev"
|
hooks="$HOME/.xlcore/dalamud/Hooks/dev"
|
||||||
mkdir -p "$hooks"
|
mkdir -p "$hooks"
|
||||||
curl -fsSL https://goatcorp.github.io/dalamud-distrib/stg/latest.zip -o dalamud.zip
|
curl -fsSL https://goatcorp.github.io/dalamud-distrib/stg/latest.zip -o dalamud.zip
|
||||||
unzip -oq dalamud.zip -d "$hooks"
|
unzip -oq dalamud.zip -d "$hooks"
|
||||||
|
|
||||||
- name: Restore
|
- name: Restore
|
||||||
run: dotnet restore HellionChat/HellionChat.csproj
|
run: dotnet restore HellionChat/HellionChat.csproj
|
||||||
|
|
||||||
- name: Build (Release)
|
- name: Build (Release)
|
||||||
run: dotnet build HellionChat/HellionChat.csproj --configuration Release --no-restore
|
run: dotnet build HellionChat/HellionChat.csproj --configuration Release --no-restore
|
||||||
|
|||||||
+215
-215
@@ -17,234 +17,234 @@ name: Forge Announce
|
|||||||
# (issue titles, PR bodies, commit messages, etc.) flows into run-steps.
|
# (issue titles, PR bodies, commit messages, etc.) flows into run-steps.
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- "v*"
|
- 'v*'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
tag:
|
tag:
|
||||||
description: "Existing tag to (re)post, e.g. v1.1.0"
|
description: 'Existing tag to (re)post, e.g. v1.1.0'
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
announce:
|
announce:
|
||||||
name: Post changelog to Hellion Forge
|
name: Post changelog to Hellion Forge
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
# The DISCORD_FORGE_WEBHOOK secret is set as a repo-level Actions Secret
|
# The DISCORD_FORGE_WEBHOOK secret is set as a repo-level Actions Secret
|
||||||
# on Gitea (Settings → Actions → Secrets). Repo-level secrets are in
|
# on Gitea (Settings → Actions → Secrets). Repo-level secrets are in
|
||||||
# scope for every job by default, no environment: declaration needed.
|
# scope for every job by default, no environment: declaration needed.
|
||||||
timeout-minutes: 5
|
timeout-minutes: 5
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
# On push:tags github.ref points at the tag commit; on workflow_dispatch
|
# On push:tags github.ref points at the tag commit; on workflow_dispatch
|
||||||
# the user supplies the tag explicitly. Always check out that tag so
|
# the user supplies the tag explicitly. Always check out that tag so
|
||||||
# the yaml + forge-posts file are read from the tagged tree, not main.
|
# the yaml + forge-posts file are read from the tagged tree, not main.
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.inputs.tag || github.ref }}
|
ref: ${{ github.event.inputs.tag || github.ref }}
|
||||||
|
|
||||||
# Build embed-payload as a JSON file on disk. PowerShell-Core (pwsh)
|
# Build embed-payload as a JSON file on disk. PowerShell-Core (pwsh)
|
||||||
# ships pre-installed on ubuntu-latest so we get the same scripting
|
# ships pre-installed on ubuntu-latest so we get the same scripting
|
||||||
# patterns release.yml uses on windows-latest. Tag is read via env: to
|
# patterns release.yml uses on windows-latest. Tag is read via env: to
|
||||||
# treat it as a string variable rather than inline shell text, and
|
# treat it as a string variable rather than inline shell text, and
|
||||||
# validated against the semver regex before any interpolation.
|
# validated against the semver regex before any interpolation.
|
||||||
- name: Build embed payload
|
- name: Build embed payload
|
||||||
id: build
|
id: build
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
env:
|
env:
|
||||||
TAG_NAME: ${{ github.event.inputs.tag || github.ref_name }}
|
TAG_NAME: ${{ github.event.inputs.tag || github.ref_name }}
|
||||||
run: |
|
run: |
|
||||||
$tag = $env:TAG_NAME
|
$tag = $env:TAG_NAME
|
||||||
if ($tag -notmatch '^v\d+\.\d+\.\d+$') {
|
if ($tag -notmatch '^v\d+\.\d+\.\d+$') {
|
||||||
throw "V1: Refusing to announce non-semver tag: $tag"
|
throw "V1: Refusing to announce non-semver tag: $tag"
|
||||||
|
}
|
||||||
|
$version = $tag.Substring(1)
|
||||||
|
|
||||||
|
# ---------- Forge-Post-Datei lesen ----------
|
||||||
|
$forgePath = ".github/forge-posts/$tag.md"
|
||||||
|
if (-not (Test-Path $forgePath)) {
|
||||||
|
throw "V2: Forge-Post-Datei für $tag fehlt unter .github/forge-posts/. Datei vor dem Tag anlegen, dann Tag re-pushen oder workflow_dispatch."
|
||||||
|
}
|
||||||
|
$forgeRaw = Get-Content -Path $forgePath -Raw
|
||||||
|
|
||||||
|
# Frontmatter (--- … ---) am Datei-Anfang
|
||||||
|
if ($forgeRaw -notmatch '(?s)\A---\s*\r?\n(.*?)\r?\n---\s*\r?\n(.*)\z') {
|
||||||
|
throw "V3: Frontmatter (---) fehlt oder ist defekt in $forgePath"
|
||||||
|
}
|
||||||
|
$fmText = $matches[1]
|
||||||
|
$deBody = $matches[2].Trim()
|
||||||
|
|
||||||
|
$subtitle = $null
|
||||||
|
$versionsnatur = $null
|
||||||
|
foreach ($line in ($fmText -split "`r?`n")) {
|
||||||
|
if ($line -match '^subtitle:\s*"?([^"]*)"?\s*$') { $subtitle = $matches[1] }
|
||||||
|
if ($line -match '^versionsnatur:\s*"?([^"]*)"?\s*$') { $versionsnatur = $matches[1] }
|
||||||
|
}
|
||||||
|
if ([string]::IsNullOrWhiteSpace($subtitle)) { throw "V3: Frontmatter-Feld 'subtitle' fehlt in $forgePath" }
|
||||||
|
if ([string]::IsNullOrWhiteSpace($versionsnatur)) { throw "V3: Frontmatter-Feld 'versionsnatur' fehlt in $forgePath" }
|
||||||
|
if ($subtitle.Length -gt 60) { throw "V4: Frontmatter-Feld 'subtitle' überschreitet Limit ($($subtitle.Length) Char, max 60)" }
|
||||||
|
if ($versionsnatur.Length -gt 40) { throw "V4: Frontmatter-Feld 'versionsnatur' überschreitet Limit ($($versionsnatur.Length) Char, max 40)" }
|
||||||
|
if ([string]::IsNullOrWhiteSpace($deBody)) { throw "V3: DE-Body fehlt in $forgePath" }
|
||||||
|
|
||||||
|
# ---------- EN-Block aus HellionChat.yaml ziehen ----------
|
||||||
|
# 1:1 Pattern aus release.yml — gleicher Header-Marker, gleiches
|
||||||
|
# Trailer-Verhalten. Bei Drift die zwei Workflows synchron halten.
|
||||||
|
$yamlPath = "HellionChat/HellionChat.yaml"
|
||||||
|
$raw = Get-Content -Path $yamlPath -Raw
|
||||||
|
$marker = "changelog: |-"
|
||||||
|
$idx = $raw.IndexOf($marker)
|
||||||
|
if ($idx -lt 0) { throw "V5: changelog-Block nicht gefunden in $yamlPath" }
|
||||||
|
$afterMarker = $raw.Substring($idx + $marker.Length)
|
||||||
|
$changelogBody = (($afterMarker -split "`r?`n") | ForEach-Object {
|
||||||
|
if ($_ -match '^ ') { $_.Substring(4) } else { $_ }
|
||||||
|
}) -join "`n"
|
||||||
|
|
||||||
|
$header = "**v$version "
|
||||||
|
$start = $changelogBody.IndexOf($header)
|
||||||
|
if ($start -lt 0) {
|
||||||
|
throw "V5: No changelog entry for version $version found in $yamlPath. Update the changelog block before tagging."
|
||||||
|
}
|
||||||
|
$rest = $changelogBody.Substring($start)
|
||||||
|
$nextHdr = $rest.IndexOf("`n`n**v", 1)
|
||||||
|
$trailer = $rest.IndexOf("`n`n---")
|
||||||
|
if ($nextHdr -ge 0 -and ($trailer -lt 0 -or $nextHdr -lt $trailer)) {
|
||||||
|
$enBlock = $rest.Substring(0, $nextHdr).TrimEnd()
|
||||||
|
} elseif ($trailer -ge 0) {
|
||||||
|
$enBlock = $rest.Substring(0, $trailer).TrimEnd()
|
||||||
|
} else {
|
||||||
|
$enBlock = $rest.TrimEnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------- Embed-Felder + Per-Field-Caps (Discord-Hard-Limits) ----------
|
||||||
|
# Discord enforces per-embed-field limits separately from the
|
||||||
|
# combined-total limit. We split the DE and EN blocks into two
|
||||||
|
# embeds that share the same release URL so Discord stitches
|
||||||
|
# them into one visual card. Hard caps per Discord docs:
|
||||||
|
# description: 4096 per embed
|
||||||
|
# title: 256 per embed
|
||||||
|
# footer.text: 2048 per embed
|
||||||
|
# combined sum across all embeds: 6000
|
||||||
|
$title = "Hellion Chat $version — $subtitle"
|
||||||
|
$deDesc = "**Deutsch**`n`n$deBody"
|
||||||
|
$enDesc = "**English**`n`n$enBlock"
|
||||||
|
$footerText = "Hellion Forge · $versionsnatur"
|
||||||
|
$releaseUrl = "https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/tag/$tag"
|
||||||
|
|
||||||
|
if ($deDesc.Length -gt 4096) {
|
||||||
|
throw "V6a: DE-Body too long for one embed ($($deDesc.Length) chars, max 4096). Trim .github/forge-posts/$tag.md or post the announcement manually (see forge style §8)."
|
||||||
|
}
|
||||||
|
if ($enDesc.Length -gt 4096) {
|
||||||
|
throw "V6b: EN-Block too long for one embed ($($enDesc.Length) chars, max 4096). Trim the changelog entry in HellionChat/HellionChat.yaml or post manually."
|
||||||
|
}
|
||||||
|
$totalChars = $title.Length + $deDesc.Length + $enDesc.Length + $footerText.Length
|
||||||
|
if ($totalChars -gt 6000) {
|
||||||
|
throw "V6c: Combined embed chars $totalChars exceed Discord's 6000-total limit. Major-Release detected — post manually via Bot/Multi-Embed (see forge style §8)."
|
||||||
|
}
|
||||||
|
Write-Host "Embed-Caps OK: de=$($deDesc.Length)/4096, en=$($enDesc.Length)/4096, total=$totalChars/6000"
|
||||||
|
|
||||||
|
# ---------- Embed-Payload bauen (zwei Embeds, gleiche url) ----------
|
||||||
|
# Sharing the same `url` tells Discord to render both embeds as a
|
||||||
|
# single contiguous card block. The title sits on the first embed,
|
||||||
|
# the footer + timestamp on the last so it reads as one post.
|
||||||
|
$payload = [ordered]@{
|
||||||
|
username = "Forge Herald"
|
||||||
|
avatar_url = "https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/raw/branch/main/HellionChat/images/icon.png"
|
||||||
|
content = "<@&1500489631555260446>"
|
||||||
|
allowed_mentions = [ordered]@{
|
||||||
|
parse = @()
|
||||||
|
roles = @("1500489631555260446")
|
||||||
|
}
|
||||||
|
embeds = @(
|
||||||
|
[ordered]@{
|
||||||
|
title = $title
|
||||||
|
url = $releaseUrl
|
||||||
|
color = 12730636
|
||||||
|
description = $deDesc
|
||||||
|
},
|
||||||
|
[ordered]@{
|
||||||
|
url = $releaseUrl
|
||||||
|
color = 12730636
|
||||||
|
description = $enDesc
|
||||||
|
footer = [ordered]@{ text = $footerText }
|
||||||
|
timestamp = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ")
|
||||||
}
|
}
|
||||||
$version = $tag.Substring(1)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
# ---------- Forge-Post-Datei lesen ----------
|
$payloadJson = $payload | ConvertTo-Json -Depth 8 -Compress
|
||||||
$forgePath = ".github/forge-posts/$tag.md"
|
# Ausgabe-Datei ohne trailing newline für sauberes curl --data-binary @-
|
||||||
if (-not (Test-Path $forgePath)) {
|
[System.IO.File]::WriteAllText("$PWD/embed-payload.json", $payloadJson, [System.Text.UTF8Encoding]::new($false))
|
||||||
throw "V2: Forge-Post-Datei für $tag fehlt unter .github/forge-posts/. Datei vor dem Tag anlegen, dann Tag re-pushen oder workflow_dispatch."
|
|
||||||
}
|
|
||||||
$forgeRaw = Get-Content -Path $forgePath -Raw
|
|
||||||
|
|
||||||
# Frontmatter (--- … ---) am Datei-Anfang
|
Write-Host "Payload size: $($payloadJson.Length) chars"
|
||||||
if ($forgeRaw -notmatch '(?s)\A---\s*\r?\n(.*?)\r?\n---\s*\r?\n(.*)\z') {
|
Write-Host "Embed title: $title"
|
||||||
throw "V3: Frontmatter (---) fehlt oder ist defekt in $forgePath"
|
Write-Host "Embed footer: $footerText"
|
||||||
}
|
|
||||||
$fmText = $matches[1]
|
|
||||||
$deBody = $matches[2].Trim()
|
|
||||||
|
|
||||||
$subtitle = $null
|
# POST to the Hellion Forge changelog webhook. curl from PowerShell-Core
|
||||||
$versionsnatur = $null
|
# so we can pipe the payload via stdin (--data-binary @-) and keep
|
||||||
foreach ($line in ($fmText -split "`r?`n")) {
|
# secrets out of process arg lists. One retry on 5xx, hard fail on 4xx.
|
||||||
if ($line -match '^subtitle:\s*"?([^"]*)"?\s*$') { $subtitle = $matches[1] }
|
- name: POST to Hellion Forge webhook
|
||||||
if ($line -match '^versionsnatur:\s*"?([^"]*)"?\s*$') { $versionsnatur = $matches[1] }
|
shell: pwsh
|
||||||
}
|
env:
|
||||||
if ([string]::IsNullOrWhiteSpace($subtitle)) { throw "V3: Frontmatter-Feld 'subtitle' fehlt in $forgePath" }
|
DISCORD_FORGE_WEBHOOK: ${{ secrets.DISCORD_FORGE_WEBHOOK }}
|
||||||
if ([string]::IsNullOrWhiteSpace($versionsnatur)) { throw "V3: Frontmatter-Feld 'versionsnatur' fehlt in $forgePath" }
|
run: |
|
||||||
if ($subtitle.Length -gt 60) { throw "V4: Frontmatter-Feld 'subtitle' überschreitet Limit ($($subtitle.Length) Char, max 60)" }
|
if ([string]::IsNullOrEmpty($env:DISCORD_FORGE_WEBHOOK)) {
|
||||||
if ($versionsnatur.Length -gt 40) { throw "V4: Frontmatter-Feld 'versionsnatur' überschreitet Limit ($($versionsnatur.Length) Char, max 40)" }
|
throw "V7: DISCORD_FORGE_WEBHOOK secret is empty. Check Settings → Environments → Webhook."
|
||||||
if ([string]::IsNullOrWhiteSpace($deBody)) { throw "V3: DE-Body fehlt in $forgePath" }
|
}
|
||||||
|
|
||||||
# ---------- EN-Block aus HellionChat.yaml ziehen ----------
|
$payloadFile = "$PWD/embed-payload.json"
|
||||||
# 1:1 Pattern aus release.yml — gleicher Header-Marker, gleiches
|
if (-not (Test-Path $payloadFile)) {
|
||||||
# Trailer-Verhalten. Bei Drift die zwei Workflows synchron halten.
|
throw "Embed payload file missing — previous step did not produce embed-payload.json"
|
||||||
$yamlPath = "HellionChat/HellionChat.yaml"
|
}
|
||||||
$raw = Get-Content -Path $yamlPath -Raw
|
|
||||||
$marker = "changelog: |-"
|
|
||||||
$idx = $raw.IndexOf($marker)
|
|
||||||
if ($idx -lt 0) { throw "V5: changelog-Block nicht gefunden in $yamlPath" }
|
|
||||||
$afterMarker = $raw.Substring($idx + $marker.Length)
|
|
||||||
$changelogBody = (($afterMarker -split "`r?`n") | ForEach-Object {
|
|
||||||
if ($_ -match '^ ') { $_.Substring(4) } else { $_ }
|
|
||||||
}) -join "`n"
|
|
||||||
|
|
||||||
$header = "**v$version "
|
$maxAttempts = 2
|
||||||
$start = $changelogBody.IndexOf($header)
|
$attempt = 0
|
||||||
if ($start -lt 0) {
|
while ($attempt -lt $maxAttempts) {
|
||||||
throw "V5: No changelog entry for version $version found in $yamlPath. Update the changelog block before tagging."
|
$attempt++
|
||||||
}
|
Write-Host "POST attempt $attempt of $maxAttempts"
|
||||||
$rest = $changelogBody.Substring($start)
|
$tmpResp = "$PWD/.webhook-response"
|
||||||
$nextHdr = $rest.IndexOf("`n`n**v", 1)
|
$tmpHeaders = "$PWD/.webhook-headers"
|
||||||
$trailer = $rest.IndexOf("`n`n---")
|
# --silent suppresses progress; --show-error prints errors so
|
||||||
if ($nextHdr -ge 0 -and ($trailer -lt 0 -or $nextHdr -lt $trailer)) {
|
# the workflow log shows what happened. -w prints HTTP status
|
||||||
$enBlock = $rest.Substring(0, $nextHdr).TrimEnd()
|
# to stdout for inspection. -o captures body for diagnosis,
|
||||||
} elseif ($trailer -ge 0) {
|
# -D captures headers.
|
||||||
$enBlock = $rest.Substring(0, $trailer).TrimEnd()
|
$rawStatus = Get-Content $payloadFile -Raw |
|
||||||
} else {
|
curl --silent --show-error `
|
||||||
$enBlock = $rest.TrimEnd()
|
--header 'Content-Type: application/json' `
|
||||||
}
|
--data-binary '@-' `
|
||||||
|
-D $tmpHeaders `
|
||||||
|
-o $tmpResp `
|
||||||
|
-w '%{http_code}' `
|
||||||
|
"$env:DISCORD_FORGE_WEBHOOK"
|
||||||
|
$status = [int]$rawStatus
|
||||||
|
Write-Host "HTTP status: $status"
|
||||||
|
|
||||||
# ---------- Embed-Felder + Per-Field-Caps (Discord-Hard-Limits) ----------
|
if ($status -ge 200 -and $status -lt 300) {
|
||||||
# Discord enforces per-embed-field limits separately from the
|
Write-Host "Forge announce POST succeeded."
|
||||||
# combined-total limit. We split the DE and EN blocks into two
|
exit 0
|
||||||
# embeds that share the same release URL so Discord stitches
|
}
|
||||||
# them into one visual card. Hard caps per Discord docs:
|
|
||||||
# description: 4096 per embed
|
|
||||||
# title: 256 per embed
|
|
||||||
# footer.text: 2048 per embed
|
|
||||||
# combined sum across all embeds: 6000
|
|
||||||
$title = "Hellion Chat $version — $subtitle"
|
|
||||||
$deDesc = "**Deutsch**`n`n$deBody"
|
|
||||||
$enDesc = "**English**`n`n$enBlock"
|
|
||||||
$footerText = "Hellion Forge · $versionsnatur"
|
|
||||||
$releaseUrl = "https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/tag/$tag"
|
|
||||||
|
|
||||||
if ($deDesc.Length -gt 4096) {
|
$bodySnippet = ""
|
||||||
throw "V6a: DE-Body too long for one embed ($($deDesc.Length) chars, max 4096). Trim .github/forge-posts/$tag.md or post the announcement manually (see forge style §8)."
|
if (Test-Path $tmpResp) {
|
||||||
}
|
$bodySnippet = (Get-Content $tmpResp -Raw -ErrorAction SilentlyContinue)
|
||||||
if ($enDesc.Length -gt 4096) {
|
if ($bodySnippet.Length -gt 500) { $bodySnippet = $bodySnippet.Substring(0, 500) + " …" }
|
||||||
throw "V6b: EN-Block too long for one embed ($($enDesc.Length) chars, max 4096). Trim the changelog entry in HellionChat/HellionChat.yaml or post manually."
|
}
|
||||||
}
|
|
||||||
$totalChars = $title.Length + $deDesc.Length + $enDesc.Length + $footerText.Length
|
|
||||||
if ($totalChars -gt 6000) {
|
|
||||||
throw "V6c: Combined embed chars $totalChars exceed Discord's 6000-total limit. Major-Release detected — post manually via Bot/Multi-Embed (see forge style §8)."
|
|
||||||
}
|
|
||||||
Write-Host "Embed-Caps OK: de=$($deDesc.Length)/4096, en=$($enDesc.Length)/4096, total=$totalChars/6000"
|
|
||||||
|
|
||||||
# ---------- Embed-Payload bauen (zwei Embeds, gleiche url) ----------
|
if ($status -ge 400 -and $status -lt 500) {
|
||||||
# Sharing the same `url` tells Discord to render both embeds as a
|
# E2: 4xx is permanent — webhook revoked, channel deleted,
|
||||||
# single contiguous card block. The title sits on the first embed,
|
# payload malformed. No retry.
|
||||||
# the footer + timestamp on the last so it reads as one post.
|
throw "E2: Discord-Webhook returned permanent $status. Body: $bodySnippet"
|
||||||
$payload = [ordered]@{
|
}
|
||||||
username = "Forge Herald"
|
|
||||||
avatar_url = "https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/raw/branch/main/HellionChat/images/icon.png"
|
|
||||||
content = "<@&1500489631555260446>"
|
|
||||||
allowed_mentions = [ordered]@{
|
|
||||||
parse = @()
|
|
||||||
roles = @("1500489631555260446")
|
|
||||||
}
|
|
||||||
embeds = @(
|
|
||||||
[ordered]@{
|
|
||||||
title = $title
|
|
||||||
url = $releaseUrl
|
|
||||||
color = 12730636
|
|
||||||
description = $deDesc
|
|
||||||
},
|
|
||||||
[ordered]@{
|
|
||||||
url = $releaseUrl
|
|
||||||
color = 12730636
|
|
||||||
description = $enDesc
|
|
||||||
footer = [ordered]@{ text = $footerText }
|
|
||||||
timestamp = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
$payloadJson = $payload | ConvertTo-Json -Depth 8 -Compress
|
# E1: 5xx (or transport-level fail with status 0) — wait + retry once
|
||||||
# Ausgabe-Datei ohne trailing newline für sauberes curl --data-binary @-
|
if ($attempt -lt $maxAttempts) {
|
||||||
[System.IO.File]::WriteAllText("$PWD/embed-payload.json", $payloadJson, [System.Text.UTF8Encoding]::new($false))
|
Write-Host "Transient $status — sleeping 30s before retry."
|
||||||
|
Start-Sleep -Seconds 30
|
||||||
Write-Host "Payload size: $($payloadJson.Length) chars"
|
} else {
|
||||||
Write-Host "Embed title: $title"
|
throw "E1: Discord-Webhook returned transient $status after $maxAttempts attempts. Body: $bodySnippet"
|
||||||
Write-Host "Embed footer: $footerText"
|
}
|
||||||
|
}
|
||||||
# POST to the Hellion Forge changelog webhook. curl from PowerShell-Core
|
|
||||||
# so we can pipe the payload via stdin (--data-binary @-) and keep
|
|
||||||
# secrets out of process arg lists. One retry on 5xx, hard fail on 4xx.
|
|
||||||
- name: POST to Hellion Forge webhook
|
|
||||||
shell: pwsh
|
|
||||||
env:
|
|
||||||
DISCORD_FORGE_WEBHOOK: ${{ secrets.DISCORD_FORGE_WEBHOOK }}
|
|
||||||
run: |
|
|
||||||
if ([string]::IsNullOrEmpty($env:DISCORD_FORGE_WEBHOOK)) {
|
|
||||||
throw "V7: DISCORD_FORGE_WEBHOOK secret is empty. Check Settings → Environments → Webhook."
|
|
||||||
}
|
|
||||||
|
|
||||||
$payloadFile = "$PWD/embed-payload.json"
|
|
||||||
if (-not (Test-Path $payloadFile)) {
|
|
||||||
throw "Embed payload file missing — previous step did not produce embed-payload.json"
|
|
||||||
}
|
|
||||||
|
|
||||||
$maxAttempts = 2
|
|
||||||
$attempt = 0
|
|
||||||
while ($attempt -lt $maxAttempts) {
|
|
||||||
$attempt++
|
|
||||||
Write-Host "POST attempt $attempt of $maxAttempts"
|
|
||||||
$tmpResp = "$PWD/.webhook-response"
|
|
||||||
$tmpHeaders = "$PWD/.webhook-headers"
|
|
||||||
# --silent suppresses progress; --show-error prints errors so
|
|
||||||
# the workflow log shows what happened. -w prints HTTP status
|
|
||||||
# to stdout for inspection. -o captures body for diagnosis,
|
|
||||||
# -D captures headers.
|
|
||||||
$rawStatus = Get-Content $payloadFile -Raw |
|
|
||||||
curl --silent --show-error `
|
|
||||||
--header 'Content-Type: application/json' `
|
|
||||||
--data-binary '@-' `
|
|
||||||
-D $tmpHeaders `
|
|
||||||
-o $tmpResp `
|
|
||||||
-w '%{http_code}' `
|
|
||||||
"$env:DISCORD_FORGE_WEBHOOK"
|
|
||||||
$status = [int]$rawStatus
|
|
||||||
Write-Host "HTTP status: $status"
|
|
||||||
|
|
||||||
if ($status -ge 200 -and $status -lt 300) {
|
|
||||||
Write-Host "Forge announce POST succeeded."
|
|
||||||
exit 0
|
|
||||||
}
|
|
||||||
|
|
||||||
$bodySnippet = ""
|
|
||||||
if (Test-Path $tmpResp) {
|
|
||||||
$bodySnippet = (Get-Content $tmpResp -Raw -ErrorAction SilentlyContinue)
|
|
||||||
if ($bodySnippet.Length -gt 500) { $bodySnippet = $bodySnippet.Substring(0, 500) + " …" }
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($status -ge 400 -and $status -lt 500) {
|
|
||||||
# E2: 4xx is permanent — webhook revoked, channel deleted,
|
|
||||||
# payload malformed. No retry.
|
|
||||||
throw "E2: Discord-Webhook returned permanent $status. Body: $bodySnippet"
|
|
||||||
}
|
|
||||||
|
|
||||||
# E1: 5xx (or transport-level fail with status 0) — wait + retry once
|
|
||||||
if ($attempt -lt $maxAttempts) {
|
|
||||||
Write-Host "Transient $status — sleeping 30s before retry."
|
|
||||||
Start-Sleep -Seconds 30
|
|
||||||
} else {
|
|
||||||
throw "E1: Discord-Webhook returned transient $status after $maxAttempts attempts. Body: $bodySnippet"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+142
-142
@@ -17,167 +17,167 @@ name: Release
|
|||||||
# Linux when the Dalamud staging assemblies sit under $(HOME)/.xlcore/...
|
# Linux when the Dalamud staging assemblies sit under $(HOME)/.xlcore/...
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- "v*"
|
- 'v*'
|
||||||
# Manual recovery trigger. Use Gitea's "Run workflow" UI and select the
|
# Manual recovery trigger. Use Gitea's "Run workflow" UI and select the
|
||||||
# tag (e.g. v1.4.4) from the Ref dropdown - not main. The Validate tag
|
# tag (e.g. v1.4.4) from the Ref dropdown - not main. The Validate tag
|
||||||
# ref step below hard-fails if a non-tag ref is selected, because the
|
# ref step below hard-fails if a non-tag ref is selected, because the
|
||||||
# release-action reads GITHUB_REF directly and rejects anything that
|
# release-action reads GITHUB_REF directly and rejects anything that
|
||||||
# does not start with refs/tags/.
|
# does not start with refs/tags/.
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
name: Build and attach release ZIP
|
name: Build and attach release ZIP
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 20
|
timeout-minutes: 20
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
# release-action@main reads GITHUB_REF directly (its action.yml
|
# release-action@main reads GITHUB_REF directly (its action.yml
|
||||||
# does not declare a tag_name input). Validate up-front so manual
|
# does not declare a tag_name input). Validate up-front so manual
|
||||||
# dispatches from a branch ref fail loud here instead of burning
|
# dispatches from a branch ref fail loud here instead of burning
|
||||||
# a full build before the final step errors out with "ref X is
|
# a full build before the final step errors out with "ref X is
|
||||||
# not a tag".
|
# not a tag".
|
||||||
- name: Validate tag ref
|
- name: Validate tag ref
|
||||||
run: |
|
run: |
|
||||||
if [[ "${GITHUB_REF}" != refs/tags/v* ]]; then
|
if [[ "${GITHUB_REF}" != refs/tags/v* ]]; then
|
||||||
echo "::error::Release workflow must run on a v*.X.Y tag ref, got ${GITHUB_REF}"
|
echo "::error::Release workflow must run on a v*.X.Y tag ref, got ${GITHUB_REF}"
|
||||||
echo "::error::Push a tag, or pick the tag (not main) in the workflow_dispatch Ref dropdown."
|
echo "::error::Push a tag, or pick the tag (not main) in the workflow_dispatch Ref dropdown."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
|
|
||||||
- name: Setup .NET 10
|
- name: Setup .NET 10
|
||||||
uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5
|
uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5
|
||||||
with:
|
with:
|
||||||
dotnet-version: 10.0.x
|
dotnet-version: 10.0.x
|
||||||
|
|
||||||
- name: Download Dalamud staging
|
- name: Download Dalamud staging
|
||||||
run: |
|
run: |
|
||||||
hooks="$HOME/.xlcore/dalamud/Hooks/dev"
|
hooks="$HOME/.xlcore/dalamud/Hooks/dev"
|
||||||
mkdir -p "$hooks"
|
mkdir -p "$hooks"
|
||||||
curl -fsSL https://goatcorp.github.io/dalamud-distrib/stg/latest.zip -o dalamud.zip
|
curl -fsSL https://goatcorp.github.io/dalamud-distrib/stg/latest.zip -o dalamud.zip
|
||||||
unzip -oq dalamud.zip -d "$hooks"
|
unzip -oq dalamud.zip -d "$hooks"
|
||||||
|
|
||||||
- name: Build (Release)
|
- name: Build (Release)
|
||||||
run: dotnet build HellionChat/HellionChat.csproj --configuration Release
|
run: dotnet build HellionChat/HellionChat.csproj --configuration Release
|
||||||
|
|
||||||
- name: Locate latest.zip
|
- name: Locate latest.zip
|
||||||
id: locate
|
id: locate
|
||||||
run: |
|
run: |
|
||||||
zip="$(find HellionChat/bin/Release -name latest.zip -print -quit)"
|
zip="$(find HellionChat/bin/Release -name latest.zip -print -quit)"
|
||||||
if [ -z "$zip" ]; then
|
if [ -z "$zip" ]; then
|
||||||
echo "latest.zip not found under HellionChat/bin/Release" >&2
|
echo "latest.zip not found under HellionChat/bin/Release" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo "Found: $zip"
|
echo "Found: $zip"
|
||||||
echo "path=$zip" >> "$GITHUB_OUTPUT"
|
echo "path=$zip" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
# Build a release body from the matching changelog block in
|
# Build a release body from the matching changelog block in
|
||||||
# HellionChat.yaml plus a static install / docs footer. Fails the
|
# HellionChat.yaml plus a static install / docs footer. Fails the
|
||||||
# workflow if no block exists for the tagged version, which is the
|
# workflow if no block exists for the tagged version, which is the
|
||||||
# automated counterpart to the "yaml + repo.json + release body
|
# automated counterpart to the "yaml + repo.json + release body
|
||||||
# kept in sync" rule.
|
# kept in sync" rule.
|
||||||
#
|
#
|
||||||
# GITHUB_REF_NAME is read via env: (not ${{ }} interpolation) so the
|
# GITHUB_REF_NAME is read via env: (not ${{ }} interpolation) so the
|
||||||
# tag value is treated as a PowerShell variable, not as inline shell
|
# tag value is treated as a PowerShell variable, not as inline shell
|
||||||
# text. The strict regex below rejects anything that is not a clean
|
# text. The strict regex below rejects anything that is not a clean
|
||||||
# semver tag before it is used to build a string.
|
# semver tag before it is used to build a string.
|
||||||
- name: Generate release body
|
- name: Generate release body
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
env:
|
env:
|
||||||
# github.ref_name is the tag because Validate tag ref above
|
# github.ref_name is the tag because Validate tag ref above
|
||||||
# already enforced refs/tags/v*. Read via env: so the value
|
# already enforced refs/tags/v*. Read via env: so the value
|
||||||
# is a PowerShell variable, not inline shell text, and gets
|
# is a PowerShell variable, not inline shell text, and gets
|
||||||
# re-validated against the semver regex below.
|
# re-validated against the semver regex below.
|
||||||
TAG_NAME: ${{ github.ref_name }}
|
TAG_NAME: ${{ github.ref_name }}
|
||||||
run: |
|
run: |
|
||||||
$tag = $env:TAG_NAME
|
$tag = $env:TAG_NAME
|
||||||
if ($tag -notmatch '^v\d+\.\d+\.\d+$') {
|
if ($tag -notmatch '^v\d+\.\d+\.\d+$') {
|
||||||
throw "Refusing to generate release body for non-semver tag: $tag"
|
throw "Refusing to generate release body for non-semver tag: $tag"
|
||||||
}
|
}
|
||||||
$version = $tag.Substring(1)
|
$version = $tag.Substring(1)
|
||||||
|
|
||||||
$yamlPath = "HellionChat/HellionChat.yaml"
|
$yamlPath = "HellionChat/HellionChat.yaml"
|
||||||
$raw = Get-Content -Path $yamlPath -Raw
|
$raw = Get-Content -Path $yamlPath -Raw
|
||||||
|
|
||||||
$marker = "changelog: |-"
|
$marker = "changelog: |-"
|
||||||
$idx = $raw.IndexOf($marker)
|
$idx = $raw.IndexOf($marker)
|
||||||
if ($idx -lt 0) { throw "changelog block not found in $yamlPath" }
|
if ($idx -lt 0) { throw "changelog block not found in $yamlPath" }
|
||||||
|
|
||||||
# changelog: is the last top-level key in the manifest, so
|
# changelog: is the last top-level key in the manifest, so
|
||||||
# everything after the marker is the literal block. Strip the
|
# everything after the marker is the literal block. Strip the
|
||||||
# 4-space yaml indent (prettier convention) from each line.
|
# 4-space yaml indent (prettier convention) from each line.
|
||||||
$afterMarker = $raw.Substring($idx + $marker.Length)
|
$afterMarker = $raw.Substring($idx + $marker.Length)
|
||||||
$changelogBody = (($afterMarker -split "`r?`n") | ForEach-Object {
|
$changelogBody = (($afterMarker -split "`r?`n") | ForEach-Object {
|
||||||
if ($_ -match '^ ') { $_.Substring(4) } else { $_ }
|
if ($_ -match '^ ') { $_.Substring(4) } else { $_ }
|
||||||
}) -join "`n"
|
}) -join "`n"
|
||||||
|
|
||||||
# Subblock convention: "**vX.Y.Z — <subtitle> (<date>)**"
|
# Subblock convention: "**vX.Y.Z — <subtitle> (<date>)**"
|
||||||
# matches verify-changelog-sync.sh and slim-rule grep.
|
# matches verify-changelog-sync.sh and slim-rule grep.
|
||||||
$header = "**v$version "
|
$header = "**v$version "
|
||||||
$start = $changelogBody.IndexOf($header)
|
$start = $changelogBody.IndexOf($header)
|
||||||
if ($start -lt 0) {
|
if ($start -lt 0) {
|
||||||
throw "No changelog entry for version $version found in $yamlPath. Update the changelog block before tagging a release."
|
throw "No changelog entry for version $version found in $yamlPath. Update the changelog block before tagging a release."
|
||||||
}
|
}
|
||||||
|
|
||||||
$rest = $changelogBody.Substring($start)
|
$rest = $changelogBody.Substring($start)
|
||||||
$nextHdr = $rest.IndexOf("`n`n**v", 1)
|
$nextHdr = $rest.IndexOf("`n`n**v", 1)
|
||||||
$trailer = $rest.IndexOf("`n`n---")
|
$trailer = $rest.IndexOf("`n`n---")
|
||||||
|
|
||||||
if ($nextHdr -ge 0 -and ($trailer -lt 0 -or $nextHdr -lt $trailer)) {
|
if ($nextHdr -ge 0 -and ($trailer -lt 0 -or $nextHdr -lt $trailer)) {
|
||||||
$currentBlock = $rest.Substring(0, $nextHdr).TrimEnd()
|
$currentBlock = $rest.Substring(0, $nextHdr).TrimEnd()
|
||||||
} elseif ($trailer -ge 0) {
|
} elseif ($trailer -ge 0) {
|
||||||
$currentBlock = $rest.Substring(0, $trailer).TrimEnd()
|
$currentBlock = $rest.Substring(0, $trailer).TrimEnd()
|
||||||
} else {
|
} else {
|
||||||
$currentBlock = $rest.TrimEnd()
|
$currentBlock = $rest.TrimEnd()
|
||||||
}
|
}
|
||||||
|
|
||||||
# Static install / docs / licence footer is maintained as a
|
# Static install / docs / licence footer is maintained as a
|
||||||
# separate file so the workflow YAML stays clean (no embedded
|
# separate file so the workflow YAML stays clean (no embedded
|
||||||
# heredoc that would have to be indented under the run-block).
|
# heredoc that would have to be indented under the run-block).
|
||||||
$footerPath = ".github/release-footer.md"
|
$footerPath = ".github/release-footer.md"
|
||||||
if (-not (Test-Path $footerPath)) {
|
if (-not (Test-Path $footerPath)) {
|
||||||
throw "Release footer template not found: $footerPath"
|
throw "Release footer template not found: $footerPath"
|
||||||
}
|
}
|
||||||
$footer = Get-Content -Path $footerPath -Raw
|
$footer = Get-Content -Path $footerPath -Raw
|
||||||
|
|
||||||
$body = $currentBlock + "`n" + $footer
|
$body = $currentBlock + "`n" + $footer
|
||||||
$body | Out-File -FilePath release-body.md -Encoding utf8 -NoNewline
|
$body | Out-File -FilePath release-body.md -Encoding utf8 -NoNewline
|
||||||
|
|
||||||
Write-Host "Generated release body for $tag :"
|
Write-Host "Generated release body for $tag :"
|
||||||
Write-Host "----------------------------------------"
|
Write-Host "----------------------------------------"
|
||||||
Write-Host $body
|
Write-Host $body
|
||||||
Write-Host "----------------------------------------"
|
Write-Host "----------------------------------------"
|
||||||
|
|
||||||
# release-action@main only declares files/title/body/pre_release/
|
# release-action@main only declares files/title/body/pre_release/
|
||||||
# draft/api_key/insecure as inputs (see its action.yml). It silently
|
# draft/api_key/insecure as inputs (see its action.yml). It silently
|
||||||
# ignores anything else, including body_path and tag_name. The tag
|
# ignores anything else, including body_path and tag_name. The tag
|
||||||
# itself comes from GITHUB_REF, the body must be passed inline via
|
# itself comes from GITHUB_REF, the body must be passed inline via
|
||||||
# body:, so we re-emit release-body.md as a step output first.
|
# body:, so we re-emit release-body.md as a step output first.
|
||||||
- name: Expose release body for release-action
|
- name: Expose release body for release-action
|
||||||
id: body
|
id: body
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
{
|
{
|
||||||
echo 'content<<RELEASE_BODY_EOF'
|
echo 'content<<RELEASE_BODY_EOF'
|
||||||
cat release-body.md
|
cat release-body.md
|
||||||
echo 'RELEASE_BODY_EOF'
|
echo 'RELEASE_BODY_EOF'
|
||||||
} >> "$GITHUB_OUTPUT"
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
# Gitea-native release action. Creates the release if the tag has no
|
# Gitea-native release action. Creates the release if the tag has no
|
||||||
# release yet, or updates the existing one with latest.zip attached
|
# release yet, or updates the existing one with latest.zip attached
|
||||||
# and the generated body. The auto-injected GITHUB_TOKEN on Gitea
|
# and the generated body. The auto-injected GITHUB_TOKEN on Gitea
|
||||||
# Actions has Gitea-API scope and is sufficient for release write.
|
# Actions has Gitea-API scope and is sufficient for release write.
|
||||||
- name: Attach to Gitea release
|
- name: Attach to Gitea release
|
||||||
uses: https://gitea.com/actions/release-action@main
|
uses: https://gitea.com/actions/release-action@main
|
||||||
with:
|
with:
|
||||||
files: ${{ steps.locate.outputs.path }}
|
files: ${{ steps.locate.outputs.path }}
|
||||||
body: ${{ steps.body.outputs.content }}
|
body: ${{ steps.body.outputs.content }}
|
||||||
api_key: ${{ secrets.GITHUB_TOKEN }}
|
api_key: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
name: Security
|
name: Security
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [main, master]
|
branches: [main, master]
|
||||||
pull_request:
|
pull_request:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "0 6 * * 1"
|
- cron: '0 6 * * 1'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
scan:
|
scan:
|
||||||
uses: JonKazama-Hellion/security-workflows/.gitea/workflows/security-scan.yml@main
|
uses: JonKazama-Hellion/security-workflows/.gitea/workflows/security-scan.yml@main
|
||||||
with:
|
with:
|
||||||
# MessageStore.cs uses string-interpolation in CommandText for table
|
# MessageStore.cs uses string-interpolation in CommandText for table
|
||||||
# names and clause-joins that come from internal code constants, not
|
# names and clause-joins that come from internal code constants, not
|
||||||
# user input. Values are bound via SqlParameter, the SQL surface is
|
# user input. Values are bound via SqlParameter, the SQL surface is
|
||||||
# local-only inside a Dalamud plugin. Semgrep matches the pattern
|
# local-only inside a Dalamud plugin. Semgrep matches the pattern
|
||||||
# without dataflow, so it flags those eight call sites; CodeQL
|
# without dataflow, so it flags those eight call sites; CodeQL
|
||||||
# would not. Suppressed for this repo only.
|
# would not. Suppressed for this repo only.
|
||||||
semgrep-exclude-rules: "csharp.lang.security.sqli.csharp-sqli.csharp-sqli"
|
semgrep-exclude-rules: 'csharp.lang.security.sqli.csharp-sqli.csharp-sqli'
|
||||||
|
|||||||
@@ -1,73 +1,73 @@
|
|||||||
name: Bug report
|
name: Bug report
|
||||||
description: Something in HellionChat is broken or behaves wrong
|
description: Something in HellionChat is broken or behaves wrong
|
||||||
labels:
|
labels:
|
||||||
- bug
|
- bug
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Thanks for reporting. Please fill in the fields below so I can
|
Thanks for reporting. Please fill in the fields below so I can
|
||||||
reproduce the issue. If this is a security issue, stop here and
|
reproduce the issue. If this is a security issue, stop here and
|
||||||
report it privately to [kontakt@hellion-media.de](mailto:kontakt@hellion-media.de?subject=%5BHellionChat%20Security%5D)
|
report it privately to [kontakt@hellion-media.de](mailto:kontakt@hellion-media.de?subject=%5BHellionChat%20Security%5D)
|
||||||
instead.
|
instead.
|
||||||
|
|
||||||
- type: input
|
- type: input
|
||||||
id: version
|
id: version
|
||||||
attributes:
|
attributes:
|
||||||
label: HellionChat version
|
label: HellionChat version
|
||||||
description: From Settings → Information → Version
|
description: From Settings → Information → Version
|
||||||
placeholder: "0.5.4"
|
placeholder: '0.5.4'
|
||||||
validations:
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
id: platform
|
||||||
|
attributes:
|
||||||
|
label: Platform
|
||||||
|
options:
|
||||||
|
- Windows (XIVLauncher)
|
||||||
|
- Linux (XIVLauncher Core)
|
||||||
|
- macOS (XIVLauncher Core / wine)
|
||||||
|
- Other
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: what-happened
|
||||||
|
attributes:
|
||||||
|
label: What happened
|
||||||
|
description: Plain description, no log dumps yet
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: expected
|
||||||
|
attributes:
|
||||||
|
label: What you expected
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: steps
|
||||||
|
attributes:
|
||||||
|
label: How to reproduce
|
||||||
|
description: Step-by-step from "open settings" or "log in" through to the broken behaviour
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: log
|
||||||
|
attributes:
|
||||||
|
label: Relevant /xllog excerpt
|
||||||
|
description: Filter for "HellionChat" if the log is huge
|
||||||
|
render: text
|
||||||
|
|
||||||
|
- type: checkboxes
|
||||||
|
id: confirm
|
||||||
|
attributes:
|
||||||
|
label: Pre-flight
|
||||||
|
options:
|
||||||
|
- label: I am running the latest version of HellionChat
|
||||||
required: true
|
required: true
|
||||||
|
- label: I have searched existing issues for duplicates
|
||||||
- type: dropdown
|
|
||||||
id: platform
|
|
||||||
attributes:
|
|
||||||
label: Platform
|
|
||||||
options:
|
|
||||||
- Windows (XIVLauncher)
|
|
||||||
- Linux (XIVLauncher Core)
|
|
||||||
- macOS (XIVLauncher Core / wine)
|
|
||||||
- Other
|
|
||||||
validations:
|
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: what-happened
|
|
||||||
attributes:
|
|
||||||
label: What happened
|
|
||||||
description: Plain description, no log dumps yet
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: expected
|
|
||||||
attributes:
|
|
||||||
label: What you expected
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: steps
|
|
||||||
attributes:
|
|
||||||
label: How to reproduce
|
|
||||||
description: Step-by-step from "open settings" or "log in" through to the broken behaviour
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: log
|
|
||||||
attributes:
|
|
||||||
label: Relevant /xllog excerpt
|
|
||||||
description: Filter for "HellionChat" if the log is huge
|
|
||||||
render: text
|
|
||||||
|
|
||||||
- type: checkboxes
|
|
||||||
id: confirm
|
|
||||||
attributes:
|
|
||||||
label: Pre-flight
|
|
||||||
options:
|
|
||||||
- label: I am running the latest version of HellionChat
|
|
||||||
required: true
|
|
||||||
- label: I have searched existing issues for duplicates
|
|
||||||
required: true
|
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
|
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: Security vulnerability
|
- name: Security vulnerability
|
||||||
url: mailto:kontakt@hellion-media.de?subject=%5BHellionChat%20Security%5D
|
url: mailto:kontakt@hellion-media.de?subject=%5BHellionChat%20Security%5D
|
||||||
about: Do not open a public issue for security problems. Report by e-mail instead.
|
about: Do not open a public issue for security problems. Report by e-mail instead.
|
||||||
|
|
||||||
- name: Upstream Chat 2 issue
|
- name: Upstream Chat 2 issue
|
||||||
url: https://github.com/Infiziert90/ChatTwo/issues
|
url: https://github.com/Infiziert90/ChatTwo/issues
|
||||||
about:
|
about:
|
||||||
If the issue exists in upstream Chat 2 too, please report it there so the original maintainers see it as well.
|
If the issue exists in upstream Chat 2 too, please report it there so the original maintainers see it as well.
|
||||||
|
|
||||||
- name: Discord
|
- name: Discord
|
||||||
url: https://discord.com/users/j.j_kazama
|
url: https://discord.com/users/j.j_kazama
|
||||||
about: Quick questions, casual feedback. Bug reports still go through the issue tracker for tracking.
|
about: Quick questions, casual feedback. Bug reports still go through the issue tracker for tracking.
|
||||||
|
|||||||
@@ -1,57 +1,55 @@
|
|||||||
name: Feature request
|
name: Feature request
|
||||||
description: Suggest a feature or enhancement for HellionChat
|
description: Suggest a feature or enhancement for HellionChat
|
||||||
labels:
|
labels:
|
||||||
- enhancement
|
- enhancement
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Thanks for the suggestion. HellionChat focuses on privacy by
|
Thanks for the suggestion. HellionChat focuses on privacy by
|
||||||
default and a small, well-scoped feature set. Suggestions that
|
default and a small, well-scoped feature set. Suggestions that
|
||||||
align with that scope are easier to accept than ones that pull
|
align with that scope are easier to accept than ones that pull
|
||||||
the plugin toward "do everything".
|
the plugin toward "do everything".
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: problem
|
id: problem
|
||||||
attributes:
|
attributes:
|
||||||
label: What problem are you trying to solve
|
label: What problem are you trying to solve
|
||||||
description: The user-side problem, not the proposed solution yet
|
description: The user-side problem, not the proposed solution yet
|
||||||
validations:
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: solution
|
||||||
|
attributes:
|
||||||
|
label: What you would like HellionChat to do
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: alternatives
|
||||||
|
attributes:
|
||||||
|
label: Alternatives you have considered
|
||||||
|
description: Other plugins, manual workarounds, settings combinations
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
id: scope
|
||||||
|
attributes:
|
||||||
|
label: Scope estimate from your side
|
||||||
|
options:
|
||||||
|
- 'Small (one tab, one toggle, one filter)'
|
||||||
|
- 'Medium (a settings section, persistent state, one new file)'
|
||||||
|
- 'Large (architectural, touches the message pipeline or the database)'
|
||||||
|
- "I don't know"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: checkboxes
|
||||||
|
id: confirm
|
||||||
|
attributes:
|
||||||
|
label: Pre-flight
|
||||||
|
options:
|
||||||
|
- label: I have searched existing issues for similar requests
|
||||||
required: true
|
required: true
|
||||||
|
- label: I understand HellionChat is a privacy-focused fork and not a feature parity tool with upstream Chat 2
|
||||||
- type: textarea
|
|
||||||
id: solution
|
|
||||||
attributes:
|
|
||||||
label: What you would like HellionChat to do
|
|
||||||
validations:
|
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: alternatives
|
|
||||||
attributes:
|
|
||||||
label: Alternatives you have considered
|
|
||||||
description: Other plugins, manual workarounds, settings combinations
|
|
||||||
|
|
||||||
- type: dropdown
|
|
||||||
id: scope
|
|
||||||
attributes:
|
|
||||||
label: Scope estimate from your side
|
|
||||||
options:
|
|
||||||
- "Small (one tab, one toggle, one filter)"
|
|
||||||
- "Medium (a settings section, persistent state, one new file)"
|
|
||||||
- "Large (architectural, touches the message pipeline or the database)"
|
|
||||||
- "I don't know"
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: checkboxes
|
|
||||||
id: confirm
|
|
||||||
attributes:
|
|
||||||
label: Pre-flight
|
|
||||||
options:
|
|
||||||
- label: I have searched existing issues for similar requests
|
|
||||||
required: true
|
|
||||||
- label:
|
|
||||||
I understand HellionChat is a privacy-focused fork and not a feature parity tool with upstream Chat
|
|
||||||
2
|
|
||||||
required: true
|
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ mailto:kontakt@hellion-media.de?subject=%5BHellionChat%20Security%5D
|
|||||||
|
|
||||||
- [ ] Bug fix (non-breaking change that fixes an issue)
|
- [ ] Bug fix (non-breaking change that fixes an issue)
|
||||||
- [ ] New feature (non-breaking change that adds behaviour)
|
- [ ] New feature (non-breaking change that adds behaviour)
|
||||||
- [ ] Breaking change (config migration, removed feature, or behaviour change that user-visible defaults rely on)
|
- [ ] Breaking change (config migration, removed feature, or behaviour change that user-visible
|
||||||
|
defaults rely on)
|
||||||
- [ ] Documentation only
|
- [ ] Documentation only
|
||||||
- [ ] Translation update
|
- [ ] Translation update
|
||||||
- [ ] Build, CI or tooling change
|
- [ ] Build, CI or tooling change
|
||||||
@@ -55,10 +56,11 @@ new commands, new translations, removed behaviour. If none, write
|
|||||||
|
|
||||||
## Checklist
|
## Checklist
|
||||||
|
|
||||||
- [ ] I have read [CONTRIBUTING.md](../CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](../CODE_OF_CONDUCT.md).
|
- [ ] I have read [CONTRIBUTING.md](../CONTRIBUTING.md) and
|
||||||
|
[CODE_OF_CONDUCT.md](../CODE_OF_CONDUCT.md).
|
||||||
- [ ] My change matches the existing code style (`.editorconfig`).
|
- [ ] My change matches the existing code style (`.editorconfig`).
|
||||||
- [ ] I added or updated tests where the existing test infrastructure made that practical, or I have explained why tests
|
- [ ] I added or updated tests where the existing test infrastructure made that practical, or I have
|
||||||
are not applicable.
|
explained why tests are not applicable.
|
||||||
- [ ] I updated the README, in-plugin strings or documentation if my change is user-visible.
|
- [ ] I updated the README, in-plugin strings or documentation if my change is user-visible.
|
||||||
- [ ] I did not include any AI-generated code without disclosing it in the PR description (see
|
- [ ] I did not include any AI-generated code without disclosing it in the PR description (see
|
||||||
[AI_DISCLOSURE.md](../docs/AI_DISCLOSURE.md)).
|
[AI_DISCLOSURE.md](../docs/AI_DISCLOSURE.md)).
|
||||||
|
|||||||
+38
-38
@@ -1,42 +1,42 @@
|
|||||||
version: 2
|
version: 2
|
||||||
|
|
||||||
updates:
|
updates:
|
||||||
# NuGet package updates for the plugin project. Weekly cadence keeps the
|
# NuGet package updates for the plugin project. Weekly cadence keeps the
|
||||||
# noise down while still catching transitive security advisories within
|
# noise down while still catching transitive security advisories within
|
||||||
# a few days of disclosure.
|
# a few days of disclosure.
|
||||||
- package-ecosystem: nuget
|
- package-ecosystem: nuget
|
||||||
directory: /HellionChat
|
directory: /HellionChat
|
||||||
schedule:
|
schedule:
|
||||||
interval: weekly
|
interval: weekly
|
||||||
day: monday
|
day: monday
|
||||||
time: "07:00"
|
time: '07:00'
|
||||||
timezone: Europe/Berlin
|
timezone: Europe/Berlin
|
||||||
open-pull-requests-limit: 5
|
open-pull-requests-limit: 5
|
||||||
labels:
|
labels:
|
||||||
- dependencies
|
- dependencies
|
||||||
- nuget
|
- nuget
|
||||||
commit-message:
|
commit-message:
|
||||||
prefix: "chore(deps)"
|
prefix: 'chore(deps)'
|
||||||
groups:
|
groups:
|
||||||
patches:
|
patches:
|
||||||
update-types:
|
update-types:
|
||||||
- patch
|
- patch
|
||||||
minor:
|
minor:
|
||||||
update-types:
|
update-types:
|
||||||
- minor
|
- minor
|
||||||
|
|
||||||
# GitHub Actions versions in .github/workflows. Lower cadence because
|
# GitHub Actions versions in .github/workflows. Lower cadence because
|
||||||
# Action releases ship less frequently and are usually safe to defer
|
# Action releases ship less frequently and are usually safe to defer
|
||||||
# for a month.
|
# for a month.
|
||||||
- package-ecosystem: github-actions
|
- package-ecosystem: github-actions
|
||||||
directory: /
|
directory: /
|
||||||
schedule:
|
schedule:
|
||||||
interval: monthly
|
interval: monthly
|
||||||
time: "07:00"
|
time: '07:00'
|
||||||
timezone: Europe/Berlin
|
timezone: Europe/Berlin
|
||||||
open-pull-requests-limit: 3
|
open-pull-requests-limit: 3
|
||||||
labels:
|
labels:
|
||||||
- dependencies
|
- dependencies
|
||||||
- github-actions
|
- github-actions
|
||||||
commit-message:
|
commit-message:
|
||||||
prefix: "chore(actions)"
|
prefix: 'chore(actions)'
|
||||||
|
|||||||
@@ -3,15 +3,16 @@ subtitle: "Theme Foundation"
|
|||||||
versionsnatur: "Major-UI-Cycle"
|
versionsnatur: "Major-UI-Cycle"
|
||||||
---
|
---
|
||||||
|
|
||||||
- Theme-Engine mit fünf Built-In-Themes: Hellion Arctic (Default), Chat 2 Klassik, Event Horizon, Moonlit Bloom, Mint
|
- Theme-Engine mit fünf Built-In-Themes: Hellion Arctic (Default), Chat 2 Klassik, Event Horizon,
|
||||||
Grove
|
Moonlit Bloom, Mint Grove
|
||||||
- Settings öffnet jetzt eine Card-Grid-Übersicht — Klick auf eine Card führt in den Detail-View, Breadcrumb und ESC
|
- Settings öffnet jetzt eine Card-Grid-Übersicht — Klick auf eine Card führt in den Detail-View,
|
||||||
zurück zur Übersicht
|
Breadcrumb und ESC zurück zur Übersicht
|
||||||
- Themes-Tab mit Mini-Mockup pro Theme, Live-Switch beim Klick
|
- Themes-Tab mit Mini-Mockup pro Theme, Live-Switch beim Klick
|
||||||
- Eigene Themes als JSON in `pluginConfigs/HellionChat/themes/` — Beispiel-Vorlage wird beim ersten Start automatisch
|
- Eigene Themes als JSON in `pluginConfigs/HellionChat/themes/` — Beispiel-Vorlage wird beim ersten
|
||||||
abgelegt
|
Start automatisch abgelegt
|
||||||
- Optional pro Theme eigene Chat-Channel-Farben mit Übernehmen/Behalten-Banner — niemals automatisch überschrieben
|
- Optional pro Theme eigene Chat-Channel-Farben mit Übernehmen/Behalten-Banner — niemals automatisch
|
||||||
|
überschrieben
|
||||||
- Plugin-Icon zum Hellion-Forge-Hammer gewechselt
|
- Plugin-Icon zum Hellion-Forge-Hammer gewechselt
|
||||||
- Migration v13 → v14: alle User landen auf Hellion Arctic. Wer den Upstream-Look will, wählt Chat 2 Klassik in Settings
|
- Migration v13 → v14: alle User landen auf Hellion Arctic. Wer den Upstream-Look will, wählt Chat 2
|
||||||
→ Themes
|
Klassik in Settings → Themes
|
||||||
- Anleitung zum Schreiben eigener Themes: `docs/THEME-AUTHORING.md`
|
- Anleitung zum Schreiben eigener Themes: `docs/THEME-AUTHORING.md`
|
||||||
|
|||||||
@@ -3,22 +3,22 @@ subtitle: "Layout Refresh"
|
|||||||
versionsnatur: "Major-UI-Cycle"
|
versionsnatur: "Major-UI-Cycle"
|
||||||
---
|
---
|
||||||
|
|
||||||
- Sidebar im neuen Look: fix 44 px breit, nur Icons, Tab-Name als Tooltip beim Hover, vertikale Akzent-Pill markiert den
|
- Sidebar im neuen Look: fix 44 px breit, nur Icons, Tab-Name als Tooltip beim Hover, vertikale
|
||||||
aktiven Tab
|
Akzent-Pill markiert den aktiven Tab
|
||||||
- Top-Tabs bekommen eine Akzent-Underline statt Background-Fill am aktiven Tab
|
- Top-Tabs bekommen eine Akzent-Underline statt Background-Fill am aktiven Tab
|
||||||
- Pro Tab eigenes Icon wählbar in Einstellungen → Tabs (FontAwesome-Pool)
|
- Pro Tab eigenes Icon wählbar in Einstellungen → Tabs (FontAwesome-Pool)
|
||||||
- Auto-Tell-Tabs sind jetzt visuell unterscheidbar: jeder Tell-Partner bekommt ein eigenes Icon
|
- Auto-Tell-Tabs sind jetzt visuell unterscheidbar: jeder Tell-Partner bekommt ein eigenes Icon
|
||||||
(envelope/star/heart/bell/bookmark/flag/fire) plus eigene Farbe aus 12-Farb-Palette — 84 Kombinationen, gleicher
|
(envelope/star/heart/bell/bookmark/flag/fire) plus eigene Farbe aus 12-Farb-Palette — 84
|
||||||
Partner ergibt konsistent dieselbe
|
Kombinationen, gleicher Partner ergibt konsistent dieselbe
|
||||||
- Pulsierender roter Dot oben rechts am Sidebar-Icon zeigt ungelesene Nachrichten an. Sanft, 2-Sekunden-Cycle,
|
- Pulsierender roter Dot oben rechts am Sidebar-Icon zeigt ungelesene Nachrichten an. Sanft,
|
||||||
deaktivierbar über `Configuration.ReduceMotion` (UI-Toggle in v1.3.0)
|
2-Sekunden-Cycle, deaktivierbar über `Configuration.ReduceMotion` (UI-Toggle in v1.3.0)
|
||||||
- Bottom-Status-Bar (22 px) mit fünf Live-Slots: aktiver Channel + Color-Dot, Privacy-Badge, Tab/Message-Counter,
|
- Bottom-Status-Bar (22 px) mit fünf Live-Slots: aktiver Channel + Color-Dot, Privacy-Badge,
|
||||||
Auto-Tell-Counter, Plugin-Version. Update 1×/Sek
|
Tab/Message-Counter, Auto-Tell-Counter, Plugin-Version. Update 1×/Sek
|
||||||
- Card-Rows als Default-Message-Render: Sender-Header in Channel-Farbe, Body neue Zeile, dezenter Trenner.
|
- Card-Rows als Default-Message-Render: Sender-Header in Channel-Farbe, Body neue Zeile, dezenter
|
||||||
`Compact Density`-Toggle in Aussehen schaltet zurück auf den Einzeiler
|
Trenner. `Compact Density`-Toggle in Aussehen schaltet zurück auf den Einzeiler
|
||||||
- Bug-Fix: Settings speichern löscht den Chat-Verlauf nicht mehr. Refilter läuft jetzt nur wenn Filter-relevante
|
- Bug-Fix: Settings speichern löscht den Chat-Verlauf nicht mehr. Refilter läuft jetzt nur wenn
|
||||||
Settings geändert wurden — Cosmetic-Änderungen lassen den Chat unverändert. Persistente und Auto-Tell-Tabs überleben
|
Filter-relevante Settings geändert wurden — Cosmetic-Änderungen lassen den Chat unverändert.
|
||||||
beide
|
Persistente und Auto-Tell-Tabs überleben beide
|
||||||
- Bug-Fix: Hellion-Schrift (Exo 2) blockt die Schriftgröße nicht mehr — 4K-User können hochskalieren
|
- Bug-Fix: Hellion-Schrift (Exo 2) blockt die Schriftgröße nicht mehr — 4K-User können hochskalieren
|
||||||
- Migration v14 → v15: alte Theme-Felder entfernt, alle anderen Settings bleiben
|
- Migration v14 → v15: alte Theme-Felder entfernt, alle anderen Settings bleiben
|
||||||
|
|
||||||
|
|||||||
@@ -3,27 +3,31 @@ subtitle: "Settings Cleanup"
|
|||||||
versionsnatur: "UX-Polish-Cycle"
|
versionsnatur: "UX-Polish-Cycle"
|
||||||
---
|
---
|
||||||
|
|
||||||
- Settings-Übersicht thematisch re-sortiert: zusammenhängende Optionen wohnen jetzt zusammen, jede Card hat einen kurzen
|
- Settings-Übersicht thematisch re-sortiert: zusammenhängende Optionen wohnen jetzt zusammen, jede
|
||||||
Untertitel — kein Raten mehr wo eine Setting steckt
|
Card hat einen kurzen Untertitel — kein Raten mehr wo eine Setting steckt
|
||||||
- Drei neue Cards: **Theme & Layout** (Theme-Picker, Fenster-Style, Zeitstempel-Style), **Schriften & Farben**
|
- Drei neue Cards: **Theme & Layout** (Theme-Picker, Fenster-Style, Zeitstempel-Style), **Schriften
|
||||||
(Schriftart, Schriftgröße, Chat-Farben pro Channel), **Daten-Verwaltung** (Aufbewahrung, Cleanup, Export, DB-Viewer,
|
& Farben** (Schriftart, Schriftgröße, Chat-Farben pro Channel), **Daten-Verwaltung**
|
||||||
Advanced-Tools — vorher zwischen Datenschutz und Datenbank verteilt)
|
(Aufbewahrung, Cleanup, Export, DB-Viewer, Advanced-Tools — vorher zwischen Datenschutz und
|
||||||
|
Datenbank verteilt)
|
||||||
- Datenschutz fokussiert sich jetzt auf eine Aufgabe: den Privacy-Filter
|
- Datenschutz fokussiert sich jetzt auf eine Aufgabe: den Privacy-Filter
|
||||||
- Der Auto-Tell-Tabs-History-Preload-Slider ist von Datenschutz nach Chat → Auto-Tell-Tabs umgezogen
|
- Der Auto-Tell-Tabs-History-Preload-Slider ist von Datenschutz nach Chat → Auto-Tell-Tabs umgezogen
|
||||||
- KeybindMode wohnt jetzt unter Allgemein → Eingabe statt unter Sprache
|
- KeybindMode wohnt jetzt unter Allgemein → Eingabe statt unter Sprache
|
||||||
- Vier tote Schema-Felder entfernt (alle obsolet seit der Theme-Engine in v1.1.0): `Stilüberschreiben`-Toggle,
|
- Vier tote Schema-Felder entfernt (alle obsolet seit der Theme-Engine in v1.1.0):
|
||||||
`Stilname`-Auswahl, alter `WindowAlpha`-Slider, ungenutztes `ShowThemeQuickPicker`
|
`Stilüberschreiben`-Toggle, `Stilname`-Auswahl, alter `WindowAlpha`-Slider, ungenutztes
|
||||||
|
`ShowThemeQuickPicker`
|
||||||
- Migration v15 → v16: alter `WindowAlpha`-Wert wird automatisch nach
|
- Migration v15 → v16: alter `WindowAlpha`-Wert wird automatisch nach
|
||||||
`Theme & Layout → Fenster-Style → Fenster-Transparenz` gemappt (nur wenn der Slider noch auf Default 0.85 stand, sonst
|
`Theme & Layout → Fenster-Style → Fenster-Transparenz` gemappt (nur wenn der Slider noch auf
|
||||||
gewinnt der User-Wert). Backup der Pre-v16-Config liegt unter `pluginConfigs/HellionChat.json.pre-v16-backup`. User
|
Default 0.85 stand, sonst gewinnt der User-Wert). Backup der Pre-v16-Config liegt unter
|
||||||
die `Stilüberschreiben` aktiv hatten sehen einen einmaligen Hinweis-Toast
|
`pluginConfigs/HellionChat.json.pre-v16-backup`. User die `Stilüberschreiben` aktiv hatten sehen
|
||||||
- UX-Default-Bumps für Bestand-User mit Default-Werten: Card-Rows-Layout zurück auf Single-Line, NG+ standardmäßig
|
einen einmaligen Hinweis-Toast
|
||||||
hidden, gleiche Zeitstempel werden zusammengefasst, MaxLinesToRender auf konservativere 2500
|
- UX-Default-Bumps für Bestand-User mit Default-Werten: Card-Rows-Layout zurück auf Single-Line, NG+
|
||||||
- Frische Installs starten mit dem Hellion-Brand-Chat-Color-Preset out-of-the-box (der First-Run-Wizard hat keine
|
standardmäßig hidden, gleiche Zeitstempel werden zusammengefasst, MaxLinesToRender auf
|
||||||
Preset-Wahl)
|
konservativere 2500
|
||||||
- Hinweis zum Window-Transparenz-Slider in der Beschreibung: Dalamud's per-Window-Hamburger-Menü (oben rechts in der
|
- Frische Installs starten mit dem Hellion-Brand-Chat-Color-Preset out-of-the-box (der
|
||||||
Titelleiste) bietet eigene Overrides für Deckkraft, Hintergrund-Blur, Anpinnen und Durchklick — die haben Vorrang über
|
First-Run-Wizard hat keine Preset-Wahl)
|
||||||
unseren Slider für das jeweilige Fenster
|
- Hinweis zum Window-Transparenz-Slider in der Beschreibung: Dalamud's per-Window-Hamburger-Menü
|
||||||
|
(oben rechts in der Titelleiste) bietet eigene Overrides für Deckkraft, Hintergrund-Blur, Anpinnen
|
||||||
|
und Durchklick — die haben Vorrang über unseren Slider für das jeweilige Fenster
|
||||||
|
|
||||||
Pure UX-Polish, keine neuen Features. Nächster Cycle (v1.3.0): Animation-Polish (Lerps, Theme-Crossfade, Quick-Picker)
|
Pure UX-Polish, keine neuen Features. Nächster Cycle (v1.3.0): Animation-Polish (Lerps,
|
||||||
wie ursprünglich geplant.
|
Theme-Crossfade, Quick-Picker) wie ursprünglich geplant.
|
||||||
|
|||||||
@@ -3,21 +3,23 @@ subtitle: "Theme Expansion"
|
|||||||
versionsnatur: "Theme-Pack-Patch"
|
versionsnatur: "Theme-Pack-Patch"
|
||||||
---
|
---
|
||||||
|
|
||||||
- Vier neue Built-in-Themes verlängern die Auswahl im Picker — keine Engine-Änderung, keine Settings angefasst, einfach
|
- Vier neue Built-in-Themes verlängern die Auswahl im Picker — keine Engine-Änderung, keine Settings
|
||||||
mehr Farboptionen
|
angefasst, einfach mehr Farboptionen
|
||||||
- **Night Blue** — Royal Blue auf tiefem Marineblau. Kühles Tech-Dashboard-Mood, bewusst neutral gehalten damit es sich
|
- **Night Blue** — Royal Blue auf tiefem Marineblau. Kühles Tech-Dashboard-Mood, bewusst neutral
|
||||||
nicht mit den Brand-Themes beißt
|
gehalten damit es sich nicht mit den Brand-Themes beißt
|
||||||
- **Indigo Violet** — Royal Violet auf Deep Indigo mit Türkis-Mint-Counter für Aurora-Glitter-Stimmung. Schwester von
|
- **Indigo Violet** — Royal Violet auf Deep Indigo mit Türkis-Mint-Counter für
|
||||||
Event Horizon, aber dunkler und dichter; der Türkis-Akzent hält die beiden klar auseinander
|
Aurora-Glitter-Stimmung. Schwester von Event Horizon, aber dunkler und dichter; der Türkis-Akzent
|
||||||
- **Forge Merchantman** — Patina-Bronze auf Workshop-Slate mit warmem Bernstein-Counter. Hellion Forge bekommt ein
|
hält die beiden klar auseinander
|
||||||
eigenes Theme im Plugin selbst — Schwester von Hellion Arctic, aber grüner und wärmer statt kaltem Cyan
|
- **Forge Merchantman** — Patina-Bronze auf Workshop-Slate mit warmem Bernstein-Counter. Hellion
|
||||||
|
Forge bekommt ein eigenes Theme im Plugin selbst — Schwester von Hellion Arctic, aber grüner und
|
||||||
|
wärmer statt kaltem Cyan
|
||||||
- **Hellion Spectrum** — Farbenblind-sichere Channel-Farben (Deuteranopie/Protanopie) auf Basis der
|
- **Hellion Spectrum** — Farbenblind-sichere Channel-Farben (Deuteranopie/Protanopie) auf Basis der
|
||||||
Wong/Okabe-Ito-Palette. Channel-Identität bleibt erhalten (Tell pink, Yell gelb, Shout orange, Party blau, FC grün);
|
Wong/Okabe-Ito-Palette. Channel-Identität bleibt erhalten (Tell pink, Yell gelb, Shout orange,
|
||||||
die Töne sind so gewählt dass jeder Channel auch unter Rot-Grün-Schwäche klar trennbar bleibt. Deckt rund 99 % aller
|
Party blau, FC grün); die Töne sind so gewählt dass jeder Channel auch unter Rot-Grün-Schwäche
|
||||||
CVD-Fälle ab
|
klar trennbar bleibt. Deckt rund 99 % aller CVD-Fälle ab
|
||||||
- Kein Schema-Bump, keine Migration. Das Default-Theme bleibt **Hellion Arctic**, eigene Custom-Themes laufen
|
- Kein Schema-Bump, keine Migration. Das Default-Theme bleibt **Hellion Arctic**, eigene
|
||||||
unverändert weiter
|
Custom-Themes laufen unverändert weiter
|
||||||
- Theme-Katalog wächst damit von fünf auf neun Built-ins
|
- Theme-Katalog wächst damit von fünf auf neun Built-ins
|
||||||
|
|
||||||
Reines Theme-Pack zwischen v1.2.1 und dem nächsten Polish-Cycle. Eine Tritan-Variante (Spectrum für Blau-Gelb-Schwäche)
|
Reines Theme-Pack zwischen v1.2.1 und dem nächsten Polish-Cycle. Eine Tritan-Variante (Spectrum für
|
||||||
kann später nachgeliefert werden, falls Bedarf kommt.
|
Blau-Gelb-Schwäche) kann später nachgeliefert werden, falls Bedarf kommt.
|
||||||
|
|||||||
@@ -4,15 +4,17 @@ versionsnatur: "Plugin-Integration-Cycle 1"
|
|||||||
---
|
---
|
||||||
|
|
||||||
- Erste Plugin-Integration eingebaut, Cycle 1 von 6 auf der Roadmap
|
- Erste Plugin-Integration eingebaut, Cycle 1 von 6 auf der Roadmap
|
||||||
- **Honorific-Custom-Titles im Chat-Header** — der Titel den du in Honorific gesetzt hast erscheint jetzt links über dem
|
- **Honorific-Custom-Titles im Chat-Header** — der Titel den du in Honorific gesetzt hast erscheint
|
||||||
Message-Log mit der von dir gewählten Farbe, Auto-Hide wenn Honorific nicht installiert ist oder kein Custom-Titel
|
jetzt links über dem Message-Log mit der von dir gewählten Farbe, Auto-Hide wenn Honorific nicht
|
||||||
aktiv ist
|
installiert ist oder kein Custom-Titel aktiv ist
|
||||||
- **Krone-Icon plus Tooltip** vor dem Titel-Text, damit klar ist woher der Slot kommt ohne dass der User raten muss
|
- **Krone-Icon plus Tooltip** vor dem Titel-Text, damit klar ist woher der Slot kommt ohne dass der
|
||||||
- **Neuer Integrations-Settings-Tab** mit Status-Indikator (erkannt, nicht installiert, inkompatibel) und Toggle. Plus
|
User raten muss
|
||||||
Vorschau-Block der die fünf weiteren geplanten Cycles ankündigt: Kontextmenü-Aktionen, Smart Notifications
|
- **Neuer Integrations-Settings-Tab** mit Status-Indikator (erkannt, nicht installiert,
|
||||||
(NotificationMaster), RP-Status-Block (Moodles und LightlessClient), ExtraChat-Channels, Quick-DM-Button
|
inkompatibel) und Toggle. Plus Vorschau-Block der die fünf weiteren geplanten Cycles ankündigt:
|
||||||
(XIVInstantMessenger)
|
Kontextmenü-Aktionen, Smart Notifications (NotificationMaster), RP-Status-Block (Moodles und
|
||||||
- **Maintainer-Attribution** im Tab als Höflichkeits-Geste, zwei Buttons zum Honorific-Repo und zum Caraxi-Profil. Plus
|
LightlessClient), ExtraChat-Channels, Quick-DM-Button (XIVInstantMessenger)
|
||||||
Hellion-Forge-Discord-Button für Community-Vorschläge zu künftigen Integrationen
|
- **Maintainer-Attribution** im Tab als Höflichkeits-Geste, zwei Buttons zum Honorific-Repo und zum
|
||||||
- Keine Migration, keine Schema-Änderung. Wer Honorific eh schon nutzt sieht den Custom-Titel automatisch sobald
|
Caraxi-Profil. Plus Hellion-Forge-Discord-Button für Community-Vorschläge zu künftigen
|
||||||
HellionChat aktualisiert
|
Integrationen
|
||||||
|
- Keine Migration, keine Schema-Änderung. Wer Honorific eh schon nutzt sieht den Custom-Titel
|
||||||
|
automatisch sobald HellionChat aktualisiert
|
||||||
|
|||||||
@@ -5,19 +5,20 @@ versionsnatur: Stability-Hotfix
|
|||||||
|
|
||||||
**Hellion Chat 1.4.0 — Critical Lifecycle Fixes**
|
**Hellion Chat 1.4.0 — Critical Lifecycle Fixes**
|
||||||
|
|
||||||
Erster Sub-Patch der v1.4.x Polish-Sweep-Serie. Sieben bekannte Lifecycle- und Race-Bugs aus den Audit-Pässen
|
Erster Sub-Patch der v1.4.x Polish-Sweep-Serie. Sieben bekannte Lifecycle- und Race-Bugs aus den
|
||||||
abgearbeitet, bevor Performance- und Architektur-Refactors draufkommen.
|
Audit-Pässen abgearbeitet, bevor Performance- und Architektur-Refactors draufkommen.
|
||||||
|
|
||||||
- **SQLite-Dispose** lehnt sich nicht mehr an GC-Druck zur Datei-Freigabe an, Pooling=false auf der Connection macht den
|
- **SQLite-Dispose** lehnt sich nicht mehr an GC-Druck zur Datei-Freigabe an, Pooling=false auf der
|
||||||
manuellen GC.Collect überflüssig
|
Connection macht den manuellen GC.Collect überflüssig
|
||||||
- **Worker-Threads** (PendingMessage, RetentionSweep) sind jetzt explizit IsBackground=true, das Plugin-Domain kann
|
- **Worker-Threads** (PendingMessage, RetentionSweep) sind jetzt explizit IsBackground=true, das
|
||||||
sauber unloaden bei XIVLauncher-Reload ohne darauf zu warten
|
Plugin-Domain kann sauber unloaden bei XIVLauncher-Reload ohne darauf zu warten
|
||||||
- **EmoteCache-Loader** von async-void auf async-Task mit shared Task-Tracker, drain-on-Dispose. Kein Schreib-Risiko
|
- **EmoteCache-Loader** von async-void auf async-Task mit shared Task-Tracker, drain-on-Dispose.
|
||||||
mehr auf disposed EmoteImages-Einträge nach Plugin-Reload
|
Kein Schreib-Risiko mehr auf disposed EmoteImages-Einträge nach Plugin-Reload
|
||||||
- **DisposeAsync-Timeout** (10s) warnt jetzt laut statt silent zu failen
|
- **DisposeAsync-Timeout** (10s) warnt jetzt laut statt silent zu failen
|
||||||
- **Plugin-Dispose** flushed pending DeferredSave bevor Services abgebaut werden, Settings-Änderungen aus den letzten
|
- **Plugin-Dispose** flushed pending DeferredSave bevor Services abgebaut werden,
|
||||||
Frames vor Disable überleben jetzt zuverlässig
|
Settings-Änderungen aus den letzten Frames vor Disable überleben jetzt zuverlässig
|
||||||
- **v13→v14 Config-Migration** liest pre-v13-Backup und überträgt HellionThemeWindowOpacity in das neue
|
- **v13→v14 Config-Migration** liest pre-v13-Backup und überträgt HellionThemeWindowOpacity in das
|
||||||
WindowOpacity-Feld statt auf 0.85 zurückzufallen
|
neue WindowOpacity-Feld statt auf 0.85 zurückzufallen
|
||||||
|
|
||||||
Keine Schema-Bumps, keine User-sichtbaren Funktions-Änderungen außer dass Reload und Shutdown spürbar sauberer laufen.
|
Keine Schema-Bumps, keine User-sichtbaren Funktions-Änderungen außer dass Reload und Shutdown
|
||||||
|
spürbar sauberer laufen.
|
||||||
|
|||||||
@@ -5,23 +5,25 @@ versionsnatur: Performance-Patch
|
|||||||
|
|
||||||
**Hellion Chat 1.4.1 — Theme Engine Performance**
|
**Hellion Chat 1.4.1 — Theme Engine Performance**
|
||||||
|
|
||||||
Zweiter Sub-Patch der v1.4.x Polish-Sweep-Serie. Heap-Pressure aus dem Theme-Engine-Render-Pfad eliminiert,
|
Zweiter Sub-Patch der v1.4.x Polish-Sweep-Serie. Heap-Pressure aus dem Theme-Engine-Render-Pfad
|
||||||
Custom-Theme- Hot-Reload überlebt transiente File-Locks beim Editor-Save. Plus zehnter Built-In und überarbeitete
|
eliminiert, Custom-Theme- Hot-Reload überlebt transiente File-Locks beim Editor-Save. Plus zehnter
|
||||||
Author-Credits.
|
Built-In und überarbeitete Author-Credits.
|
||||||
|
|
||||||
- **ABGR-Cache auf den Theme-Records.** Beim Theme-Register (Built-In oder Custom) werden alle Color-Slots einmalig in
|
- **ABGR-Cache auf den Theme-Records.** Beim Theme-Register (Built-In oder Custom) werden alle
|
||||||
ABGR-Pack-Form vor-konvertiert. HellionStyle.PushGlobal liest aus dem Cache statt pro Slot pro Frame durch
|
Color-Slots einmalig in ABGR-Pack-Form vor-konvertiert. HellionStyle.PushGlobal liest aus dem
|
||||||
ColourUtil.RgbaToAbgr zu jagen. Real gemessene Frame-Time-Recovery: **~13 %** in typischer Render-Szene
|
Cache statt pro Slot pro Frame durch ColourUtil.RgbaToAbgr zu jagen. Real gemessene
|
||||||
(Plan-Erwartung war 2-6 % konservativ, real ~10-15 %)
|
Frame-Time-Recovery: **~13 %** in typischer Render-Szene (Plan-Erwartung war 2-6 % konservativ,
|
||||||
- **Custom-Theme File-Lock-Härtung.** Wenn der User ein Theme-JSON gerade speichert während HellionChat reloaden will,
|
real ~10-15 %)
|
||||||
fängt der Loader jetzt explizit Sharing-Violation und Lock-Violation ab. Last-Known-Good-Snapshot bleibt im Picker,
|
- **Custom-Theme File-Lock-Härtung.** Wenn der User ein Theme-JSON gerade speichert während
|
||||||
beim nächsten Tick wird automatisch retry'd — vorher fiel das Theme aus der Liste bis zum Plugin-Reload
|
HellionChat reloaden will, fängt der Loader jetzt explizit Sharing-Violation und Lock-Violation
|
||||||
- **Defensive Cache-Refresh beim Theme-Switch.** Falls ein Theme auf einem alten Pfad ohne Cache-Fill in den Speicher
|
ab. Last-Known-Good-Snapshot bleibt im Picker, beim nächsten Tick wird automatisch retry'd —
|
||||||
gekommen ist, holt Switch() das beim Anwenden nach
|
vorher fiel das Theme aus der Liste bis zum Plugin-Reload
|
||||||
- **Synthwave Sunset als zehnter Built-In.** Hot Magenta + Cyan auf Mitternachts-Violett, 80s-Neon-Grid-Vibes für
|
- **Defensive Cache-Refresh beim Theme-Switch.** Falls ein Theme auf einem alten Pfad ohne
|
||||||
Late-Night-Raids
|
Cache-Fill in den Speicher gekommen ist, holt Switch() das beim Anwenden nach
|
||||||
- **Author-Credits konsolidiert.** Brand-Themes laufen jetzt unter „Hellion Forge". Mint Grove und Forge Merchantman
|
- **Synthwave Sunset als zehnter Built-In.** Hot Magenta + Cyan auf Mitternachts-Violett,
|
||||||
werden Carla Beleandis als Community-Geste zugeschrieben.
|
80s-Neon-Grid-Vibes für Late-Night-Raids
|
||||||
|
- **Author-Credits konsolidiert.** Brand-Themes laufen jetzt unter „Hellion Forge". Mint Grove und
|
||||||
|
Forge Merchantman werden Carla Beleandis als Community-Geste zugeschrieben.
|
||||||
|
|
||||||
Keine Schema-Bumps, keine User-sichtbaren Funktions- Änderungen außer dass die Frames in Theme-getrieben rendernden
|
Keine Schema-Bumps, keine User-sichtbaren Funktions- Änderungen außer dass die Frames in
|
||||||
Szenen merklich glatter laufen und ein neues Theme im Picker steht.
|
Theme-getrieben rendernden Szenen merklich glatter laufen und ein neues Theme im Picker steht.
|
||||||
|
|||||||
@@ -3,34 +3,25 @@ subtitle: Symbol-Picker und Tell-History Fix
|
|||||||
versionsnatur: Feature-Patch + Hotfix
|
versionsnatur: Feature-Patch + Hotfix
|
||||||
---
|
---
|
||||||
|
|
||||||
- Symbol-Picker im Chat-Eingang: ein kleiner Smile-Button links neben
|
- Symbol-Picker im Chat-Eingang: ein kleiner Smile-Button links neben dem Kanal-Indikator öffnet ein
|
||||||
dem Kanal-Indikator öffnet ein Popup mit zwei Tabs. Der erste listet
|
Popup mit zwei Tabs. Der erste listet alle 161 FFXIV-PUA-Glyphen (Dalamuds SeIconChar); der zweite
|
||||||
alle 161 FFXIV-PUA-Glyphen (Dalamuds SeIconChar); der zweite trägt
|
trägt 97 verifizierte BMP-Symbole (Latin-Marken, Währungen, das ganze griechische Alphabet,
|
||||||
97 verifizierte BMP-Symbole (Latin-Marken, Währungen, das ganze
|
Geometrie, Spielkarten, Noten) — jedes davon über `/echo` und `/say` in einer vierrundigen
|
||||||
griechische Alphabet, Geometrie, Spielkarten, Noten) — jedes davon
|
Whitelist-Probe durchgereicht, damit der Channel-Render dem entspricht, was der Picker anzeigt.
|
||||||
über `/echo` und `/say` in einer vierrundigen Whitelist-Probe
|
Klick fügt das Symbol an der Cursor-Position ein, Multi-Insert lässt das Popup offen, eine
|
||||||
durchgereicht, damit der Channel-Render dem entspricht, was der
|
Recent-Used-Leiste zeigt die letzten sechzehn Picks über beide Tabs. Toggle in Settings → Chat →
|
||||||
Picker anzeigt. Klick fügt das Symbol an der Cursor-Position ein,
|
Nachrichten-Verhalten, Default an.
|
||||||
Multi-Insert lässt das Popup offen, eine Recent-Used-Leiste zeigt
|
- Verlauf in angepinnten Tell-Tabs lädt wieder vollständig: ein versteckter 500-Zeilen-Scan-Cap in
|
||||||
die letzten sechzehn Picks über beide Tabs. Toggle in Settings →
|
PreloadHistory hat das User-Setting `AutoTellTabsHistoryPreload` überschrieben, wodurch
|
||||||
Chat → Nachrichten-Verhalten, Default an.
|
weniger-frequente Tell-Partner ihren Backlog verloren haben sobald die Scan-Schicht mit anderen
|
||||||
- Verlauf in angepinnten Tell-Tabs lädt wieder vollständig: ein
|
Chat-Partnern voll lief. Cap ist raus, der Index auf `(Receiver, Date)` hält die Query schnell.
|
||||||
versteckter 500-Zeilen-Scan-Cap in PreloadHistory hat das
|
- Slash-Command-Teardown: /hellion, /hellionView, /hellionDebugger (und im Debug-Build
|
||||||
User-Setting `AutoTellTabsHistoryPreload` überschrieben, wodurch
|
/hellionSeString) sind als private Felder gecached. Plugin-Dispose detached die echte
|
||||||
weniger-frequente Tell-Partner ihren Backlog verloren haben sobald
|
Registrierung, statt mit identischen Args neu zu registrieren — schließt eine latente
|
||||||
die Scan-Schicht mit anderen Chat-Partnern voll lief. Cap ist raus,
|
|
||||||
der Index auf `(Receiver, Date)` hält die Query schnell.
|
|
||||||
- Slash-Command-Teardown: /hellion, /hellionView, /hellionDebugger
|
|
||||||
(und im Debug-Build /hellionSeString) sind als private Felder
|
|
||||||
gecached. Plugin-Dispose detached die echte Registrierung, statt
|
|
||||||
mit identischen Args neu zu registrieren — schließt eine latente
|
|
||||||
Wartungs-Falle aus v1.4.9.
|
Wartungs-Falle aus v1.4.9.
|
||||||
- v1.4.x-Polish-Sweep endet hier. Der ImGuiListClipper-Refactor von
|
- v1.4.x-Polish-Sweep endet hier. Der ImGuiListClipper-Refactor von der v1.4.10-Reserve-Liste wurde
|
||||||
der v1.4.10-Reserve-Liste wurde gecancelt, nachdem der Cross-
|
gecancelt, nachdem der Cross- Plattform-Smoke gezeigt hat dass das Scroll-Gummi ein Wine/Linux-
|
||||||
Plattform-Smoke gezeigt hat dass das Scroll-Gummi ein Wine/Linux-
|
Quirk ist — Windows-User haben es nie gesehen. Spike dafür kommt in einem späteren Patch. Nächster
|
||||||
Quirk ist — Windows-User haben es nie gesehen. Spike dafür kommt in
|
Major-Cycle ist v1.5.0 mit der DI-Container-Adoption (`Microsoft.Extensions.Hosting` +
|
||||||
einem späteren Patch. Nächster Major-Cycle ist v1.5.0 mit der
|
|
||||||
DI-Container-Adoption (`Microsoft.Extensions.Hosting` +
|
|
||||||
`ILogger<T>`) nach dem Lightless-Vorbild.
|
`ILogger<T>`) nach dem Lightless-Vorbild.
|
||||||
- Migration v17 unverändert: kein Schema-Bump, kein
|
- Migration v17 unverändert: kein Schema-Bump, kein Config-Migrations-Aufwand.
|
||||||
Config-Migrations-Aufwand.
|
|
||||||
|
|||||||
@@ -5,25 +5,27 @@ versionsnatur: Performance-Patch
|
|||||||
|
|
||||||
**Hellion Chat 1.4.2 — ChatLog Frame-Hot-Path**
|
**Hellion Chat 1.4.2 — ChatLog Frame-Hot-Path**
|
||||||
|
|
||||||
Dritter Sub-Patch der v1.4.x Polish-Sweep-Serie. Drei Per-Frame-Allokations-Quellen aus dem ChatLogWindow-Render- Pfad
|
Dritter Sub-Patch der v1.4.x Polish-Sweep-Serie. Drei Per-Frame-Allokations-Quellen aus dem
|
||||||
und der Settings-StatusBar eliminiert.
|
ChatLogWindow-Render- Pfad und der Settings-StatusBar eliminiert.
|
||||||
|
|
||||||
- **Card-Mode-Border-Loop entlastet.** DrawMessages hebt Theme, DrawList, Window-Left, Window-Right und die ABGR-
|
- **Card-Mode-Border-Loop entlastet.** DrawMessages hebt Theme, DrawList, Window-Left, Window-Right
|
||||||
Border-Color einmalig vor den Per-Message-Loop. Bei 100 sichtbaren Messages sind das gut 500 redundante P/Invokes und
|
und die ABGR- Border-Color einmalig vor den Per-Message-Loop. Bei 100 sichtbaren Messages sind das
|
||||||
Property-Reads, die der Hoist eliminiert. Pop-Out- Heavy-Setups (mehrere parallele Chat-Windows) profitieren
|
gut 500 redundante P/Invokes und Property-Reads, die der Hoist eliminiert. Pop-Out- Heavy-Setups
|
||||||
proportional, weil der Hoist pro DrawMessages-Call greift, also pro Window
|
(mehrere parallele Chat-Windows) profitieren proportional, weil der Hoist pro DrawMessages-Call
|
||||||
- **Auto-Tell Tab-Tint und Icon gecached.** Die Hash-Color- Berechnung für Auto-Tell-Tabs lief pro Tab pro Frame, mit
|
greift, also pro Window
|
||||||
zwei String-Allokationen pro Tab (eine für Tint-Hash, eine für Icon-Hash). Der neue TabTintCache liest pre-computed
|
- **Auto-Tell Tab-Tint und Icon gecached.** Die Hash-Color- Berechnung für Auto-Tell-Tabs lief pro
|
||||||
Werte aus dem Tab und rechnet nur neu wenn das Tell-Target drifted. Beide Caches haben separate Validation-Keys, also
|
Tab pro Frame, mit zwei String-Allokationen pro Tab (eine für Tint-Hash, eine für Icon-Hash). Der
|
||||||
keine Cross-Invalidation zwischen Tint- und Icon-Pfad. AutoTellTabTint selbst bleibt pure Hash-Helper, weiterhin ohne
|
neue TabTintCache liest pre-computed Werte aus dem Tab und rechnet nur neu wenn das Tell-Target
|
||||||
Tab-Awareness
|
drifted. Beide Caches haben separate Validation-Keys, also keine Cross-Invalidation zwischen Tint-
|
||||||
- **StatusBar-Aggregation hinter Cache-Gate.** Die Status- Leiste am unteren Window-Rand summiert die Tab-Message-
|
und Icon-Pfad. AutoTellTabTint selbst bleibt pure Hash-Helper, weiterhin ohne Tab-Awareness
|
||||||
Counts und zählt die Auto-Tell-Tabs pro Frame. Der Cache- Gate (1 Sekunde) lag bisher hinter den LINQ-Pfaden, also
|
- **StatusBar-Aggregation hinter Cache-Gate.** Die Status- Leiste am unteren Window-Rand summiert
|
||||||
liefen Sum und Count trotzdem pro Frame. Jetzt vor dem Gate, plus die LINQ-Pfade durch eine Single-Pass-Foreach
|
die Tab-Message- Counts und zählt die Auto-Tell-Tabs pro Frame. Der Cache- Gate (1 Sekunde) lag
|
||||||
ersetzt. Die Aggregation läuft auf etwa 1 % der Frames
|
bisher hinter den LINQ-Pfaden, also liefen Sum und Count trotzdem pro Frame. Jetzt vor dem Gate,
|
||||||
|
plus die LINQ-Pfade durch eine Single-Pass-Foreach ersetzt. Die Aggregation läuft auf etwa 1 % der
|
||||||
|
Frames
|
||||||
|
|
||||||
Realistische Frame-Time-Recovery: 2-5 % in typischen Szenen, Pop-Out-Heavy-Setups potenziell mehr durch die Card-Border-
|
Realistische Frame-Time-Recovery: 2-5 % in typischen Szenen, Pop-Out-Heavy-Setups potenziell mehr
|
||||||
Multiplikation pro Window.
|
durch die Card-Border- Multiplikation pro Window.
|
||||||
|
|
||||||
Keine Schema-Bumps, keine User-sichtbaren Funktions- Änderungen außer dass die Frames im Chat-Log und in der
|
Keine Schema-Bumps, keine User-sichtbaren Funktions- Änderungen außer dass die Frames im Chat-Log
|
||||||
Settings-Statusleiste merklich glatter laufen.
|
und in der Settings-Statusleiste merklich glatter laufen.
|
||||||
|
|||||||
@@ -5,25 +5,29 @@ versionsnatur: Architecture-Refactor
|
|||||||
|
|
||||||
**Hellion Chat 1.4.3 — Plugin-Load Async-Init + Repo-Cutover**
|
**Hellion Chat 1.4.3 — Plugin-Load Async-Init + Repo-Cutover**
|
||||||
|
|
||||||
Vierter Sub-Patch der v1.4.x Polish-Sweep-Serie. Plugin- Lifecycle auf Dalamud's `IAsyncDalamudPlugin`-API migriert und
|
Vierter Sub-Patch der v1.4.x Polish-Sweep-Serie. Plugin- Lifecycle auf Dalamud's
|
||||||
das Custom-Repo zieht von GitHub auf Gitea um.
|
`IAsyncDalamudPlugin`-API migriert und das Custom-Repo zieht von GitHub auf Gitea um.
|
||||||
|
|
||||||
- **Async-Plugin-Architektur.** Konstruktor übernimmt nur noch die Bootstrap-Essentials (Config-Load, Language-Init,
|
- **Async-Plugin-Architektur.** Konstruktor übernimmt nur noch die Bootstrap-Essentials
|
||||||
Conflict-Detection). Migrationen, Service-Allokationen, Window-Konstruktion und Hook-Subscription wandern in
|
(Config-Load, Language-Init, Conflict-Detection). Migrationen, Service-Allokationen,
|
||||||
LoadAsync, sodass Dalamud die UI während der schweren Arbeit responsive halten kann. Per-Line-CaptureFailure in
|
Window-Konstruktion und Hook-Subscription wandern in LoadAsync, sodass Dalamud die UI während der
|
||||||
DisposeAsync mirrort LightlessSync's Pattern, plus Idempotency-Guard gegen Reload-Races
|
schweren Arbeit responsive halten kann. Per-Line-CaptureFailure in DisposeAsync mirrort
|
||||||
- **Custom-Repo-URL umgezogen auf Gitea.** Bestehende Tester müssen einmalig in XIVLauncher die Custom-Repo-URL auf
|
LightlessSync's Pattern, plus Idempotency-Guard gegen Reload-Races
|
||||||
`https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/raw/branch/main/repo.json` umstellen, dann
|
- **Custom-Repo-URL umgezogen auf Gitea.** Bestehende Tester müssen einmalig in XIVLauncher die
|
||||||
XIVLauncher neu starten. Das alte GitHub-Repo bleibt als eingefrorener v1.4.2-Snapshot stehen und wird nicht mehr
|
Custom-Repo-URL auf
|
||||||
aktualisiert
|
`https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/raw/branch/main/repo.json`
|
||||||
- **Schema-Gate statt Migrations-Kette.** Die v9 → v16 Migrationen sind raus, ersetzt durch einen harten Schema-Check in
|
umstellen, dann XIVLauncher neu starten. Das alte GitHub-Repo bleibt als eingefrorener
|
||||||
Phase 1. Configs auf Schema v16+ laden direkt; ältere Configs (vor v1.2.1) bekommen jetzt eine klare „install v1.4.2
|
v1.4.2-Snapshot stehen und wird nicht mehr aktualisiert
|
||||||
first"-Fehlermeldung statt eines impliziten Migrations-Pfads
|
- **Schema-Gate statt Migrations-Kette.** Die v9 → v16 Migrationen sind raus, ersetzt durch einen
|
||||||
- **AutoTranslate-Cache läuft im Hintergrund.** Der Cache füllt sich jetzt fire-and-forget statt blockierend im
|
harten Schema-Check in Phase 1. Configs auf Schema v16+ laden direkt; ältere Configs (vor v1.2.1)
|
||||||
Plugin-Load. Trade-off: die erste Auto-Translate-Nutzung einer Session kann einen kurzen Hitch haben, dafür kein
|
bekommen jetzt eine klare „install v1.4.2 first"-Fehlermeldung statt eines impliziten
|
||||||
300-ms-Block beim Plugin-Start
|
Migrations-Pfads
|
||||||
- **Plugin-Load-Zeit ehrlich.** Median 3,7 s über fünf Reloads, vergleichbar mit v1.4.2. Der Async-Refactor ist
|
- **AutoTranslate-Cache läuft im Hintergrund.** Der Cache füllt sich jetzt fire-and-forget statt
|
||||||
Foundation für künftige Lazy-Init-Optimierungen (v1.4.4) und Code-Architektur-Hygiene, kein direkter User-spürbarer
|
blockierend im Plugin-Load. Trade-off: die erste Auto-Translate-Nutzung einer Session kann einen
|
||||||
Speed-Win in dieser Release
|
kurzen Hitch haben, dafür kein 300-ms-Block beim Plugin-Start
|
||||||
|
- **Plugin-Load-Zeit ehrlich.** Median 3,7 s über fünf Reloads, vergleichbar mit v1.4.2. Der
|
||||||
|
Async-Refactor ist Foundation für künftige Lazy-Init-Optimierungen (v1.4.4) und
|
||||||
|
Code-Architektur-Hygiene, kein direkter User-spürbarer Speed-Win in dieser Release
|
||||||
|
|
||||||
Keine User-sichtbaren Funktions-Änderungen außer dem Repo-URL-Update. Settings, Themes und Tabs bleiben unangetastet.
|
Keine User-sichtbaren Funktions-Änderungen außer dem Repo-URL-Update. Settings, Themes und Tabs
|
||||||
|
bleiben unangetastet.
|
||||||
|
|||||||
@@ -5,30 +5,33 @@ versionsnatur: Wartung und Robustheit
|
|||||||
|
|
||||||
**Hellion Chat 1.4.4 — Threading- und IPC-Sicherheits-Politur**
|
**Hellion Chat 1.4.4 — Threading- und IPC-Sicherheits-Politur**
|
||||||
|
|
||||||
Fünfter Sub-Patch der v1.4.x Polish-Sweep-Serie. Threading-Annahmen werden explizit pro Methode dokumentiert, ein
|
Fünfter Sub-Patch der v1.4.x Polish-Sweep-Serie. Threading-Annahmen werden explizit pro Methode
|
||||||
Hot-Path-Lock im Auto-Tell-Tab-Counter fällt weg, IPC-Cleanup wird sichtbar wenn er fehlschlägt und der Privacy-Filter
|
dokumentiert, ein Hot-Path-Lock im Auto-Tell-Tab-Counter fällt weg, IPC-Cleanup wird sichtbar wenn
|
||||||
spricht jetzt bei unbekannten ChatTypes.
|
er fehlschlägt und der Privacy-Filter spricht jetzt bei unbekannten ChatTypes.
|
||||||
|
|
||||||
- **AutoTellTabsService Hot-Path-Lock entfernt.** `ActiveTempTabCount` hat bisher pro Render-Frame ein LINQ-Count unter
|
- **AutoTellTabsService Hot-Path-Lock entfernt.** `ActiveTempTabCount` hat bisher pro Render-Frame
|
||||||
einem Lock gemacht. Jetzt läuft das über einen Interlocked-Counter der parallel zur Tabs-Liste mitgeführt wird,
|
ein LINQ-Count unter einem Lock gemacht. Jetzt läuft das über einen Interlocked-Counter der
|
||||||
inklusive Resync-Hook für den Snapshot-Restore-Pfad in `SaveConfig`. Plus Pure-Helper-Test-Mirror in der Build-Suite
|
parallel zur Tabs-Liste mitgeführt wird, inklusive Resync-Hook für den Snapshot-Restore-Pfad in
|
||||||
damit die Atomicity-Semantik nicht versehentlich wegrefactored wird
|
`SaveConfig`. Plus Pure-Helper-Test-Mirror in der Build-Suite damit die Atomicity-Semantik nicht
|
||||||
- **HonorificService selbst-dokumentierende Threading-Banner.** Statt eines Block-Comments am Klassen-Ende hat jede
|
versehentlich wegrefactored wird
|
||||||
IPC-Callback-Methode jetzt einen 1-Zeilen-Banner darüber, der den Thread-Kontext direkt am Call-Site benennt
|
- **HonorificService selbst-dokumentierende Threading-Banner.** Statt eines Block-Comments am
|
||||||
(framework only, framework scheduled, any). Mehr Hilfe für künftige Reviews als ein abstraktes Threading-Kapitel
|
Klassen-Ende hat jede IPC-Callback-Methode jetzt einen 1-Zeilen-Banner darüber, der den
|
||||||
- **Unsubscribe-Failure ist jetzt sichtbar.** `TryUnsubscribe` hat ein Honorific-Unsubscribe-Failure bisher als Debug
|
Thread-Kontext direkt am Call-Site benennt (framework only, framework scheduled, any). Mehr Hilfe
|
||||||
geloggt, was bei Standard-Loglevel verschluckt wurde. Eine geleakte Subscription kann den Service über Plugin-Reloads
|
für künftige Reviews als ein abstraktes Threading-Kapitel
|
||||||
hinweg leben lassen, also läuft der Log jetzt auf Warning
|
- **Unsubscribe-Failure ist jetzt sichtbar.** `TryUnsubscribe` hat ein Honorific-Unsubscribe-Failure
|
||||||
- **AutoTranslate-Warmup blockiert den Plugin-Unload nicht mehr.** Der Cache-Warmup-Thread war ohne `IsBackground=true`
|
bisher als Debug geloggt, was bei Standard-Loglevel verschluckt wurde. Eine geleakte Subscription
|
||||||
unterwegs, was den Unload um 100-300 ms verzögern konnte. Pattern-Match zu MessageManager und RetentionSweep (beide
|
kann den Service über Plugin-Reloads hinweg leben lassen, also läuft der Log jetzt auf Warning
|
||||||
seit v1.4.0)
|
- **AutoTranslate-Warmup blockiert den Plugin-Unload nicht mehr.** Der Cache-Warmup-Thread war ohne
|
||||||
- **Privacy-Filter loggt unbekannte ChatTypes.** Wenn FFXIV durch einen Patch einen neuen ChatType einführt der weder in
|
`IsBackground=true` unterwegs, was den Unload um 100-300 ms verzögern konnte. Pattern-Match zu
|
||||||
der Whitelist noch in den Defaults steht, wird er bisher silent durch den Failsafe geleitet. Jetzt loggt der Filter
|
MessageManager und RetentionSweep (beide seit v1.4.0)
|
||||||
einmalig pro Runtime eine Warning mit dem Type und dem Failsafe-Wert. Dedup über ein NonSerialized-HashSet, also kein
|
- **Privacy-Filter loggt unbekannte ChatTypes.** Wenn FFXIV durch einen Patch einen neuen ChatType
|
||||||
Log-Spam
|
einführt der weder in der Whitelist noch in den Defaults steht, wird er bisher silent durch den
|
||||||
- **Default-Flip für neue Installationen.** `PrivacyPersistUnknownChannels` startet bei neuen Configs jetzt auf `true`,
|
Failsafe geleitet. Jetzt loggt der Filter einmalig pro Runtime eine Warning mit dem Type und dem
|
||||||
damit ein Patch-bedingt neuer ChatType nicht stillschweigend gedroppt wird bevor der User entscheiden kann. Bestehende
|
Failsafe-Wert. Dedup über ein NonSerialized-HashSet, also kein Log-Spam
|
||||||
Configs behalten ihre Wahl, weil der Deserializer den Initializer überschreibt. Keine Migration, kein Schema-Bump
|
- **Default-Flip für neue Installationen.** `PrivacyPersistUnknownChannels` startet bei neuen
|
||||||
|
Configs jetzt auf `true`, damit ein Patch-bedingt neuer ChatType nicht stillschweigend gedroppt
|
||||||
|
wird bevor der User entscheiden kann. Bestehende Configs behalten ihre Wahl, weil der Deserializer
|
||||||
|
den Initializer überschreibt. Keine Migration, kein Schema-Bump
|
||||||
|
|
||||||
Keine User-sichtbaren Funktions-Änderungen außer dem Default-Flip für neue Installationen. Settings, Themes, Tabs und
|
Keine User-sichtbaren Funktions-Änderungen außer dem Default-Flip für neue Installationen. Settings,
|
||||||
das Privacy-Verhalten für Bestand bleiben unangetastet.
|
Themes, Tabs und das Privacy-Verhalten für Bestand bleiben unangetastet.
|
||||||
|
|||||||
@@ -5,24 +5,27 @@ versionsnatur: UX-Polish-Cycle
|
|||||||
|
|
||||||
**Hellion Chat 1.4.5 — UX und Robustheit**
|
**Hellion Chat 1.4.5 — UX und Robustheit**
|
||||||
|
|
||||||
Sechster Sub-Patch der v1.4.x Polish-Sweep-Serie. Render-Fehler im Chat-Fenster werden jetzt sichtbar, der
|
Sechster Sub-Patch der v1.4.x Polish-Sweep-Serie. Render-Fehler im Chat-Fenster werden jetzt
|
||||||
First-Run-Wizard hat eine explizite Cancel-Schaltfläche, der Eingabe-Verlauf bleibt nicht mehr über Plugin-Reloads
|
sichtbar, der First-Run-Wizard hat eine explizite Cancel-Schaltfläche, der Eingabe-Verlauf bleibt
|
||||||
hinweg liegen, und die Statusleiste klippt in schmalen Fenstern nicht mehr.
|
nicht mehr über Plugin-Reloads hinweg liegen, und die Statusleiste klippt in schmalen Fenstern nicht
|
||||||
|
mehr.
|
||||||
|
|
||||||
- **Fehler-Benachrichtigung im Chat-Fenster.** Wenn ein Render-Fehler in `DrawChatLog` auftritt, zeigt das Plugin jetzt
|
- **Fehler-Benachrichtigung im Chat-Fenster.** Wenn ein Render-Fehler in `DrawChatLog` auftritt,
|
||||||
eine einmalige Warning-Notification mit Verweis aufs `/xllog`, statt das Fenster stillschweigend leer zu lassen. Der
|
zeigt das Plugin jetzt eine einmalige Warning-Notification mit Verweis aufs `/xllog`, statt das
|
||||||
Stack-Trace selbst geht weiter via `Plugin.Log.Error` ins Logfile. De-Dup über Per-Session-Bool, damit ein
|
Fenster stillschweigend leer zu lassen. Der Stack-Trace selbst geht weiter via `Plugin.Log.Error`
|
||||||
wiederkehrender Fehler die Notification-Stack nicht pro Frame neu vollkippt
|
ins Logfile. De-Dup über Per-Session-Bool, damit ein wiederkehrender Fehler die Notification-Stack
|
||||||
- **First-Run-Wizard trennt Accept und Close.** `OnClose` setzt nicht mehr stillschweigend `FirstRunCompleted=true`,
|
nicht pro Frame neu vollkippt
|
||||||
also lässt das X den Wizard schwebend zurück und er kommt beim nächsten Plugin-Reload wieder. Eine neue „Später —
|
- **First-Run-Wizard trennt Accept und Close.** `OnClose` setzt nicht mehr stillschweigend
|
||||||
Defaults behalten"-Schaltfläche im Footer ist der explizite Weg, ohne Profil-Auswahl rauszukommen. Strings bilingual
|
`FirstRunCompleted=true`, also lässt das X den Wizard schwebend zurück und er kommt beim nächsten
|
||||||
EN+DE plus Tooltip
|
Plugin-Reload wieder. Eine neue „Später — Defaults behalten"-Schaltfläche im Footer ist der
|
||||||
- **Eingabe-Verlauf wird beim Plugin-Reload geleert.** `InputHistoryService.Reset` hängt jetzt in `Plugin.DisposeAsync`
|
explizite Weg, ohne Profil-Auswahl rauszukommen. Strings bilingual EN+DE plus Tooltip
|
||||||
neben den anderen Pure-Memory-Cleanups, damit der statische Zustand aus der vorigen Session den nächsten Load nicht
|
- **Eingabe-Verlauf wird beim Plugin-Reload geleert.** `InputHistoryService.Reset` hängt jetzt in
|
||||||
mehr erbt
|
`Plugin.DisposeAsync` neben den anderen Pure-Memory-Cleanups, damit der statische Zustand aus der
|
||||||
- **Statusleiste klippt nicht mehr.** Der rechtsbündige Versions-Slot wird ausgeblendet wenn die Chat-Window-Breite
|
vorigen Session den nächsten Load nicht mehr erbt
|
||||||
abzüglich Versions-Text unter 200 px fällt — vorher überlappte er die vier linken Slots. Ab ausreichender Breite
|
- **Statusleiste klippt nicht mehr.** Der rechtsbündige Versions-Slot wird ausgeblendet wenn die
|
||||||
taucht der Slot wieder auf
|
Chat-Window-Breite abzüglich Versions-Text unter 200 px fällt — vorher überlappte er die vier
|
||||||
- **Intern:** `FontManager` fällt auf System-Font zurück wenn die eingebettete Hellion-Font-Resource fehlt
|
linken Slots. Ab ausreichender Breite taucht der Slot wieder auf
|
||||||
(Broken-csproj-Pfad, nie ein Produktions-Build), plus expliziter Session-Only-Invariant-Kommentar für Auto-Tell-Tabs
|
- **Intern:** `FontManager` fällt auf System-Font zurück wenn die eingebettete Hellion-Font-Resource
|
||||||
in `Plugin.cs:167-168` mit einem TempTabCounter-Init-Pin in der Build-Suite. Kein Schema-Bump, keine Migration
|
fehlt (Broken-csproj-Pfad, nie ein Produktions-Build), plus expliziter
|
||||||
|
Session-Only-Invariant-Kommentar für Auto-Tell-Tabs in `Plugin.cs:167-168` mit einem
|
||||||
|
TempTabCounter-Init-Pin in der Build-Suite. Kein Schema-Bump, keine Migration
|
||||||
|
|||||||
@@ -3,31 +3,34 @@ subtitle: Code Hygiene and Refactor
|
|||||||
versionsnatur: Maintenance-Cycle
|
versionsnatur: Maintenance-Cycle
|
||||||
---
|
---
|
||||||
|
|
||||||
Wartungs-Patch ohne User-sichtbare Änderungen. Saubere Code-Basis als Vorbereitung auf das v1.4.7-Backlog-Cleanup, plus
|
Wartungs-Patch ohne User-sichtbare Änderungen. Saubere Code-Basis als Vorbereitung auf das
|
||||||
zwei geerbte Bugfixes aus dem ChatTwo-Upstream `f35b7d3`.
|
v1.4.7-Backlog-Cleanup, plus zwei geerbte Bugfixes aus dem ChatTwo-Upstream `f35b7d3`.
|
||||||
|
|
||||||
- **preflight.sh härter**: csharpier-Reflow-Check (Block E) und markdownlint (Block F) laufen jetzt im Pre-Push-Gate,
|
- **preflight.sh härter**: csharpier-Reflow-Check (Block E) und markdownlint (Block F) laufen jetzt
|
||||||
statt erst beim Pre-Merge-Review aufzufallen.
|
im Pre-Push-Gate, statt erst beim Pre-Merge-Review aufzufallen.
|
||||||
- **FontManager-Fallback robuster**: Atlas-Toolkit-Throws aus kaputten Font-Configs (IO, InvalidOperation,
|
- **FontManager-Fallback robuster**: Atlas-Toolkit-Throws aus kaputten Font-Configs (IO,
|
||||||
ArgumentException) fallen jetzt zuverlässig auf NotoSansCjkRegular, statt den Atlas-Build mitzureißen. Der
|
InvalidOperation, ArgumentException) fallen jetzt zuverlässig auf NotoSansCjkRegular, statt den
|
||||||
Exception-Typ wird im Log mitgegeben für die Diagnose.
|
Atlas-Build mitzureißen. Der Exception-Typ wird im Log mitgegeben für die Diagnose.
|
||||||
- **URL-Validation beim Plugin-Load**: BrandingLinks (5 URLs) und IntegrationLinks (2 URLs) werden via
|
- **URL-Validation beim Plugin-Load**: BrandingLinks (5 URLs) und IntegrationLinks (2 URLs) werden
|
||||||
`[ModuleInitializer]` geprüft. Ein Tippfehler bei einer künftigen URL-Rotation wirft jetzt sofort beim Plugin-Load,
|
via `[ModuleInitializer]` geprüft. Ein Tippfehler bei einer künftigen URL-Rotation wirft jetzt
|
||||||
statt still beim Klick zu scheitern.
|
sofort beim Plugin-Load, statt still beim Klick zu scheitern.
|
||||||
- **Cherry-Pick aus ChatTwo `f35b7d3`** — Memory-Leak in `Chat.SetChannel`: der native `Utf8String` wird jetzt auch dann
|
- **Cherry-Pick aus ChatTwo `f35b7d3`** — Memory-Leak in `Chat.SetChannel`: der native `Utf8String`
|
||||||
freigegeben, wenn der Linkshell-Check den Channel ablehnt (vorher gefangen im early-return).
|
wird jetzt auch dann freigegeben, wenn der Linkshell-Check den Channel ablehnt (vorher gefangen im
|
||||||
- **Cherry-Pick aus ChatTwo `f35b7d3`** — `Tab.Clone()` Deep-cloned jetzt `UsedChannel` und `TellTarget`. Vorher
|
early-return).
|
||||||
Reference-Share-Bug: PopOut- und Temp-Tabs mutierten sich gegenseitig.
|
- **Cherry-Pick aus ChatTwo `f35b7d3`** — `Tab.Clone()` Deep-cloned jetzt `UsedChannel` und
|
||||||
|
`TellTarget`. Vorher Reference-Share-Bug: PopOut- und Temp-Tabs mutierten sich gegenseitig.
|
||||||
- **Aktive-Tab-Underline pixel-perfect bei DPI-Scaling**: Die Underline-Pill skaliert jetzt mit
|
- **Aktive-Tab-Underline pixel-perfect bei DPI-Scaling**: Die Underline-Pill skaliert jetzt mit
|
||||||
`ImGuiHelpers.GlobalScale` und rundet die DrawList-Koordinaten auf physische Pixel. Kein Sub-Pixel-Blur mehr auf
|
`ImGuiHelpers.GlobalScale` und rundet die DrawList-Koordinaten auf physische Pixel. Kein
|
||||||
125/150%-Setups.
|
Sub-Pixel-Blur mehr auf 125/150%-Setups.
|
||||||
- **IconButton-Width-Fix**: der manuelle `width - 2 * CellPadding.X`-Subtract verlor den HUD-Scale (Padding skaliert,
|
- **IconButton-Width-Fix**: der manuelle `width - 2 * CellPadding.X`-Subtract verlor den HUD-Scale
|
||||||
der raw int nicht). Gemessene Breite läuft jetzt unverändert durch.
|
(Padding skaliert, der raw int nicht). Gemessene Breite läuft jetzt unverändert durch.
|
||||||
- **Test-Isolation für MessageStore**: `Dalamud.Utility.Util`-Surface (IsWine, OpenLink) läuft jetzt durch eine
|
- **Test-Isolation für MessageStore**: `Dalamud.Utility.Util`-Surface (IsWine, OpenLink) läuft jetzt
|
||||||
`IPlatformUtil`-Indirektion. MessageStores `IsWine`-Probe ist isoliert testbar in der Build-Suite. Plus:
|
durch eine `IPlatformUtil`-Indirektion. MessageStores `IsWine`-Probe ist isoliert testbar in der
|
||||||
HellionStyle-ChildBgAlpha als Pure-Helper extrahiert, Plugin.SaveConfig kopiert nur Session-Tabs statt der ganzen
|
Build-Suite. Plus: HellionStyle-ChildBgAlpha als Pure-Helper extrahiert, Plugin.SaveConfig kopiert
|
||||||
Tab-Liste, SettingsOverview cached den DrawList einmal pro Frame.
|
nur Session-Tabs statt der ganzen Tab-Liste, SettingsOverview cached den DrawList einmal pro
|
||||||
- **Built-in-Theme-Roster**: Crystal Nocturne (Royal Sapphire + Electric Magenta auf Obsidian, von CRYSTALLITE) ersetzt
|
Frame.
|
||||||
Moonlit Bloom. User mit Moonlit Bloom als aktivem Theme fallen beim ersten Plugin-Load auf Hellion Arctic zurück.
|
- **Built-in-Theme-Roster**: Crystal Nocturne (Royal Sapphire + Electric Magenta auf Obsidian, von
|
||||||
|
CRYSTALLITE) ersetzt Moonlit Bloom. User mit Moonlit Bloom als aktivem Theme fallen beim ersten
|
||||||
|
Plugin-Load auf Hellion Arctic zurück.
|
||||||
|
|
||||||
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
||||||
|
|||||||
@@ -3,27 +3,31 @@ subtitle: Backlog Cleanup and Mid-Features
|
|||||||
versionsnatur: Mid-Feature-Patch
|
versionsnatur: Mid-Feature-Patch
|
||||||
---
|
---
|
||||||
|
|
||||||
Achter Sub-Patch der v1.4.x Polish-Sweep-Serie. Erstes User-sichtbares Feature-Bundle seit v1.4.5 — angepinnte Tell-Tabs
|
Achter Sub-Patch der v1.4.x Polish-Sweep-Serie. Erstes User-sichtbares Feature-Bundle seit v1.4.5 —
|
||||||
die Relog überleben, opt-in Honorific-Glow, plus eine konfigurierbare Sidebar.
|
angepinnte Tell-Tabs die Relog überleben, opt-in Honorific-Glow, plus eine konfigurierbare Sidebar.
|
||||||
|
|
||||||
- **TempTell anpinnen**: Rechtsklick auf einen TempTell-Tab in der Sidebar → „Tab anpinnen". Angepinnte Tabs überleben
|
- **TempTell anpinnen**: Rechtsklick auf einen TempTell-Tab in der Sidebar → „Tab anpinnen".
|
||||||
Plugin-Reload und Char-Logout, behalten ihre Konversations-Historie (wird beim Rehydrate aus dem MessageStore
|
Angepinnte Tabs überleben Plugin-Reload und Char-Logout, behalten ihre Konversations-Historie
|
||||||
nachgeladen) und bleiben an die gleiche /tell-Person gebunden. Hard-Cap 5 angepinnte Tabs in einem separaten Pool —
|
(wird beim Rehydrate aus dem MessageStore nachgeladen) und bleiben an die gleiche /tell-Person
|
||||||
die normalen Auto-Tell-Tabs (15er Cap) sind davon entkoppelt, Gesamt-Decke 20. Die Sidebar gruppiert angepinnte Tabs
|
gebunden. Hard-Cap 5 angepinnte Tabs in einem separaten Pool — die normalen Auto-Tell-Tabs (15er
|
||||||
in einer eigenen „Angepinnt"-Sektion mit eigenem Trenner.
|
Cap) sind davon entkoppelt, Gesamt-Decke 20. Die Sidebar gruppiert angepinnte Tabs in einer
|
||||||
- **Honorific Glow-Outline**: rendert jetzt eine 8-Richtungs-DrawList-Outline wenn der Honorific-Titel eine Glow-Farbe
|
eigenen „Angepinnt"-Sektion mit eigenem Trenner.
|
||||||
trägt. Opt-in via **Settings → Integrationen → Glow-Outline rendern (Honorific)** (Default OFF). Gradient (Color3 /
|
- **Honorific Glow-Outline**: rendert jetzt eine 8-Richtungs-DrawList-Outline wenn der
|
||||||
GradientColourSet / Wave / Pulse) wird geparst und im DTO weitergereicht, rendert aktuell aber statisch als
|
Honorific-Titel eine Glow-Farbe trägt. Opt-in via **Settings → Integrationen → Glow-Outline
|
||||||
Primärfarbe — der volle Gradient-Port (Animations-Algorithmus + Pride-Palette) kommt als eigener Cycle nach.
|
rendern (Honorific)** (Default OFF). Gradient (Color3 / GradientColourSet / Wave / Pulse) wird
|
||||||
- **Sidebar-Breite konfigurierbar**: in **Theme & Layout** ein Slider 44–160 px. Default bleibt 44 px (icon-only), aber
|
geparst und im DTO weitergereicht, rendert aktuell aber statisch als Primärfarbe — der volle
|
||||||
breiter machen damit Sektion-Header wie „Aktive Tells (3)" oder „Angepinnt (2)" nicht abgeschnitten werden.
|
Gradient-Port (Animations-Algorithmus + Pride-Palette) kommt als eigener Cycle nach.
|
||||||
- **Settings-Save Channel-Fix**: ein Save mit aktivem Party- oder Linkshell-Tab konnte den Chat-Input zurück auf
|
- **Sidebar-Breite konfigurierbar**: in **Theme & Layout** ein Slider 44–160 px. Default bleibt 44
|
||||||
`/tell <angepinnte Person>` springen lassen. `Configuration.UpdateFrom` bewahrt jetzt den Runtime-`CurrentChannel`
|
px (icon-only), aber breiter machen damit Sektion-Header wie „Aktive Tells (3)" oder „Angepinnt
|
||||||
über den persistent-Tab-Merge hinweg, und `TabSwitched` deep-cloned den Seed-Channel statt sich den `UsedChannel` mit
|
(2)" nicht abgeschnitten werden.
|
||||||
dem vorigen Tab zu teilen.
|
- **Settings-Save Channel-Fix**: ein Save mit aktivem Party- oder Linkshell-Tab konnte den
|
||||||
- **Internal**: `IPluginLogProxy`-Indirektion vor Dalamud's `IPluginLog` über alle ~91 `Plugin.Log`-Call-Sites. Damit
|
Chat-Input zurück auf `/tell <angepinnte Person>` springen lassen. `Configuration.UpdateFrom`
|
||||||
läuft `MessageStore.Migrate0` voll-isoliert in xUnit (F12.1-Lücke aus v1.4.6 geschlossen). Plus: TempTab-Counter als
|
bewahrt jetzt den Runtime-`CurrentChannel` über den persistent-Tab-Merge hinweg, und `TabSwitched`
|
||||||
abgeleitete Property statt gecachtes Interlocked-Feld — die neuen Pin/Unpin-Übergänge sind Cold-Path, kein
|
deep-cloned den Seed-Channel statt sich den `UsedChannel` mit dem vorigen Tab zu teilen.
|
||||||
Lock-Free-Vorteil mehr. Migration v16 → v17 ist rein additiv (neues `Tab.IsPinned`-Bool, Default false).
|
- **Internal**: `IPluginLogProxy`-Indirektion vor Dalamud's `IPluginLog` über alle ~91
|
||||||
|
`Plugin.Log`-Call-Sites. Damit läuft `MessageStore.Migrate0` voll-isoliert in xUnit (F12.1-Lücke
|
||||||
|
aus v1.4.6 geschlossen). Plus: TempTab-Counter als abgeleitete Property statt gecachtes
|
||||||
|
Interlocked-Feld — die neuen Pin/Unpin-Übergänge sind Cold-Path, kein Lock-Free-Vorteil mehr.
|
||||||
|
Migration v16 → v17 ist rein additiv (neues `Tab.IsPinned`-Bool, Default false).
|
||||||
|
|
||||||
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
||||||
|
|||||||
@@ -3,19 +3,17 @@ subtitle: Hook-Layer und Polish-Quick-Wins
|
|||||||
versionsnatur: Polish-Patch
|
versionsnatur: Polish-Patch
|
||||||
---
|
---
|
||||||
|
|
||||||
- DbViewer Volltext-Suche: optionaler FTS5-Index über die ganze Chat-Historie.
|
- DbViewer Volltext-Suche: optionaler FTS5-Index über die ganze Chat-Historie. Wird beim ersten
|
||||||
Wird beim ersten v1.4.8-Start asynchron im Hintergrund gebaut, Progress als
|
v1.4.8-Start asynchron im Hintergrund gebaut, Progress als Toast. Lokale Page-Suche bleibt
|
||||||
Toast. Lokale Page-Suche bleibt Default. Such-Eingaben werden als exakte
|
Default. Such-Eingaben werden als exakte Wortfolge gematcht; mehrere Wörter werden nur gefunden,
|
||||||
Wortfolge gematcht; mehrere Wörter werden nur gefunden, wenn sie zusammen
|
wenn sie zusammen und in der Reihenfolge stehen. Wer rohe FTS5-MATCH-Syntax nutzen will, setzt
|
||||||
und in der Reihenfolge stehen. Wer rohe FTS5-MATCH-Syntax nutzen will, setzt
|
|
||||||
eigene Anführungszeichen um den Suchbegriff.
|
eigene Anführungszeichen um den Suchbegriff.
|
||||||
- Custom-Theme-Files laden sich beim Speichern automatisch neu, wenn das Theme
|
- Custom-Theme-Files laden sich beim Speichern automatisch neu, wenn das Theme aktiv ist. Kein
|
||||||
aktiv ist. Kein Picker-Klick mehr nötig.
|
Picker-Klick mehr nötig.
|
||||||
- Retention-Sweep blockt nicht mehr den Framework-Thread. Der Mini-Hitch von
|
- Retention-Sweep blockt nicht mehr den Framework-Thread. Der Mini-Hitch von ~194ms pro Sweep ist
|
||||||
~194ms pro Sweep ist weg.
|
weg.
|
||||||
- Statusleiste rendert sauber bei Windows-Skalierung über 100%.
|
- Statusleiste rendert sauber bei Windows-Skalierung über 100%.
|
||||||
- Receive-Suppressed-Tells-Routing wurde in diesem Cycle untersucht und auf
|
- Receive-Suppressed-Tells-Routing wurde in diesem Cycle untersucht und auf v1.5.x verschoben: wenn
|
||||||
v1.5.x verschoben: wenn andere Plugins Tells via CheckMessageHandled
|
andere Plugins Tells via CheckMessageHandled unterdrücken, überspringt FFXIVs Chat-Pipeline den
|
||||||
unterdrücken, überspringt FFXIVs Chat-Pipeline den RaptureLogModule-Resolver
|
RaptureLogModule-Resolver und HellionChats Tab-Routing verliert den Tell-Partner. Der Fix liegt
|
||||||
und HellionChats Tab-Routing verliert den Tell-Partner. Der Fix liegt
|
|
||||||
architektonisch neben dem geplanten Ad-Block-Hook-Layer und kommt dort mit.
|
architektonisch neben dem geplanten Ad-Block-Hook-Layer und kommt dort mit.
|
||||||
|
|||||||
@@ -3,35 +3,26 @@ subtitle: Plugin-Load Render Polish
|
|||||||
versionsnatur: Performance-Patch
|
versionsnatur: Performance-Patch
|
||||||
---
|
---
|
||||||
|
|
||||||
- First-Frame-HITCH unter 100 ms: der erste Render-Frame des Plugins liegt
|
- First-Frame-HITCH unter 100 ms: der erste Render-Frame des Plugins liegt jetzt bei ~76 ms Median
|
||||||
jetzt bei ~76 ms Median (vorher ~127 ms), die Dalamud-Warnung
|
(vorher ~127 ms), die Dalamud-Warnung „UiBuilder(Hellion Chat) > 100ms" beim Plugin-Start ist
|
||||||
„UiBuilder(Hellion Chat) > 100ms" beim Plugin-Start ist damit weg.
|
damit weg. Erreicht durch das Verlagern von sechs nicht-essentiellen Render- Sektionen
|
||||||
Erreicht durch das Verlagern von sechs nicht-essentiellen Render-
|
(Statusleiste, Kanalname-Chunks, Fenster-Bounds-Check, Hinweis-Banner, Autocomplete,
|
||||||
Sektionen (Statusleiste, Kanalname-Chunks, Fenster-Bounds-Check,
|
Input-Preview) auf den zweiten Frame. Bei 60 fps sieht man die deferred-Sektionen ~17 ms später,
|
||||||
Hinweis-Banner, Autocomplete, Input-Preview) auf den zweiten Frame.
|
was im Atlas-Build-Fenster nach einem Reload unsichtbar bleibt.
|
||||||
Bei 60 fps sieht man die deferred-Sektionen ~17 ms später, was im
|
- Slash-Commands zentral registriert: /hellion, /hellionView, /hellionSeString und /hellionDebugger
|
||||||
Atlas-Build-Fenster nach einem Reload unsichtbar bleibt.
|
werden jetzt im Plugin-Load zentral registriert statt erst beim ersten Öffnen ihres Ziel-Fensters.
|
||||||
- Slash-Commands zentral registriert: /hellion, /hellionView,
|
Heißt: die Befehle funktionieren ab dem ersten Tick, auch wenn das jeweilige Fenster nie geöffnet
|
||||||
/hellionSeString und /hellionDebugger werden jetzt im Plugin-Load zentral
|
wurde. Der „Einstellungen"-Button im Plugin-Manager hängt am selben Pfad.
|
||||||
registriert statt erst beim ersten Öffnen ihres Ziel-Fensters. Heißt: die
|
- Plugin-Load-Diagnose-Logs als Tripwire: die Profiling-Logs für MessageStore.Connect,
|
||||||
Befehle funktionieren ab dem ersten Tick, auch wenn das jeweilige Fenster
|
MessageStore.Migrate, FilterAllTabs und den Auto-Translate-Warmup bleiben auf Information-Level
|
||||||
nie geöffnet wurde. Der „Einstellungen"-Button im Plugin-Manager hängt am
|
eingeschaltet. Falls eine zukünftige Änderung die Lade-Zeit wieder über 100 ms drückt, taucht der
|
||||||
selben Pfad.
|
Mehrverbrauch direkt im /xllog auf, ohne dass jemand erst den Debug-Filter einschalten muss.
|
||||||
- Plugin-Load-Diagnose-Logs als Tripwire: die Profiling-Logs für
|
- ChatTwo-IPC-Kompatibilitäts-Layer: HellionChat spiegelt jetzt die komplette ChatTwo-IPC-Surface
|
||||||
MessageStore.Connect, MessageStore.Migrate, FilterAllTabs und den
|
(`GetChatInputState`, `ChatInputStateChanged`, `Register`, `Unregister`, `Available`, `Invoke`)
|
||||||
Auto-Translate-Warmup bleiben auf Information-Level eingeschaltet. Falls
|
zusätzlich zu unseren eigenen `HellionChat.*`-Gates unter dem `ChatTwo.*`-Namensraum. Drittseitige
|
||||||
eine zukünftige Änderung die Lade-Zeit wieder über 100 ms drückt, taucht
|
Integrationen die nur auf ChatTwo's IPC reagieren, etwa die Kontextmenü-Hooks von Artisan und
|
||||||
der Mehrverbrauch direkt im /xllog auf, ohne dass jemand erst den
|
AllaganTools, funktionieren damit weiter ohne Code-Änderung auf ihrer Seite. Die
|
||||||
Debug-Filter einschalten muss.
|
Conflict-Detection blockiert das parallele Laden von ChatTwo, daher kein Namensraum-Konflikt im
|
||||||
- ChatTwo-IPC-Kompatibilitäts-Layer: HellionChat spiegelt jetzt die
|
Live-Betrieb.
|
||||||
komplette ChatTwo-IPC-Surface (`GetChatInputState`,
|
- Migration v17 unverändert: kein Schema-Bump, kein Config-Migrations- Aufwand. Nach dem Update
|
||||||
`ChatInputStateChanged`, `Register`, `Unregister`, `Available`,
|
läuft das Plugin gegen die bestehende v17-Datenbank weiter.
|
||||||
`Invoke`) zusätzlich zu unseren eigenen `HellionChat.*`-Gates unter
|
|
||||||
dem `ChatTwo.*`-Namensraum. Drittseitige Integrationen die nur auf
|
|
||||||
ChatTwo's IPC reagieren, etwa die Kontextmenü-Hooks von Artisan und
|
|
||||||
AllaganTools, funktionieren damit weiter ohne Code-Änderung auf
|
|
||||||
ihrer Seite. Die Conflict-Detection blockiert das parallele Laden
|
|
||||||
von ChatTwo, daher kein Namensraum-Konflikt im Live-Betrieb.
|
|
||||||
- Migration v17 unverändert: kein Schema-Bump, kein Config-Migrations-
|
|
||||||
Aufwand. Nach dem Update läuft das Plugin gegen die bestehende
|
|
||||||
v17-Datenbank weiter.
|
|
||||||
|
|||||||
@@ -3,35 +3,26 @@ subtitle: DI Foundation und Service-Refactor
|
|||||||
versionsnatur: Architektur-Cycle
|
versionsnatur: Architektur-Cycle
|
||||||
---
|
---
|
||||||
|
|
||||||
- **Architektur-Umbau ohne User-spürbare Verhaltens-Änderung:** der
|
- **Architektur-Umbau ohne User-spürbare Verhaltens-Änderung:** der Plugin-Bootstrap wechselt auf
|
||||||
Plugin-Bootstrap wechselt auf einen Generic-Host DI-Container
|
einen Generic-Host DI-Container (`Microsoft.Extensions.Hosting` + `IServiceCollection`) nach dem
|
||||||
(`Microsoft.Extensions.Hosting` + `IServiceCollection`) nach dem
|
Lightless-Sync-Muster. 18 Service-Klassen wandern von einem statischen `Plugin.LogProxy`-Locator
|
||||||
Lightless-Sync-Muster. 18 Service-Klassen wandern von einem
|
auf typisierte `ILogger<T>`-Constructor-Injection. `DalamudLogger` brückt
|
||||||
statischen `Plugin.LogProxy`-Locator auf typisierte
|
`Microsoft.Extensions.Logging` über auf Dalamuds `IPluginLog` — im xllog erscheinen jetzt
|
||||||
`ILogger<T>`-Constructor-Injection. `DalamudLogger` brückt
|
Service-spezifische Spalten wie `[ MessageManager]` und `[Honori...ervice]`.
|
||||||
`Microsoft.Extensions.Logging` über auf Dalamuds `IPluginLog` —
|
- **Plugin.LogProxy bleibt für die acht Buckets erhalten,** die Constructor-Injection nicht
|
||||||
im xllog erscheinen jetzt Service-spezifische Spalten wie
|
erreicht: Static-Helper (EmoteCache, AutoTranslate, MemoryUtil, WrapperUtil), Dalamud-Reflektion
|
||||||
`[ MessageManager]` und `[Honori...ervice]`.
|
(Configuration), Data-Class mit Massen-Instanziierung (Message) und Instanz-Klassen die nur aus
|
||||||
- **Plugin.LogProxy bleibt für die acht Buckets erhalten,** die
|
Static-Methods loggen (FontManager, eine GameFunctions-Stelle).
|
||||||
Constructor-Injection nicht erreicht: Static-Helper (EmoteCache,
|
- **Performance bestätigt durch Cross-Plugin-Baseline:** HellionChat First-Frame-HITCH 77 ms Median,
|
||||||
AutoTranslate, MemoryUtil, WrapperUtil), Dalamud-Reflektion
|
Chat 2 v1.40.2 74 ms Median — kein DI-Penalty gegenüber dem Upstream-Fork-Origin. Lightless und
|
||||||
(Configuration), Data-Class mit Massen-Instanziierung (Message)
|
XIVInstantMessenger liegen bei ~7 ms weil sie ihren FontAtlas-Build deferren; das wird das
|
||||||
und Instanz-Klassen die nur aus Static-Methods loggen (FontManager,
|
v1.5.1-Item.
|
||||||
eine GameFunctions-Stelle).
|
- **User-sichtbarer Bug-Fix nebenbei:** Slash-Command-Einfügen in das Chat-Eingabefeld (Friend-List
|
||||||
- **Performance bestätigt durch Cross-Plugin-Baseline:** HellionChat
|
"/tell"-Action plus Plugin-Inserts von Artisan, AllaganTools und ähnlichen) ersetzt jetzt den
|
||||||
First-Frame-HITCH 77 ms Median, Chat 2 v1.40.2 74 ms Median — kein
|
vorhandenen Input, statt anzukonkatenieren. Cherry-Pick aus ChatTwo upstream `ee7768ac` mit
|
||||||
DI-Penalty gegenüber dem Upstream-Fork-Origin. Lightless und
|
Namespace-Anpassung.
|
||||||
XIVInstantMessenger liegen bei ~7 ms weil sie ihren FontAtlas-Build
|
- **Foundation für die Plugin-Integrations-Wave:** v1.5.7-11 (Context-Menu, NotificationMaster,
|
||||||
deferren; das wird das v1.5.1-Item.
|
Moodles, ExtraChat, XIVIM Quick-DM) werden ab jetzt strukturell handhabbar — neue Services sind
|
||||||
- **User-sichtbarer Bug-Fix nebenbei:** Slash-Command-Einfügen in das
|
ein `services.AddSingleton<T>` plus ein paar Factory-Lambda- Zeilen, kein Plugin.cs-Anflanschen
|
||||||
Chat-Eingabefeld (Friend-List "/tell"-Action plus Plugin-Inserts
|
mehr.
|
||||||
von Artisan, AllaganTools und ähnlichen) ersetzt jetzt den
|
- Migration v17 unverändert: kein Schema-Bump, kein Config-Migrations-Aufwand.
|
||||||
vorhandenen Input, statt anzukonkatenieren. Cherry-Pick aus ChatTwo
|
|
||||||
upstream `ee7768ac` mit Namespace-Anpassung.
|
|
||||||
- **Foundation für die Plugin-Integrations-Wave:** v1.5.7-11
|
|
||||||
(Context-Menu, NotificationMaster, Moodles, ExtraChat, XIVIM
|
|
||||||
Quick-DM) werden ab jetzt strukturell handhabbar — neue Services
|
|
||||||
sind ein `services.AddSingleton<T>` plus ein paar Factory-Lambda-
|
|
||||||
Zeilen, kein Plugin.cs-Anflanschen mehr.
|
|
||||||
- Migration v17 unverändert: kein Schema-Bump, kein
|
|
||||||
Config-Migrations-Aufwand.
|
|
||||||
|
|||||||
+14
-12
@@ -2,26 +2,28 @@
|
|||||||
|
|
||||||
## How to install
|
## How to install
|
||||||
|
|
||||||
This release is distributed via the HellionChat custom repository, not the Dalamud main plugin repo. To install:
|
This release is distributed via the HellionChat custom repository, not the Dalamud main plugin repo.
|
||||||
|
To install:
|
||||||
|
|
||||||
1. In XIVLauncher: **Settings → Experimental → Custom Plugin Repositories**
|
1. In XIVLauncher: **Settings → Experimental → Custom Plugin Repositories**
|
||||||
2. Add the URL: `https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/raw/branch/main/repo.json`
|
2. Add the URL:
|
||||||
|
`https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/raw/branch/main/repo.json`
|
||||||
3. Enable, save, then `/xlplugins` → search **Hellion Chat** → install
|
3. Enable, save, then `/xlplugins` → search **Hellion Chat** → install
|
||||||
|
|
||||||
## Project documents
|
## Project documents
|
||||||
|
|
||||||
- [README](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/src/branch/main/README.md) — features,
|
- [README](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/src/branch/main/README.md)
|
||||||
architecture, build
|
— features, architecture, build
|
||||||
- [Privacy notice](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/src/branch/main/PRIVACY.md) — what
|
- [Privacy notice](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/src/branch/main/PRIVACY.md)
|
||||||
the plugin stores and sends
|
— what the plugin stores and sends
|
||||||
- [Third-party notices](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/src/branch/main/docs/THIRD_PARTY_NOTICES.md)
|
- [Third-party notices](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/src/branch/main/docs/THIRD_PARTY_NOTICES.md)
|
||||||
— dependencies and licences
|
— dependencies and licences
|
||||||
- [Security policy](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/src/branch/main/SECURITY.md) —
|
- [Security policy](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/src/branch/main/SECURITY.md)
|
||||||
vulnerability reporting
|
— vulnerability reporting
|
||||||
- [Support](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/src/branch/main/SUPPORT.md) — bug reports,
|
- [Support](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/src/branch/main/SUPPORT.md)
|
||||||
questions, contact paths
|
— bug reports, questions, contact paths
|
||||||
|
|
||||||
## Licence
|
## Licence
|
||||||
|
|
||||||
[EUPL-1.2](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/src/branch/main/LICENSE). Based on
|
[EUPL-1.2](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/src/branch/main/LICENSE).
|
||||||
[Chat 2](https://github.com/Infiziert90/ChatTwo) by Infi and Anna, also EUPL-1.2.
|
Based on [Chat 2](https://github.com/Infiziert90/ChatTwo) by Infi and Anna, also EUPL-1.2.
|
||||||
|
|||||||
+456
-229
@@ -1,37 +1,193 @@
|
|||||||
## Ignore Visual Studio temporary files, build results, and
|
##############################################################
|
||||||
## files generated by popular Visual Studio add-ons.
|
|
||||||
##
|
##
|
||||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
## .gitignore – Hellion Forge / Hellion Media
|
||||||
|
##
|
||||||
|
## Basis: github/gitignore VisualStudio.gitignore
|
||||||
|
## Überarbeitet: Mai 2026
|
||||||
|
## Status: Original-Patterns vollständig erhalten,
|
||||||
|
## neu sortiert in logische Sektionen,
|
||||||
|
## Sicherheits- & Tooling-Sektionen ergänzt.
|
||||||
|
##
|
||||||
|
## Markierungen:
|
||||||
|
## [!! OBSOLET 2026 !!] → Tool offiziell eingestellt,
|
||||||
|
## Pattern bleibt aus Vorsicht drin.
|
||||||
|
##
|
||||||
|
##############################################################
|
||||||
|
|
||||||
# Local development environment (HellionChat fork)
|
|
||||||
|
# =====================================================
|
||||||
|
# [!! KRITISCH !!] Secrets, Keys & Credentials
|
||||||
|
# Diese Sachen dürfen NIEMALS im Repo landen!
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
# Environment Files
|
||||||
.env
|
.env
|
||||||
|
.env.*
|
||||||
.env.bak*
|
.env.bak*
|
||||||
.envrc
|
.envrc
|
||||||
!.env.example
|
!.env.example
|
||||||
|
!.env.sample
|
||||||
|
|
||||||
|
# Private Keys & Zertifikate
|
||||||
|
*.pem
|
||||||
|
*.key
|
||||||
|
*.p12
|
||||||
|
*.pfx
|
||||||
|
*.cer
|
||||||
|
*.crt
|
||||||
|
*.csr
|
||||||
|
*.gpg
|
||||||
|
*.asc
|
||||||
|
|
||||||
|
# SSH Keys (falls jemand die ins Repo legt)
|
||||||
|
id_rsa
|
||||||
|
id_ed25519
|
||||||
|
id_ecdsa
|
||||||
|
known_hosts
|
||||||
|
|
||||||
|
# Auth-/Token-Files
|
||||||
|
auth.json
|
||||||
|
.npmrc
|
||||||
|
.pypirc
|
||||||
|
secrets.json
|
||||||
|
|
||||||
|
# ASP.NET / .NET App-Configs mit lokalen Secrets
|
||||||
|
appsettings.*.local.json
|
||||||
|
appsettings.Local.json
|
||||||
|
local.settings.json
|
||||||
|
|
||||||
|
# Memory Dumps (können Credentials im Heap enthalten!)
|
||||||
|
*.dmp
|
||||||
|
*.mdmp
|
||||||
|
crash.log
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Projekt-spezifisch (HellionChat Fork)
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
# Lokale Entwicklungsumgebung
|
||||||
.vscode/
|
.vscode/
|
||||||
scripts/setup-dev-env.sh
|
scripts/setup-dev-env.sh
|
||||||
|
|
||||||
# Local test project (stays out of the published plugin repo;
|
# Lokales Test-Projekt (bleibt aus dem Plugin-Repo raus;
|
||||||
# pure-function safety net for refactor cycles)
|
# pure-function safety net für Refactor-Cycles)
|
||||||
HellionChat.Tests/
|
HellionChat.Tests/
|
||||||
|
ChatTwo.Tests
|
||||||
|
TestResults
|
||||||
|
*.db-shm
|
||||||
|
*.db-wal
|
||||||
|
|
||||||
# Packaging
|
# Packaging
|
||||||
pack/
|
pack/
|
||||||
|
|
||||||
# User-specific files
|
# Specs und Plan-Dateien
|
||||||
|
/.superpowers/
|
||||||
|
|
||||||
|
# Claude Code lokales Setup (nicht committed)
|
||||||
|
/.claude/
|
||||||
|
/CLAUDE.md
|
||||||
|
|
||||||
|
# Cycle-Working-Notes (im Vault gepflegt, lokales Repo-Pad bei Bedarf)
|
||||||
|
/docs/cycle-notes/
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# OS-spezifische Files
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
# macOS
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Windows
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
Desktop.ini
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Linux
|
||||||
|
.directory
|
||||||
|
.Trash-*
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# AI / LLM Tooling (2026 era)
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
# Cursor IDE
|
||||||
|
.cursor/
|
||||||
|
.cursorignore
|
||||||
|
|
||||||
|
# Aider
|
||||||
|
.aider*
|
||||||
|
|
||||||
|
# Continue.dev
|
||||||
|
.continue/
|
||||||
|
.continuerc.json
|
||||||
|
|
||||||
|
# Windsurf
|
||||||
|
.windsurf/
|
||||||
|
|
||||||
|
# Sourcegraph Cody
|
||||||
|
.cody/
|
||||||
|
|
||||||
|
# Lokale Prompt-Sammlungen / Scratch-Pads
|
||||||
|
prompts/local/
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Editor & IDE (neben Visual Studio)
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
# JetBrains (IntelliJ, Rider, etc.)
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# Vim / Neovim
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*.swn
|
||||||
|
|
||||||
|
# Sublime Text
|
||||||
|
*.sublime-workspace
|
||||||
|
*.sublime-project
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# IDE & Editor – User-spezifische Files (VS)
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
# Visual Studio User Files
|
||||||
*.rsuser
|
*.rsuser
|
||||||
*.suo
|
*.suo
|
||||||
*.user
|
*.user
|
||||||
*.userosscache
|
*.userosscache
|
||||||
*.sln.docstates
|
*.sln.docstates
|
||||||
|
|
||||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
# MonoDevelop/Xamarin Studio
|
||||||
*.userprefs
|
*.userprefs
|
||||||
|
|
||||||
# Mono auto generated files
|
# Visual Studio Cache/Options Directory
|
||||||
mono_crash.*
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto-generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# Local History
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Build Output
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
# Build results
|
|
||||||
[Dd]ebug/
|
[Dd]ebug/
|
||||||
[Dd]ebugPublic/
|
[Dd]ebugPublic/
|
||||||
[Rr]elease/
|
[Rr]elease/
|
||||||
@@ -47,43 +203,24 @@ bld/
|
|||||||
[Ll]og/
|
[Ll]og/
|
||||||
[Ll]ogs/
|
[Ll]ogs/
|
||||||
|
|
||||||
# Visual Studio 2015/2017 cache/options directory
|
# ATL Project Build Output
|
||||||
.vs/
|
|
||||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
|
||||||
#wwwroot/
|
|
||||||
|
|
||||||
# Visual Studio 2017 auto generated files
|
|
||||||
Generated\ Files/
|
|
||||||
|
|
||||||
# MSTest test Results
|
|
||||||
[Tt]est[Rr]esult*/
|
|
||||||
[Bb]uild[Ll]og.*
|
|
||||||
|
|
||||||
# NUnit
|
|
||||||
*.VisualState.xml
|
|
||||||
TestResult.xml
|
|
||||||
nunit-*.xml
|
|
||||||
|
|
||||||
# Build Results of an ATL Project
|
|
||||||
[Dd]ebugPS/
|
[Dd]ebugPS/
|
||||||
[Rr]eleasePS/
|
[Rr]eleasePS/
|
||||||
dlldata.c
|
dlldata.c
|
||||||
|
|
||||||
# Benchmark Results
|
|
||||||
BenchmarkDotNet.Artifacts/
|
|
||||||
|
|
||||||
# .NET Core
|
# .NET Core
|
||||||
project.lock.json
|
project.lock.json
|
||||||
project.fragment.lock.json
|
project.fragment.lock.json
|
||||||
artifacts/
|
artifacts/
|
||||||
|
|
||||||
# ASP.NET Scaffolding
|
# MigrationBackup (Package Reference Convert Tool)
|
||||||
ScaffoldingReadMe.txt
|
MigrationBackup/
|
||||||
|
|
||||||
# StyleCop
|
|
||||||
StyleCopReport.xml
|
|
||||||
|
|
||||||
# Files built by Visual Studio
|
# =====================================================
|
||||||
|
# Build-Artefakte (Files built by Visual Studio)
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
*_i.c
|
*_i.c
|
||||||
*_p.c
|
*_p.c
|
||||||
*_h.h
|
*_h.h
|
||||||
@@ -105,6 +242,7 @@ StyleCopReport.xml
|
|||||||
*.tmp_proj
|
*.tmp_proj
|
||||||
*_wpftmp.csproj
|
*_wpftmp.csproj
|
||||||
*.log
|
*.log
|
||||||
|
*.binlog
|
||||||
*.vspscc
|
*.vspscc
|
||||||
*.vssscc
|
*.vssscc
|
||||||
.builds
|
.builds
|
||||||
@@ -112,10 +250,87 @@ StyleCopReport.xml
|
|||||||
*.svclog
|
*.svclog
|
||||||
*.scc
|
*.scc
|
||||||
|
|
||||||
# Chutzpah Test files
|
|
||||||
|
# =====================================================
|
||||||
|
# Test Results
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
# MSTest
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# Verify / Snapshot Testing (modern .NET, Spotty Wisdom)
|
||||||
|
*.received.*
|
||||||
|
*.received.txt
|
||||||
|
|
||||||
|
# [!! OBSOLET 2026 !!] Chutzpah – Repository auf GitHub archiviert
|
||||||
_Chutzpah*
|
_Chutzpah*
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Code Coverage
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
# Coverlet
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# DotCover (JetBrains)
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# OpenCover UI Analysis
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# [!! OBSOLET 2026 !!] MightyMoose / AutoTest.Net – seit >10 Jahren nicht mehr gepflegt
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Profiler & Trace
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
# Visual Studio Profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# NVidia Nsight GPU Debugger
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Cache Files (VS, C++, Sass)
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
# Visual C++ cache files
|
# Visual C++ cache files
|
||||||
|
# Hinweis: Manche Patterns hier werden auch vom C#-Linter genutzt (z. B. *.lscache)
|
||||||
ipch/
|
ipch/
|
||||||
*.aps
|
*.aps
|
||||||
*.ncb
|
*.ncb
|
||||||
@@ -125,101 +340,80 @@ ipch/
|
|||||||
*.cachefile
|
*.cachefile
|
||||||
*.VC.db
|
*.VC.db
|
||||||
*.VC.VC.opendb
|
*.VC.VC.opendb
|
||||||
|
*.lscache
|
||||||
|
|
||||||
# Visual Studio profiler
|
# Visual Studio cache (.cache files allgemein, .cache directories behalten)
|
||||||
*.psess
|
*.[Cc]ache
|
||||||
*.vsp
|
!?*.[Cc]ache/
|
||||||
*.vspx
|
|
||||||
*.sap
|
|
||||||
|
|
||||||
# Visual Studio Trace Files
|
# Web Workbench Sass
|
||||||
*.e2e
|
|
||||||
|
|
||||||
# TFS 2012 Local Workspace
|
|
||||||
$tf/
|
|
||||||
|
|
||||||
# Guidance Automation Toolkit
|
|
||||||
*.gpState
|
|
||||||
|
|
||||||
# ReSharper is a .NET coding add-in
|
|
||||||
_ReSharper*/
|
|
||||||
*.[Rr]e[Ss]harper
|
|
||||||
*.DotSettings.user
|
|
||||||
|
|
||||||
# TeamCity is a build add-in
|
|
||||||
_TeamCity*
|
|
||||||
|
|
||||||
# DotCover is a Code Coverage Tool
|
|
||||||
*.dotCover
|
|
||||||
|
|
||||||
# AxoCover is a Code Coverage Tool
|
|
||||||
.axoCover/*
|
|
||||||
!.axoCover/settings.json
|
|
||||||
|
|
||||||
# Coverlet is a free, cross platform Code Coverage Tool
|
|
||||||
coverage*.json
|
|
||||||
coverage*.xml
|
|
||||||
coverage*.info
|
|
||||||
|
|
||||||
# Visual Studio code coverage results
|
|
||||||
*.coverage
|
|
||||||
*.coveragexml
|
|
||||||
|
|
||||||
# NCrunch
|
|
||||||
_NCrunch_*
|
|
||||||
.*crunch*.local.xml
|
|
||||||
nCrunchTemp_*
|
|
||||||
|
|
||||||
# MightyMoose
|
|
||||||
*.mm.*
|
|
||||||
AutoTest.Net/
|
|
||||||
|
|
||||||
# Web workbench (sass)
|
|
||||||
.sass-cache/
|
.sass-cache/
|
||||||
|
|
||||||
# Installshield output folder
|
|
||||||
[Ee]xpress/
|
|
||||||
|
|
||||||
# DocProject is a documentation generator add-in
|
# =====================================================
|
||||||
DocProject/buildhelp/
|
# NuGet & Dependencies
|
||||||
DocProject/Help/*.HxT
|
# =====================================================
|
||||||
DocProject/Help/*.HxC
|
|
||||||
DocProject/Help/*.hhc
|
|
||||||
DocProject/Help/*.hhk
|
|
||||||
DocProject/Help/*.hhp
|
|
||||||
DocProject/Help/Html2
|
|
||||||
DocProject/Help/html
|
|
||||||
|
|
||||||
# Click-Once directory
|
|
||||||
publish/
|
|
||||||
|
|
||||||
# Publish Web Output
|
|
||||||
*.[Pp]ublish.xml
|
|
||||||
*.azurePubxml
|
|
||||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
|
||||||
# but database connection strings (with potential passwords) will be unencrypted
|
|
||||||
*.pubxml
|
|
||||||
*.publishproj
|
|
||||||
|
|
||||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
|
||||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
|
||||||
# in these scripts will be unencrypted
|
|
||||||
PublishScripts/
|
|
||||||
|
|
||||||
# NuGet Packages
|
# NuGet Packages
|
||||||
*.nupkg
|
*.nupkg
|
||||||
# NuGet Symbol Packages
|
|
||||||
*.snupkg
|
*.snupkg
|
||||||
# The packages folder can be ignored because of Package Restore
|
|
||||||
**/[Pp]ackages/*
|
**/[Pp]ackages/*
|
||||||
# except build/, which is used as an MSBuild target.
|
|
||||||
!**/[Pp]ackages/build/
|
!**/[Pp]ackages/build/
|
||||||
# Uncomment if necessary however generally it will be regenerated when needed
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
#!**/[Pp]ackages/repositories.config
|
#!**/[Pp]ackages/repositories.config
|
||||||
# NuGet v3's project.json files produces more ignorable files
|
|
||||||
*.nuget.props
|
*.nuget.props
|
||||||
*.nuget.targets
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Fody – auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
||||||
|
|
||||||
|
# Node (falls JS-Tooling im Build genutzt wird)
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Python Tools für Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Mono
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Publish & Deploy
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
# Click-Once
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App Publish Settings
|
||||||
|
# Comment the next line if you want to checkin your Azure Web App publish settings,
|
||||||
|
# but sensitive information contained in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
# Microsoft Azure Build Output
|
# Microsoft Azure Build Output
|
||||||
csx/
|
csx/
|
||||||
*.build.csdef
|
*.build.csdef
|
||||||
@@ -228,7 +422,35 @@ csx/
|
|||||||
ecf/
|
ecf/
|
||||||
rcf/
|
rcf/
|
||||||
|
|
||||||
# Windows Store app package directories and files
|
# Service Fabric Backup
|
||||||
|
ServiceFabricBackup/
|
||||||
|
|
||||||
|
# Installshield
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Container / Infrastructure-as-Code (Vorsicht: Tokens!)
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
docker-compose.override.yml
|
||||||
|
|
||||||
|
# Terraform
|
||||||
|
.terraform/
|
||||||
|
*.tfstate
|
||||||
|
*.tfstate.*
|
||||||
|
*.tfvars
|
||||||
|
!example.tfvars
|
||||||
|
|
||||||
|
# Serverless Framework
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Windows Store / AppX
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
AppPackages/
|
AppPackages/
|
||||||
BundleArtifacts/
|
BundleArtifacts/
|
||||||
Package.StoreAssociation.xml
|
Package.StoreAssociation.xml
|
||||||
@@ -237,50 +459,29 @@ _pkginfo.txt
|
|||||||
*.appxbundle
|
*.appxbundle
|
||||||
*.appxupload
|
*.appxupload
|
||||||
|
|
||||||
# Visual Studio cache files
|
|
||||||
# files ending in .cache can be ignored
|
|
||||||
*.[Cc]ache
|
|
||||||
# but keep track of directories ending in .cache
|
|
||||||
!?*.[Cc]ache/
|
|
||||||
|
|
||||||
# Others
|
# =====================================================
|
||||||
ClientBin/
|
# Datenbanken & SQL
|
||||||
~$*
|
# =====================================================
|
||||||
*~
|
|
||||||
*.dbmdl
|
|
||||||
*.dbproj.schemaview
|
|
||||||
*.jfm
|
|
||||||
*.pfx
|
|
||||||
*.publishsettings
|
|
||||||
orleans.codegen.cs
|
|
||||||
|
|
||||||
# Including strong name files can present a security risk
|
# SQL Server
|
||||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
|
||||||
#*.snk
|
|
||||||
|
|
||||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
|
||||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
|
||||||
#bower_components/
|
|
||||||
|
|
||||||
# RIA/Silverlight projects
|
|
||||||
Generated_Code/
|
|
||||||
|
|
||||||
# Backup & report files from converting an old project file
|
|
||||||
# to a newer Visual Studio version. Backup files are not needed,
|
|
||||||
# because we have git ;-)
|
|
||||||
_UpgradeReport_Files/
|
|
||||||
Backup*/
|
|
||||||
UpgradeLog*.XML
|
|
||||||
UpgradeLog*.htm
|
|
||||||
ServiceFabricBackup/
|
|
||||||
*.rptproj.bak
|
|
||||||
|
|
||||||
# SQL Server files
|
|
||||||
*.mdf
|
*.mdf
|
||||||
*.ldf
|
*.ldf
|
||||||
*.ndf
|
*.ndf
|
||||||
|
|
||||||
# Business Intelligence projects
|
# Andere DB-bezogene
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
|
||||||
|
# [!! OBSOLET 2026 !!] BeatPulse – wurde 2019 umbenannt zu AspNetCore.Diagnostics.HealthChecks
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Business Intelligence / Reporting
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
*.rdl.data
|
*.rdl.data
|
||||||
*.bim.layout
|
*.bim.layout
|
||||||
*.bim_*.settings
|
*.bim_*.settings
|
||||||
@@ -288,27 +489,97 @@ ServiceFabricBackup/
|
|||||||
*- [Bb]ackup.rdl
|
*- [Bb]ackup.rdl
|
||||||
*- [Bb]ackup ([0-9]).rdl
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Add-ins & Analyzer Tools
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
# ReSharper
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
# Microsoft Fakes
|
# Microsoft Fakes
|
||||||
FakesAssemblies/
|
FakesAssemblies/
|
||||||
|
|
||||||
# GhostDoc plugin setting file
|
# [!! OBSOLET 2026 !!] GhostDoc Plugin – Submain hat das Tool eingestellt
|
||||||
*.GhostDoc.xml
|
*.GhostDoc.xml
|
||||||
|
|
||||||
# Node.js Tools for Visual Studio
|
# Tabs Studio
|
||||||
.ntvs_analysis.dat
|
*.tss
|
||||||
node_modules/
|
|
||||||
|
|
||||||
# Visual Studio 6 build log
|
# Telerik JustMock
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool)
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# DocProject Documentation Generator
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Sonstige Sprachen & Tooling
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
# Ionide (F# VS Code Tools)
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Azure Stream Analytics Local Run
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# BizTalk Build Output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# Orleans
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# [!! OBSOLET 2026 !!] Legacy-Tooling (eingestellt)
|
||||||
|
# Patterns bleiben aus Vorsicht drin.
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
# [!! OBSOLET 2026 !!] TFS 2012 Local Workspace – ersetzt durch Azure DevOps
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# [!! OBSOLET 2026 !!] Visual Studio 6 Build Log – VS6 ist von 1998
|
||||||
*.plg
|
*.plg
|
||||||
|
|
||||||
# Visual Studio 6 workspace options file
|
# [!! OBSOLET 2026 !!] Visual Studio 6 Workspace Options
|
||||||
*.opt
|
*.opt
|
||||||
|
|
||||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
# [!! OBSOLET 2026 !!] Visual Studio 6 Workspace File
|
||||||
*.vbw
|
*.vbw
|
||||||
|
|
||||||
# Visual Studio LightSwitch build output
|
# [!! OBSOLET 2026 !!] RIA / Silverlight – Microsoft hat das Okt. 2021 eingestellt
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# [!! OBSOLET 2026 !!] Visual Studio LightSwitch – von Microsoft eingestellt
|
||||||
**/*.HTMLClient/GeneratedArtifacts
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
**/*.DesktopClient/GeneratedArtifacts
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
**/*.DesktopClient/ModelManifest.xml
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
@@ -316,75 +587,31 @@ node_modules/
|
|||||||
**/*.Server/ModelManifest.xml
|
**/*.Server/ModelManifest.xml
|
||||||
_Pvt_Extensions
|
_Pvt_Extensions
|
||||||
|
|
||||||
# Paket dependency manager
|
|
||||||
.paket/paket.exe
|
|
||||||
paket-files/
|
|
||||||
|
|
||||||
# FAKE - F# Make
|
# =====================================================
|
||||||
.fake/
|
# Upgrade / Backup-Reports
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
# CodeRush personal settings
|
# Backup-Files vom Konvertieren alter VS-Projekte (wir haben ja git ;-))
|
||||||
.cr/personal
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
|
||||||
# Python Tools for Visual Studio (PTVS)
|
|
||||||
__pycache__/
|
|
||||||
*.pyc
|
|
||||||
|
|
||||||
# Cake - Uncomment if you are using it
|
# =====================================================
|
||||||
# tools/**
|
# Misc / Temp / Backup
|
||||||
# !tools/packages.config
|
# =====================================================
|
||||||
|
|
||||||
# Tabs Studio
|
ClientBin/
|
||||||
*.tss
|
~$*
|
||||||
|
*~
|
||||||
|
*.publishsettings
|
||||||
|
|
||||||
# Telerik's JustMock configuration file
|
# Including strong name files can present a security risk
|
||||||
*.jmconfig
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
# BizTalk build output
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
*.btp.cs
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
*.btm.cs
|
#bower_components/
|
||||||
*.odx.cs
|
|
||||||
*.xsd.cs
|
|
||||||
|
|
||||||
# OpenCover UI analysis results
|
|
||||||
OpenCover/
|
|
||||||
|
|
||||||
# Azure Stream Analytics local run output
|
|
||||||
ASALocalRun/
|
|
||||||
|
|
||||||
# MSBuild Binary and Structured Log
|
|
||||||
*.binlog
|
|
||||||
|
|
||||||
# NVidia Nsight GPU debugger configuration file
|
|
||||||
*.nvuser
|
|
||||||
|
|
||||||
# MFractors (Xamarin productivity tool) working folder
|
|
||||||
.mfractor/
|
|
||||||
|
|
||||||
# Local History for Visual Studio
|
|
||||||
.localhistory/
|
|
||||||
|
|
||||||
# BeatPulse healthcheck temp database
|
|
||||||
healthchecksdb
|
|
||||||
|
|
||||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
|
||||||
MigrationBackup/
|
|
||||||
|
|
||||||
# Ionide (cross platform F# VS Code tools) working folder
|
|
||||||
.ionide/
|
|
||||||
|
|
||||||
# Fody - auto-generated XML schema
|
|
||||||
FodyWeavers.xsd
|
|
||||||
|
|
||||||
#Specs und Plan datein
|
|
||||||
/.superpowers/
|
|
||||||
|
|
||||||
#Test Datein
|
|
||||||
ChatTwo.Tests
|
|
||||||
TestResults
|
|
||||||
*.db-shm
|
|
||||||
*.db-wal
|
|
||||||
|
|
||||||
# Claude Code projekt-spezifisches Setup (lokal, nicht committed)
|
|
||||||
/.claude/
|
|
||||||
/CLAUDE.md
|
|
||||||
+10
-2
@@ -1,9 +1,17 @@
|
|||||||
{
|
{
|
||||||
"MD007": { "indent": 4 },
|
"MD003": { "style": "atx" },
|
||||||
|
"MD004": { "style": "dash" },
|
||||||
|
"MD007": { "indent": 2 },
|
||||||
|
"MD009": { "br_spaces": 2, "strict": false, "list_item_empty_lines": false },
|
||||||
"MD013": false,
|
"MD013": false,
|
||||||
"MD024": { "siblings_only": true },
|
"MD024": { "siblings_only": true },
|
||||||
"MD029": false,
|
"MD029": false,
|
||||||
"MD033": false,
|
"MD033": false,
|
||||||
"MD036": false,
|
"MD036": false,
|
||||||
"MD041": false
|
"MD040": true,
|
||||||
|
"MD041": false,
|
||||||
|
"MD046": { "style": "fenced" },
|
||||||
|
"MD048": { "style": "backtick" },
|
||||||
|
"MD049": { "style": "underscore" },
|
||||||
|
"MD050": { "style": "asterisk" }
|
||||||
}
|
}
|
||||||
|
|||||||
+47
-1
@@ -1,4 +1,50 @@
|
|||||||
|
# ##############################################################
|
||||||
|
# #
|
||||||
|
# # .prettierignore – Hellion Forge / Hellion Media
|
||||||
|
# #
|
||||||
|
# # Files die Prettier NICHT anfassen soll.
|
||||||
|
# # Überarbeitet: Mai 2026
|
||||||
|
# #
|
||||||
|
# # Hinweis: Prettier liest auch .gitignore automatisch mit.
|
||||||
|
# # Hier nur Sachen die zusätzlich ignoriert werden müssen
|
||||||
|
# # oder die im Repo liegen aber nicht formatiert werden dürfen.
|
||||||
|
# #
|
||||||
|
# ##############################################################
|
||||||
|
|
||||||
|
|
||||||
|
# === .NET Build Output ===
|
||||||
bin/
|
bin/
|
||||||
obj/
|
obj/
|
||||||
|
|
||||||
|
# === JS / Web Build Output ===
|
||||||
node_modules/
|
node_modules/
|
||||||
*.Designer.cs
|
dist/
|
||||||
|
out/
|
||||||
|
build/
|
||||||
|
coverage/
|
||||||
|
|
||||||
|
# === Generierte C#-Files (Designer, Source Generators) ===
|
||||||
|
*.Designer.cs
|
||||||
|
*.g.cs
|
||||||
|
*.g.i.cs
|
||||||
|
*.generated.cs
|
||||||
|
*.AssemblyInfo.cs
|
||||||
|
*.AssemblyAttributes.cs
|
||||||
|
|
||||||
|
# === Lock-Files (NIE umformatieren – zerschießt den Hash) ===
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
|
pnpm-lock.yaml
|
||||||
|
packages.lock.json
|
||||||
|
|
||||||
|
# === Minified Files (bewusst kompakt, niemals anfassen) ===
|
||||||
|
*.min.js
|
||||||
|
*.min.css
|
||||||
|
|
||||||
|
# === Test-Snapshots (z. B. Verify) ===
|
||||||
|
*.received.*
|
||||||
|
*.verified.*
|
||||||
|
**/__snapshots__/
|
||||||
|
|
||||||
|
# === Plugin-Manifest (DalamudPackager-Schema, fix lassen) ===
|
||||||
|
HellionChat/HellionChat.yaml
|
||||||
|
|||||||
+30
-2
@@ -1,7 +1,35 @@
|
|||||||
{
|
{
|
||||||
"printWidth": 120,
|
"printWidth": 120,
|
||||||
"tabWidth": 4,
|
"tabWidth": 4,
|
||||||
"proseWrap": "always",
|
"useTabs": false,
|
||||||
|
"semi": true,
|
||||||
"singleQuote": false,
|
"singleQuote": false,
|
||||||
"endOfLine": "lf"
|
"trailingComma": "all",
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"arrowParens": "always",
|
||||||
|
"proseWrap": "always",
|
||||||
|
"endOfLine": "lf",
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": "*.md",
|
||||||
|
"options": {
|
||||||
|
"printWidth": 100,
|
||||||
|
"tabWidth": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": ["*.yml", "*.yaml"],
|
||||||
|
"options": {
|
||||||
|
"tabWidth": 2,
|
||||||
|
"singleQuote": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": "*.json",
|
||||||
|
"options": {
|
||||||
|
"tabWidth": 4,
|
||||||
|
"trailingComma": "none"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+45
-6
@@ -1,8 +1,47 @@
|
|||||||
|
# ##############################################################
|
||||||
|
# #
|
||||||
|
# # .yamllint.yaml – Hellion Forge / Hellion Media
|
||||||
|
# #
|
||||||
|
# # YAML-Linting Konfiguration.
|
||||||
|
# # Überarbeitet: Mai 2026
|
||||||
|
# #
|
||||||
|
# # Regel-Doku:
|
||||||
|
# # https://yamllint.readthedocs.io/en/stable/rules.html
|
||||||
|
# #
|
||||||
|
# ##############################################################
|
||||||
|
|
||||||
extends: default
|
extends: default
|
||||||
|
|
||||||
rules:
|
rules:
|
||||||
line-length: disable
|
# Zeilenlängen-Check aus (konsistent mit markdownlint MD013)
|
||||||
document-start: disable
|
line-length: disable
|
||||||
truthy:
|
|
||||||
allowed-values: ["true", "false", "on"]
|
# YAML ohne führendes "---" erlaubt
|
||||||
empty-lines:
|
document-start: disable
|
||||||
max: 1
|
|
||||||
|
# GitHub Actions nutzt "on:" als Trigger-Key.
|
||||||
|
# Ohne diesen Override würde yamllint das als boolean "on" beklagen.
|
||||||
|
truthy:
|
||||||
|
allowed-values: ['true', 'false', 'on']
|
||||||
|
|
||||||
|
# Maximal 1 Leerzeile in Folge (saubere Files)
|
||||||
|
empty-lines:
|
||||||
|
max: 1
|
||||||
|
|
||||||
|
# YAML-Standard ist 2 Spaces (auch GitHub Actions erwartet das).
|
||||||
|
# Explizit setzen, um Konsistenz im Repo zu erzwingen.
|
||||||
|
indentation:
|
||||||
|
spaces: 2
|
||||||
|
indent-sequences: true
|
||||||
|
check-multi-line-strings: false
|
||||||
|
|
||||||
|
# Kommentare brauchen Space nach #, müssen mit Content beginnen
|
||||||
|
comments:
|
||||||
|
require-starting-space: true
|
||||||
|
min-spaces-from-content: 1
|
||||||
|
|
||||||
|
# Kein Whitespace am Zeilenende
|
||||||
|
trailing-spaces: enable
|
||||||
|
|
||||||
|
# Datei muss mit Newline enden
|
||||||
|
new-line-at-end-of-file: enable
|
||||||
|
|||||||
+48
-44
@@ -2,14 +2,15 @@
|
|||||||
|
|
||||||
## A Note on This Project
|
## A Note on This Project
|
||||||
|
|
||||||
HellionChat is a one-person side project developed under Hellion Forge. I maintain this in my spare time, which means
|
HellionChat is a one-person side project developed under Hellion Forge. I maintain this in my spare
|
||||||
replies can take a few days. Please do not escalate just because a thread is quiet.
|
time, which means replies can take a few days. Please do not escalate just because a thread is
|
||||||
|
quiet.
|
||||||
|
|
||||||
When in doubt, assume good intent. Contributors come from different backgrounds, time zones and skill levels. A
|
When in doubt, assume good intent. Contributors come from different backgrounds, time zones and
|
||||||
clarifying question is almost always a better first move than an accusation.
|
skill levels. A clarifying question is almost always a better first move than an accusation.
|
||||||
|
|
||||||
Please also keep discussions on topic. This project is about a Dalamud chat plugin. Off-topic arguments belong
|
Please also keep discussions on topic. This project is about a Dalamud chat plugin. Off-topic
|
||||||
elsewhere.
|
arguments belong elsewhere.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -17,20 +18,21 @@ elsewhere.
|
|||||||
|
|
||||||
We pledge to make our community welcoming, safe, and equitable for all.
|
We pledge to make our community welcoming, safe, and equitable for all.
|
||||||
|
|
||||||
We are committed to fostering an environment that respects and promotes the dignity, rights, and contributions of all
|
We are committed to fostering an environment that respects and promotes the dignity, rights, and
|
||||||
individuals, regardless of characteristics including race, ethnicity, caste, color, age, physical characteristics,
|
contributions of all individuals, regardless of characteristics including race, ethnicity, caste,
|
||||||
neurodiversity, disability, sex or gender, gender identity or expression, sexual orientation, language, philosophy or
|
color, age, physical characteristics, neurodiversity, disability, sex or gender, gender identity or
|
||||||
religion, national or social origin, socio-economic position, level of education, or other status. The same privileges
|
expression, sexual orientation, language, philosophy or religion, national or social origin,
|
||||||
of participation are extended to everyone who participates in good faith and in accordance with this Covenant.
|
socio-economic position, level of education, or other status. The same privileges of participation
|
||||||
|
are extended to everyone who participates in good faith and in accordance with this Covenant.
|
||||||
|
|
||||||
## Encouraged Behaviors
|
## Encouraged Behaviors
|
||||||
|
|
||||||
While acknowledging differences in social norms, we all strive to meet our community's expectations for positive
|
While acknowledging differences in social norms, we all strive to meet our community's expectations
|
||||||
behavior. We also understand that our words and actions may be interpreted differently than we intend based on culture,
|
for positive behavior. We also understand that our words and actions may be interpreted differently
|
||||||
background, or native language.
|
than we intend based on culture, background, or native language.
|
||||||
|
|
||||||
With these considerations in mind, we agree to behave mindfully toward each other and act in ways that center our shared
|
With these considerations in mind, we agree to behave mindfully toward each other and act in ways
|
||||||
values, including:
|
that center our shared values, including:
|
||||||
|
|
||||||
1. Respecting the **purpose of our community**, our activities, and our ways of gathering.
|
1. Respecting the **purpose of our community**, our activities, and our ways of gathering.
|
||||||
2. Engaging **kindly and honestly** with others.
|
2. Engaging **kindly and honestly** with others.
|
||||||
@@ -42,31 +44,32 @@ values, including:
|
|||||||
|
|
||||||
## Restricted Behaviors
|
## Restricted Behaviors
|
||||||
|
|
||||||
We agree to restrict the following behaviors in our community. Instances, threats, and promotion of these behaviors are
|
We agree to restrict the following behaviors in our community. Instances, threats, and promotion of
|
||||||
violations of this Code of Conduct.
|
these behaviors are violations of this Code of Conduct.
|
||||||
|
|
||||||
1. **Harassment.** Violating explicitly expressed boundaries or engaging in unnecessary personal attention after any
|
1. **Harassment.** Violating explicitly expressed boundaries or engaging in unnecessary personal
|
||||||
clear request to stop.
|
attention after any clear request to stop.
|
||||||
2. **Character attacks.** Making insulting, demeaning, or pejorative comments directed at a community member or group of
|
2. **Character attacks.** Making insulting, demeaning, or pejorative comments directed at a
|
||||||
people.
|
community member or group of people.
|
||||||
3. **Stereotyping or discrimination.** Characterizing anyone's personality or behavior on the basis of immutable
|
3. **Stereotyping or discrimination.** Characterizing anyone's personality or behavior on the basis
|
||||||
identities or traits.
|
of immutable identities or traits.
|
||||||
4. **Sexualization.** Behaving in a way that would generally be considered inappropriately intimate in the context or
|
4. **Sexualization.** Behaving in a way that would generally be considered inappropriately intimate
|
||||||
purpose of the community.
|
in the context or purpose of the community.
|
||||||
5. **Violating confidentiality.** Sharing or acting on someone's personal or private information without their
|
5. **Violating confidentiality.** Sharing or acting on someone's personal or private information
|
||||||
permission.
|
without their permission.
|
||||||
6. **Endangerment.** Causing, encouraging, or threatening violence or other harm toward any person or group.
|
6. **Endangerment.** Causing, encouraging, or threatening violence or other harm toward any person
|
||||||
|
or group.
|
||||||
7. Behaving in other ways that **threaten the well-being** of our community.
|
7. Behaving in other ways that **threaten the well-being** of our community.
|
||||||
|
|
||||||
### Other Restrictions
|
### Other Restrictions
|
||||||
|
|
||||||
1. **Misleading identity.** Impersonating someone else for any reason, or pretending to be someone else to evade
|
1. **Misleading identity.** Impersonating someone else for any reason, or pretending to be someone
|
||||||
enforcement actions.
|
else to evade enforcement actions.
|
||||||
2. **Failing to credit sources.** Not properly crediting the sources of content you contribute.
|
2. **Failing to credit sources.** Not properly crediting the sources of content you contribute.
|
||||||
3. **Promotional materials.** Sharing marketing or other commercial content in a way that is outside the norms of the
|
3. **Promotional materials.** Sharing marketing or other commercial content in a way that is outside
|
||||||
community.
|
the norms of the community.
|
||||||
4. **Irresponsible communication.** Failing to responsibly present content which includes, links to, or describes any
|
4. **Irresponsible communication.** Failing to responsibly present content which includes, links to,
|
||||||
other restricted behaviors.
|
or describes any other restricted behaviors.
|
||||||
|
|
||||||
## Reporting
|
## Reporting
|
||||||
|
|
||||||
@@ -77,12 +80,13 @@ If something here is being broken, contact me directly. Do not open a public iss
|
|||||||
| Email | `kontakt@hellion-media.de` |
|
| Email | `kontakt@hellion-media.de` |
|
||||||
| Discord DM | `@j.j_kazama` |
|
| Discord DM | `@j.j_kazama` |
|
||||||
|
|
||||||
Reports stay private. I will acknowledge within a few weekdays (European business hours) and tell you what I plan to do.
|
Reports stay private. I will acknowledge within a few weekdays (European business hours) and tell
|
||||||
|
you what I plan to do.
|
||||||
|
|
||||||
## Enforcement
|
## Enforcement
|
||||||
|
|
||||||
I am the sole maintainer, so enforcement is a single-person process. I will pick the lightest measure that actually
|
I am the sole maintainer, so enforcement is a single-person process. I will pick the lightest
|
||||||
resolves the situation:
|
measure that actually resolves the situation:
|
||||||
|
|
||||||
1. Private note asking the behaviour to stop.
|
1. Private note asking the behaviour to stop.
|
||||||
2. Public correction in the affected thread.
|
2. Public correction in the affected thread.
|
||||||
@@ -95,16 +99,16 @@ Severe cases skip the lower steps. I will not negotiate over harassment or threa
|
|||||||
|
|
||||||
## Scope
|
## Scope
|
||||||
|
|
||||||
This Code of Conduct applies to all spaces the project owns or that I run on its behalf: the GitHub repository, GitHub
|
This Code of Conduct applies to all spaces the project owns or that I run on its behalf: the GitHub
|
||||||
Discussions, project-related Discord conversations, and the maintainer contact listed in [`SECURITY.md`](SECURITY.md).
|
repository, GitHub Discussions, project-related Discord conversations, and the maintainer contact
|
||||||
It also applies when someone is identifiably representing HellionChat elsewhere, for example when posting as a
|
listed in [`SECURITY.md`](SECURITY.md). It also applies when someone is identifiably representing
|
||||||
HellionChat maintainer in the Dalamud Discord.
|
HellionChat elsewhere, for example when posting as a HellionChat maintainer in the Dalamud Discord.
|
||||||
|
|
||||||
## Attribution
|
## Attribution
|
||||||
|
|
||||||
This Code of Conduct is adapted from the Contributor Covenant, version 3.0, available at
|
This Code of Conduct is adapted from the Contributor Covenant, version 3.0, available at
|
||||||
[https://www.contributor-covenant.org/version/3/0/](https://www.contributor-covenant.org/version/3/0/).
|
[https://www.contributor-covenant.org/version/3/0/](https://www.contributor-covenant.org/version/3/0/).
|
||||||
|
|
||||||
Contributor Covenant is stewarded by the Organization for Ethical Source and licensed under CC BY-SA 4.0. To view a copy
|
Contributor Covenant is stewarded by the Organization for Ethical Source and licensed under CC BY-SA
|
||||||
of this license, visit
|
4.0. To view a copy of this license, visit
|
||||||
[https://creativecommons.org/licenses/by-sa/4.0/](https://creativecommons.org/licenses/by-sa/4.0/).
|
[https://creativecommons.org/licenses/by-sa/4.0/](https://creativecommons.org/licenses/by-sa/4.0/).
|
||||||
|
|||||||
+70
-58
@@ -1,69 +1,75 @@
|
|||||||
# Contributing to HellionChat
|
# Contributing to HellionChat
|
||||||
|
|
||||||
Thanks for taking a look. HellionChat is a one-person side project developed under Hellion Forge. It started as a fork
|
Thanks for taking a look. HellionChat is a one-person side project developed under Hellion Forge. It
|
||||||
of [Chat 2](https://github.com/Infiziert90/ChatTwo) and has since become a standalone plugin under its own namespace,
|
started as a fork of [Chat 2](https://github.com/Infiziert90/ChatTwo) and has since become a
|
||||||
IPC channels and source tree (standalone-cut completed in v1.0.0). Forking HellionChat itself is explicitly permitted
|
standalone plugin under its own namespace, IPC channels and source tree (standalone-cut completed in
|
||||||
under the EUPL-1.2.
|
v1.0.0). Forking HellionChat itself is explicitly permitted under the EUPL-1.2.
|
||||||
|
|
||||||
This document explains what I am looking for, what I am not, and how to make a contribution land smoothly.
|
This document explains what I am looking for, what I am not, and how to make a contribution land
|
||||||
|
smoothly.
|
||||||
|
|
||||||
## Before You Open Anything
|
## Before You Open Anything
|
||||||
|
|
||||||
- Read the [README](README.md) so you understand the scope: a privacy-focused, EUPL-1.2-licensed Dalamud plugin that
|
- Read the [README](README.md) so you understand the scope: a privacy-focused, EUPL-1.2-licensed
|
||||||
intentionally removes the upstream webinterface and ships privacy-first defaults.
|
Dalamud plugin that intentionally removes the upstream webinterface and ships privacy-first
|
||||||
- Read [`docs/UPSTREAM_SYNC.md`](docs/UPSTREAM_SYNC.md). Active cherry-picking from upstream Chat 2 has ended in the
|
defaults.
|
||||||
v1.4.x cycle; HellionChat continues as an independent codebase. Existing upstream-derived code keeps its attribution.
|
- Read [`docs/UPSTREAM_SYNC.md`](docs/UPSTREAM_SYNC.md). Active cherry-picking from upstream Chat 2
|
||||||
New contributions stand on their own and do not need to be cherry-pick-compatible.
|
has ended in the v1.4.x cycle; HellionChat continues as an independent codebase. Existing
|
||||||
- Read [`SECURITY.md`](SECURITY.md). Anything security-sensitive goes through a private advisory, never a public issue
|
upstream-derived code keeps its attribution. New contributions stand on their own and do not need
|
||||||
or PR.
|
to be cherry-pick-compatible.
|
||||||
|
- Read [`SECURITY.md`](SECURITY.md). Anything security-sensitive goes through a private advisory,
|
||||||
|
never a public issue or PR.
|
||||||
- Read the [Code of Conduct](CODE_OF_CONDUCT.md).
|
- Read the [Code of Conduct](CODE_OF_CONDUCT.md).
|
||||||
|
|
||||||
## What I Will Accept
|
## What I Will Accept
|
||||||
|
|
||||||
- Bug fixes for behaviour documented in the README, the in-plugin settings or the changelog.
|
- Bug fixes for behaviour documented in the README, the in-plugin settings or the changelog.
|
||||||
- Translation contributions for Hellion-specific strings via direct pull requests against
|
- Translation contributions for Hellion-specific strings via direct pull requests against
|
||||||
`HellionChat/Resources/HellionStrings.*.resx`. Translations for upstream Chat 2 strings (`Language.*.resx`) are not
|
`HellionChat/Resources/HellionStrings.*.resx`. Translations for upstream Chat 2 strings
|
||||||
handled here; those go to the upstream Chat 2 project.
|
(`Language.*.resx`) are not handled here; those go to the upstream Chat 2 project.
|
||||||
- Documentation improvements (README, comments, this file).
|
- Documentation improvements (README, comments, this file).
|
||||||
- Performance fixes with a measurable before/after.
|
- Performance fixes with a measurable before/after.
|
||||||
- New features that fit the privacy-first scope and do not duplicate what an existing Dalamud plugin already does well.
|
- New features that fit the privacy-first scope and do not duplicate what an existing Dalamud plugin
|
||||||
|
already does well.
|
||||||
|
|
||||||
## What I Will Probably Decline
|
## What I Will Probably Decline
|
||||||
|
|
||||||
- Re-introducing the webinterface or any remote-access feature. It was removed in v0.2.0 on purpose. See the README
|
- Re-introducing the webinterface or any remote-access feature. It was removed in v0.2.0 on purpose.
|
||||||
section "Was gegenüber Chat 2 fehlt".
|
See the README section "Was gegenüber Chat 2 fehlt".
|
||||||
- Features that bypass the privacy filter or weaken the default retention behaviour without an explicit, documented
|
- Features that bypass the privacy filter or weaken the default retention behaviour without an
|
||||||
opt-in.
|
explicit, documented opt-in.
|
||||||
- Sweeping refactors that touch large parts of the codebase. The maintenance cost outweighs the benefit for a one-person
|
- Sweeping refactors that touch large parts of the codebase. The maintenance cost outweighs the
|
||||||
project. (This used to be doubly important because of the upstream cherry-pick path; that path is closed now, but the
|
benefit for a one-person project. (This used to be doubly important because of the upstream
|
||||||
rule still holds on its own merits.)
|
cherry-pick path; that path is closed now, but the rule still holds on its own merits.)
|
||||||
- AI-generated code dropped in without disclosure or human review. See [`docs/AI_DISCLOSURE.md`](docs/AI_DISCLOSURE.md)
|
- AI-generated code dropped in without disclosure or human review. See
|
||||||
for how I handle AI assistance on my side; I expect comparable transparency from contributors.
|
[`docs/AI_DISCLOSURE.md`](docs/AI_DISCLOSURE.md) for how I handle AI assistance on my side; I
|
||||||
|
expect comparable transparency from contributors.
|
||||||
|
|
||||||
If you are unsure whether an idea fits, open a feature-request issue first and ask before writing code. I would rather
|
If you are unsure whether an idea fits, open a feature-request issue first and ask before writing
|
||||||
say "no" to a proposal than to a finished pull request.
|
code. I would rather say "no" to a proposal than to a finished pull request.
|
||||||
|
|
||||||
## Workflow
|
## Workflow
|
||||||
|
|
||||||
1. Open an issue (bug or feature request) using the templates under `.github/ISSUE_TEMPLATE/`. Skip this for trivial
|
1. Open an issue (bug or feature request) using the templates under `.github/ISSUE_TEMPLATE/`. Skip
|
||||||
typos.
|
this for trivial typos.
|
||||||
2. Fork the repository and branch off `main`. Branch naming is informal; something like `fix/auto-tell-history-empty` or
|
2. Fork the repository and branch off `main`. Branch naming is informal; something like
|
||||||
`feat/theme-export` is fine.
|
`fix/auto-tell-history-empty` or `feat/theme-export` is fine.
|
||||||
3. Match the existing code style. The repository ships an `.editorconfig` that VS Code and Rider pick up automatically.
|
3. Match the existing code style. The repository ships an `.editorconfig` that VS Code and Rider
|
||||||
4. Keep commits focused. Several small commits with clear messages are easier to review than one large one.
|
pick up automatically.
|
||||||
Squash-on-merge happens at the PR level if needed.
|
4. Keep commits focused. Several small commits with clear messages are easier to review than one
|
||||||
|
large one. Squash-on-merge happens at the PR level if needed.
|
||||||
5. If your change touches user-visible behaviour, update the README and/or the changelog block in
|
5. If your change touches user-visible behaviour, update the README and/or the changelog block in
|
||||||
`HellionChat/HellionChat.yaml` and `repo.json`. I bump the version number myself at release time.
|
`HellionChat/HellionChat.yaml` and `repo.json`. I bump the version number myself at release time.
|
||||||
6. Open the pull request against `main`. The PR template will ask you to summarise the change, the testing you did and
|
6. Open the pull request against `main`. The PR template will ask you to summarise the change, the
|
||||||
any compatibility notes.
|
testing you did and any compatibility notes.
|
||||||
|
|
||||||
## Build and Test
|
## Build and Test
|
||||||
|
|
||||||
The project targets `net10.0-windows` against Dalamud SDK 15. To build locally you need:
|
The project targets `net10.0-windows` against Dalamud SDK 15. To build locally you need:
|
||||||
|
|
||||||
- .NET 10 SDK
|
- .NET 10 SDK
|
||||||
- A working Dalamud dev environment with `DALAMUD_HOME` set (XIVLauncher installed and launched once is the simplest
|
- A working Dalamud dev environment with `DALAMUD_HOME` set (XIVLauncher installed and launched once
|
||||||
path)
|
is the simplest path)
|
||||||
- VS Code with the C# Dev Kit, Rider, or Visual Studio
|
- VS Code with the C# Dev Kit, Rider, or Visual Studio
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -71,11 +77,12 @@ dotnet restore
|
|||||||
dotnet build HellionChat.sln -c Release
|
dotnet build HellionChat.sln -c Release
|
||||||
```
|
```
|
||||||
|
|
||||||
There are currently no tests in `HellionChat.sln`. If you add a test project, point it at the relevant subsystems
|
There are currently no tests in `HellionChat.sln`. If you add a test project, point it at the
|
||||||
(privacy filter, configuration migration, message store) and mention it in the PR.
|
relevant subsystems (privacy filter, configuration migration, message store) and mention it in the
|
||||||
|
PR.
|
||||||
|
|
||||||
For a smoke test in-game: build, copy the output into your Dalamud `devPlugins/HellionChat/` directory and load it via
|
For a smoke test in-game: build, copy the output into your Dalamud `devPlugins/HellionChat/`
|
||||||
`/xlplugins`.
|
directory and load it via `/xlplugins`.
|
||||||
|
|
||||||
## Continuous Integration
|
## Continuous Integration
|
||||||
|
|
||||||
@@ -86,30 +93,33 @@ Every push and every pull request runs:
|
|||||||
| `build.yml` | `dotnet build` and `dotnet test` |
|
| `build.yml` | `dotnet build` and `dotnet test` |
|
||||||
| `codeql.yml` | CodeQL security analysis |
|
| `codeql.yml` | CodeQL security analysis |
|
||||||
|
|
||||||
A pull request will not be merged while either of these is failing. CodeQL findings on changed code need to be
|
A pull request will not be merged while either of these is failing. CodeQL findings on changed code
|
||||||
addressed; pre-existing findings on untouched code are tracked separately.
|
need to be addressed; pre-existing findings on untouched code are tracked separately.
|
||||||
|
|
||||||
## Translations
|
## Translations
|
||||||
|
|
||||||
Hellion-specific strings live in `HellionChat/Resources/HellionStrings.resx` (English source) and
|
Hellion-specific strings live in `HellionChat/Resources/HellionStrings.resx` (English source) and
|
||||||
`HellionStrings.<lang>.resx` (per-language). These are accepted as direct pull requests.
|
`HellionStrings.<lang>.resx` (per-language). These are accepted as direct pull requests.
|
||||||
|
|
||||||
The upstream Chat 2 strings in `HellionChat/Resources/Language.*.resx` are **not** translated here. They are kept as-is
|
The upstream Chat 2 strings in `HellionChat/Resources/Language.*.resx` are **not** translated here.
|
||||||
from the last upstream sync and remain the work of the Chat 2 Crowdin community. Active cherry-picking from upstream
|
They are kept as-is from the last upstream sync and remain the work of the Chat 2 Crowdin community.
|
||||||
ended in the v1.4.x cycle (see [`docs/UPSTREAM_SYNC.md`](docs/UPSTREAM_SYNC.md)), so future translation improvements to
|
Active cherry-picking from upstream ended in the v1.4.x cycle (see
|
||||||
those upstream strings will not flow into HellionChat automatically anymore. If you have improvements for the original
|
[`docs/UPSTREAM_SYNC.md`](docs/UPSTREAM_SYNC.md)), so future translation improvements to those
|
||||||
Chat 2 strings, please contribute them to [Infiziert90/ChatTwo](https://github.com/Infiziert90/ChatTwo) directly.
|
upstream strings will not flow into HellionChat automatically anymore. If you have improvements for
|
||||||
|
the original Chat 2 strings, please contribute them to
|
||||||
|
[Infiziert90/ChatTwo](https://github.com/Infiziert90/ChatTwo) directly.
|
||||||
|
|
||||||
## Licensing
|
## Licensing
|
||||||
|
|
||||||
By submitting a pull request you confirm that:
|
By submitting a pull request you confirm that:
|
||||||
|
|
||||||
- Your contribution is your own work, or you have the right to contribute it under the project licence.
|
- Your contribution is your own work, or you have the right to contribute it under the project
|
||||||
- You agree that your contribution will be released under the [EUPL-1.2](LICENSE), the same licence as the rest of the
|
licence.
|
||||||
project.
|
- You agree that your contribution will be released under the [EUPL-1.2](LICENSE), the same licence
|
||||||
|
as the rest of the project.
|
||||||
|
|
||||||
There is no separate CLA. Forking HellionChat is explicitly permitted under the EUPL-1.2, as with any EUPL-licensed
|
There is no separate CLA. Forking HellionChat is explicitly permitted under the EUPL-1.2, as with
|
||||||
project.
|
any EUPL-licensed project.
|
||||||
|
|
||||||
## Response Times
|
## Response Times
|
||||||
|
|
||||||
@@ -119,8 +129,9 @@ project.
|
|||||||
| Discord DM | `@j.j_kazama` |
|
| Discord DM | `@j.j_kazama` |
|
||||||
| Email | `kontakt@hellion-media.de` |
|
| Email | `kontakt@hellion-media.de` |
|
||||||
|
|
||||||
I respond on weekdays during European business hours and take weekends and FFXIV patch days off. A pull request that
|
I respond on weekdays during European business hours and take weekends and FFXIV patch days off. A
|
||||||
sits for a few days has not been ignored. Pinging once after a week is fine; please do not ping daily.
|
pull request that sits for a few days has not been ignored. Pinging once after a week is fine;
|
||||||
|
please do not ping daily.
|
||||||
|
|
||||||
## First-time setup
|
## First-time setup
|
||||||
|
|
||||||
@@ -130,9 +141,10 @@ After cloning, run once:
|
|||||||
./scripts/setup-hooks.sh
|
./scripts/setup-hooks.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
This wires `core.hooksPath` to `.githooks/`. The pre-push hook runs preflight (versions/manifest/changelog/build).
|
This wires `core.hooksPath` to `.githooks/`. The pre-push hook runs preflight
|
||||||
|
(versions/manifest/changelog/build).
|
||||||
|
|
||||||
### Test suite
|
### Test suite
|
||||||
|
|
||||||
The plugin's test suite lives in a separate local repository and is not part of this codebase. If you need access for
|
The plugin's test suite lives in a separate local repository and is not part of this codebase. If
|
||||||
development, contact the maintainer.
|
you need access for development, contact the maintainer.
|
||||||
|
|||||||
@@ -3,82 +3,90 @@
|
|||||||
## Acknowledgements
|
## Acknowledgements
|
||||||
|
|
||||||
HellionChat is a fork of [Chat 2](https://github.com/Infiziert90/ChatTwo) by
|
HellionChat is a fork of [Chat 2](https://github.com/Infiziert90/ChatTwo) by
|
||||||
**[Infiziert90 (Infi)](https://github.com/Infiziert90)** and **[Anna](https://github.com/anna-is-cute)**, both of whom
|
**[Infiziert90 (Infi)](https://github.com/Infiziert90)** and
|
||||||
kept that plugin running and maintained for years before I ever opened the source. Without their work this fork would
|
**[Anna](https://github.com/anna-is-cute)**, both of whom kept that plugin running and maintained
|
||||||
not exist, full stop. I owe them the architecture, the message store, the channel filtering, the sidebar tab system, the
|
for years before I ever opened the source. Without their work this fork would not exist, full stop.
|
||||||
hooks into FFXIV's chat, the localisation infrastructure, and countless small decisions that I only noticed because they
|
I owe them the architecture, the message store, the channel filtering, the sidebar tab system, the
|
||||||
had already been made correctly.
|
hooks into FFXIV's chat, the localisation infrastructure, and countless small decisions that I only
|
||||||
|
noticed because they had already been made correctly.
|
||||||
|
|
||||||
If you find HellionChat useful, please remember that the foundation came from Chat 2. The code Anna and Infi wrote is
|
If you find HellionChat useful, please remember that the foundation came from Chat 2. The code Anna
|
||||||
doing most of the heavy lifting in this fork too.
|
and Infi wrote is doing most of the heavy lifting in this fork too.
|
||||||
|
|
||||||
## A direct word to Infi and Anna
|
## A direct word to Infi and Anna
|
||||||
|
|
||||||
Hi. I am Florian. I forked Chat 2 because I wanted a privacy-by-default version for my own use case and a small group of
|
Hi. I am Florian. I forked Chat 2 because I wanted a privacy-by-default version for my own use case
|
||||||
friends I play with, not because I thought I could do anything better than what you built. The opposite is true.
|
and a small group of friends I play with, not because I thought I could do anything better than what
|
||||||
ChatTwo's default of full history and cross-character logging is the right call for most users. I just have a different
|
you built. The opposite is true. ChatTwo's default of full history and cross-character logging is
|
||||||
threat model and a different data-handling philosophy that fits a smaller, locally-stored, retention- limited approach.
|
the right call for most users. I just have a different threat model and a different data-handling
|
||||||
|
philosophy that fits a smaller, locally-stored, retention- limited approach.
|
||||||
|
|
||||||
What HellionChat adds is mostly Hellion-specific surface area: a privacy filter, per-channel retention windows, an
|
What HellionChat adds is mostly Hellion-specific surface area: a privacy filter, per-channel
|
||||||
export pipeline, an Auto-Tell- Tabs feature for FFXIV club greeters, the Hellion theme and font, German localisation,
|
retention windows, an export pipeline, an Auto-Tell- Tabs feature for FFXIV club greeters, the
|
||||||
and a settings UX rebuild. None of it touches the bones of what you built. Where I had to modify your code I tried to
|
Hellion theme and font, German localisation, and a settings UX rebuild. None of it touches the bones
|
||||||
keep the edits minimal, isolated to clearly-marked Hellion files, and reversible.
|
of what you built. Where I had to modify your code I tried to keep the edits minimal, isolated to
|
||||||
|
clearly-marked Hellion files, and reversible.
|
||||||
|
|
||||||
Concrete example: when API 15 hit, I cherry-picked your fix for the BetterTTV emote regression with `git cherry-pick -x`
|
Concrete example: when API 15 hit, I cherry-picked your fix for the BetterTTV emote regression with
|
||||||
so authorship and co-author trail stay intact. That was the standard I held to as long as cherry-picking was viable, and
|
`git cherry-pick -x` so authorship and co-author trail stay intact. That was the standard I held to
|
||||||
you should never have to look at this fork and wonder if I quietly ate your work.
|
as long as cherry-picking was viable, and you should never have to look at this fork and wonder if I
|
||||||
|
quietly ate your work.
|
||||||
|
|
||||||
With ChatTwo entering its rework cycle, the active cherry-pick pipeline is closed since v1.4.x — see
|
With ChatTwo entering its rework cycle, the active cherry-pick pipeline is closed since v1.4.x — see
|
||||||
[docs/UPSTREAM_SYNC.md](docs/UPSTREAM_SYNC.md) for the full reasoning. The attribution standard stays exactly the same:
|
[docs/UPSTREAM_SYNC.md](docs/UPSTREAM_SYNC.md) for the full reasoning. The attribution standard
|
||||||
every existing `(cherry picked from commit ...)` line remains in the git history, the EUPL-1.2 anchor lines in source
|
stays exactly the same: every existing `(cherry picked from commit ...)` line remains in the git
|
||||||
files are untouched, and this NOTICE.md remains canonical. If anything from this point forward originates from Chat 2 it
|
history, the EUPL-1.2 anchor lines in source files are untouched, and this NOTICE.md remains
|
||||||
will be a hand-port at most, called out as such in the commit message and source comments, not a `git cherry-pick`.
|
canonical. If anything from this point forward originates from Chat 2 it will be a hand-port at
|
||||||
|
most, called out as such in the commit message and source comments, not a `git cherry-pick`.
|
||||||
|
|
||||||
If anything in this fork ever steps on something you would not be okay with, please reach out and I will fix it.
|
If anything in this fork ever steps on something you would not be okay with, please reach out and I
|
||||||
Genuinely. The list of contacts is below.
|
will fix it. Genuinely. The list of contacts is below.
|
||||||
|
|
||||||
## Maintainer contact
|
## Maintainer contact
|
||||||
|
|
||||||
If something in HellionChat causes problems, especially if it relates back to Chat 2 or to anything Infi or Anna would
|
If something in HellionChat causes problems, especially if it relates back to Chat 2 or to anything
|
||||||
want flagged:
|
Infi or Anna would want flagged:
|
||||||
|
|
||||||
- **Gitea Issues:**
|
- **Gitea Issues:**
|
||||||
[JonKazama-Hellion/HellionChat/issues](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/issues)
|
[JonKazama-Hellion/HellionChat/issues](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/issues)
|
||||||
- **Discord:** `@j.j_kazama`
|
- **Discord:** `@j.j_kazama`
|
||||||
- **Email (business):** <kontakt@hellion-media.de>
|
- **Email (business):** <kontakt@hellion-media.de>
|
||||||
|
|
||||||
I respond on weekdays during European business hours. For anything urgent (security, attribution, takedown), email is
|
I respond on weekdays during European business hours. For anything urgent (security, attribution,
|
||||||
the fastest path.
|
takedown), email is the fastest path.
|
||||||
|
|
||||||
## Why this fork is not upstreamed
|
## Why this fork is not upstreamed
|
||||||
|
|
||||||
The privacy-by-default position fits a small audience. ChatTwo's full-history-by-default position fits a much larger
|
The privacy-by-default position fits a small audience. ChatTwo's full-history-by-default position
|
||||||
one, including the roleplaying community where chat archive is part of the play experience. Trying to upstream
|
fits a much larger one, including the roleplaying community where chat archive is part of the play
|
||||||
HellionChat's defaults would have meant arguing that Chat 2's defaults are wrong, and they are not. They are right for
|
experience. Trying to upstream HellionChat's defaults would have meant arguing that Chat 2's
|
||||||
the user base ChatTwo serves. So I keep the fork separate and attribute clearly. Active cherry-picking from upstream
|
defaults are wrong, and they are not. They are right for the user base ChatTwo serves. So I keep the
|
||||||
stopped in the v1.4.x cycle once Chat 2's rework made selective patches no longer portable; the existing cherry-pick
|
fork separate and attribute clearly. Active cherry-picking from upstream stopped in the v1.4.x cycle
|
||||||
trail stays in the git history.
|
once Chat 2's rework made selective patches no longer portable; the existing cherry-pick trail stays
|
||||||
|
in the git history.
|
||||||
|
|
||||||
## Why HellionChat left the GitHub fork network
|
## Why HellionChat left the GitHub fork network
|
||||||
|
|
||||||
The Dalamud plugin ecosystem treats the GitHub-Fork relation as a signal that a fork is either a development branch or a
|
The Dalamud plugin ecosystem treats the GitHub-Fork relation as a signal that a fork is either a
|
||||||
dead mirror. HellionChat is neither. It is an independently-maintained EUPL-1.2 fork with its own release cadence, its
|
development branch or a dead mirror. HellionChat is neither. It is an independently-maintained
|
||||||
own custom repo, its own user base. Detaching the fork-network relation just makes the situation honest. The git
|
EUPL-1.2 fork with its own release cadence, its own custom repo, its own user base. Detaching the
|
||||||
history, the existing cherry-pick trail, and the attribution stay exactly the same. The only thing that changes is the
|
fork-network relation just makes the situation honest. The git history, the existing cherry-pick
|
||||||
GitHub UI no longer says "forked from".
|
trail, and the attribution stay exactly the same. The only thing that changes is the GitHub UI no
|
||||||
|
longer says "forked from".
|
||||||
|
|
||||||
## Trademarks and naming
|
## Trademarks and naming
|
||||||
|
|
||||||
"Chat 2" and "ChatTwo" are the names Infi and Anna chose for the upstream plugin. HellionChat does not use either of
|
"Chat 2" and "ChatTwo" are the names Infi and Anna chose for the upstream plugin. HellionChat does
|
||||||
those names in user-facing copy except where required to describe origin (settings tab, manifest, this file, the
|
not use either of those names in user-facing copy except where required to describe origin (settings
|
||||||
README). The Hellion brand is mine.
|
tab, manifest, this file, the README). The Hellion brand is mine.
|
||||||
|
|
||||||
## Questions
|
## Questions
|
||||||
|
|
||||||
This file is the canonical place for "is this attribution correct, is the maintainer reachable, is the relationship to
|
This file is the canonical place for "is this attribution correct, is the maintainer reachable, is
|
||||||
Chat 2 documented". If anything in here is wrong, please open an issue or contact me directly.
|
the relationship to Chat 2 documented". If anything in here is wrong, please open an issue or
|
||||||
|
contact me directly.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Maintained under **Hellion Forge**, the modding and plugin line of **Hellion Online Media** | Bad Harzburg |
|
Maintained under **Hellion Forge**, the modding and plugin line of **Hellion Online Media** | Bad
|
||||||
[hellion-media.de](https://hellion-media.de)
|
Harzburg | [hellion-media.de](https://hellion-media.de)
|
||||||
|
|||||||
+112
-96
@@ -1,12 +1,14 @@
|
|||||||
# Privacy notice
|
# Privacy notice
|
||||||
|
|
||||||
HellionChat is a Dalamud plugin for FINAL FANTASY XIV, focused on giving the user explicit control over what their chat
|
HellionChat is a Dalamud plugin for FINAL FANTASY XIV, focused on giving the user explicit control
|
||||||
client stores locally. This document describes what the plugin does with your data, what it does not do, and how you
|
over what their chat client stores locally. This document describes what the plugin does with your
|
||||||
exercise the rights the GDPR gives you over data you generate yourself.
|
data, what it does not do, and how you exercise the rights the GDPR gives you over data you generate
|
||||||
|
yourself.
|
||||||
|
|
||||||
This document is informational. The maintainer of HellionChat is **not** a controller or processor of your data in the
|
This document is informational. The maintainer of HellionChat is **not** a controller or processor
|
||||||
GDPR sense, because no data ever leaves your machine on the maintainer's infrastructure. Independently of that, the
|
of your data in the GDPR sense, because no data ever leaves your machine on the maintainer's
|
||||||
plugin is built so that you can act on your own data the way the GDPR expects.
|
infrastructure. Independently of that, the plugin is built so that you can act on your own data the
|
||||||
|
way the GDPR expects.
|
||||||
|
|
||||||
Last reviewed: 2026-05-05 (HellionChat v1.1.0).
|
Last reviewed: 2026-05-05 (HellionChat v1.1.0).
|
||||||
|
|
||||||
@@ -14,34 +16,37 @@ Last reviewed: 2026-05-05 (HellionChat v1.1.0).
|
|||||||
|
|
||||||
## TL;DR
|
## TL;DR
|
||||||
|
|
||||||
- All chat data the plugin stores stays on your machine, in your Dalamud `pluginConfigs/HellionChat/` directory.
|
- All chat data the plugin stores stays on your machine, in your Dalamud
|
||||||
- The plugin does not phone home. No telemetry, no analytics, no crash reporter, no usage counter, no remote update
|
`pluginConfigs/HellionChat/` directory.
|
||||||
check beyond what Dalamud itself does.
|
- The plugin does not phone home. No telemetry, no analytics, no crash reporter, no usage counter,
|
||||||
- One outbound network call exists by design: the BetterTTV emote service (for chat emotes). It is documented in detail
|
no remote update check beyond what Dalamud itself does.
|
||||||
below and can be reasoned about per request.
|
- One outbound network call exists by design: the BetterTTV emote service (for chat emotes). It is
|
||||||
- You can export every message the plugin has stored, in Markdown, JSON or CSV, and you can wipe stored history per
|
documented in detail below and can be reasoned about per request.
|
||||||
channel, per date range, or globally.
|
- You can export every message the plugin has stored, in Markdown, JSON or CSV, and you can wipe
|
||||||
|
stored history per channel, per date range, or globally.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## What the plugin stores locally
|
## What the plugin stores locally
|
||||||
|
|
||||||
HellionChat keeps three kinds of state on your machine, all under `%appdata%\XIVLauncher\pluginConfigs\HellionChat\` on
|
HellionChat keeps three kinds of state on your machine, all under
|
||||||
Windows (`~/.xlcore/pluginConfigs/HellionChat/` on Linux/macOS via XIVLauncher Core):
|
`%appdata%\XIVLauncher\pluginConfigs\HellionChat\` on Windows
|
||||||
|
(`~/.xlcore/pluginConfigs/HellionChat/` on Linux/macOS via XIVLauncher Core):
|
||||||
|
|
||||||
1. **Configuration** (`HellionChat.json`). Plugin settings, channel whitelist, retention values, layout state, theme
|
1. **Configuration** (`HellionChat.json`). Plugin settings, channel whitelist, retention values,
|
||||||
colours. Contains no chat content.
|
layout state, theme colours. Contains no chat content.
|
||||||
|
|
||||||
2. **Message database** (SQLite file in the same directory). Chat messages from the channels on your whitelist, stored
|
2. **Message database** (SQLite file in the same directory). Chat messages from the channels on your
|
||||||
as MessagePack-encoded blobs. The default whitelist out of the box covers only your own conversations: tells, party,
|
whitelist, stored as MessagePack-encoded blobs. The default whitelist out of the box covers only
|
||||||
free company, linkshells, cross-world linkshells, alliance, ExtraChat. Public chat, NPC dialogue, system messages and
|
your own conversations: tells, party, free company, linkshells, cross-world linkshells, alliance,
|
||||||
battle logs are dropped on the storage layer and never written to disk.
|
ExtraChat. Public chat, NPC dialogue, system messages and battle logs are dropped on the storage
|
||||||
|
layer and never written to disk.
|
||||||
|
|
||||||
3. **Cached emote images** (`EmoteCacheV1/` directory). Image files downloaded from BetterTTV when an emote appears in a
|
3. **Cached emote images** (`EmoteCacheV1/` directory). Image files downloaded from BetterTTV when
|
||||||
message you receive. See "Outbound network calls" below.
|
an emote appears in a message you receive. See "Outbound network calls" below.
|
||||||
|
|
||||||
There is no shared state with the upstream Chat 2 plugin. `pluginConfigs/HellionChat/` is independent from
|
There is no shared state with the upstream Chat 2 plugin. `pluginConfigs/HellionChat/` is
|
||||||
`pluginConfigs/ChatTwo/`.
|
independent from `pluginConfigs/ChatTwo/`.
|
||||||
|
|
||||||
### Retention defaults
|
### Retention defaults
|
||||||
|
|
||||||
@@ -49,44 +54,49 @@ There is no shared state with the upstream Chat 2 plugin. `pluginConfigs/Hellion
|
|||||||
- Your-conversation channels (party, FC, linkshells, cross-world LS, alliance, ExtraChat): 90 days
|
- Your-conversation channels (party, FC, linkshells, cross-world LS, alliance, ExtraChat): 90 days
|
||||||
- Global default for anything else: 30 days
|
- Global default for anything else: 30 days
|
||||||
|
|
||||||
**Retention is off by default.** The plugin does not delete anything on its own until you explicitly turn the retention
|
**Retention is off by default.** The plugin does not delete anything on its own until you explicitly
|
||||||
sweep on in the settings. Until then, stored messages stay until you clear them.
|
turn the retention sweep on in the settings. Until then, stored messages stay until you clear them.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## What the plugin does not store
|
## What the plugin does not store
|
||||||
|
|
||||||
- Public chat (`/say`, `/yell`, `/shout`), NPC dialogue, system messages and battle logs. These are filtered before they
|
- Public chat (`/say`, `/yell`, `/shout`), NPC dialogue, system messages and battle logs. These are
|
||||||
reach the storage layer.
|
filtered before they reach the storage layer.
|
||||||
- Anything from channels you remove from the whitelist. The privacy filter runs on the way in, not on the way out.
|
- Anything from channels you remove from the whitelist. The privacy filter runs on the way in, not
|
||||||
- Login credentials, character IDs, account IDs. The plugin uses whatever Dalamud already exposes about the local
|
on the way out.
|
||||||
character to attribute messages. Nothing of that is sent anywhere or persisted beyond the message itself.
|
- Login credentials, character IDs, account IDs. The plugin uses whatever Dalamud already exposes
|
||||||
|
about the local character to attribute messages. Nothing of that is sent anywhere or persisted
|
||||||
|
beyond the message itself.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Outbound network calls
|
## Outbound network calls
|
||||||
|
|
||||||
HellionChat makes two kinds of automatic outbound network requests. Both are inherited from upstream Chat 2 and both are
|
HellionChat makes two kinds of automatic outbound network requests. Both are inherited from upstream
|
||||||
documented here because "GDPR-by-design" means you should know what your client does on your behalf.
|
Chat 2 and both are documented here because "GDPR-by-design" means you should know what your client
|
||||||
|
does on your behalf.
|
||||||
|
|
||||||
### 1. BetterTTV emote service (`api.betterttv.net`, `cdn.betterttv.net`)
|
### 1. BetterTTV emote service (`api.betterttv.net`, `cdn.betterttv.net`)
|
||||||
|
|
||||||
- **What it does:** When a chat message arrives that references a BetterTTV emote, the plugin asks the BetterTTV API for
|
- **What it does:** When a chat message arrives that references a BetterTTV emote, the plugin asks
|
||||||
the emote metadata and downloads the image from the BetterTTV CDN to display it inline.
|
the BetterTTV API for the emote metadata and downloads the image from the BetterTTV CDN to display
|
||||||
- **What is sent:** A standard HTTPS GET request. Your IP address reaches BetterTTV (unavoidable for any HTTPS request);
|
it inline.
|
||||||
the request itself contains no identifying user data, no character name, no message text. Only the emote ID being
|
- **What is sent:** A standard HTTPS GET request. Your IP address reaches BetterTTV (unavoidable for
|
||||||
looked up is in the URL path.
|
any HTTPS request); the request itself contains no identifying user data, no character name, no
|
||||||
|
message text. Only the emote ID being looked up is in the URL path.
|
||||||
- **When it triggers:**
|
- **When it triggers:**
|
||||||
- The emote _list_ (global emotes plus the top-1500 community emotes over fifteen API pages) is fetched from
|
- The emote _list_ (global emotes plus the top-1500 community emotes over fifteen API pages) is
|
||||||
`api.betterttv.net` once per session at plugin startup, provided the **Show emotes** option is on. This first
|
fetched from `api.betterttv.net` once per session at plugin startup, provided the **Show
|
||||||
list-fetch happens before any chat message has arrived. BetterTTV's edge therefore sees your IP as soon as the
|
emotes** option is on. This first list-fetch happens before any chat message has arrived.
|
||||||
plugin loads, not only after an emote is mentioned.
|
BetterTTV's edge therefore sees your IP as soon as the plugin loads, not only after an emote is
|
||||||
- The individual emote _images_ on `cdn.betterttv.net` are fetched on demand, only when an incoming chat message
|
mentioned.
|
||||||
contains a token matching one of the cached IDs. These are cached locally (`emoteCache/`) and reused across
|
- The individual emote _images_ on `cdn.betterttv.net` are fetched on demand, only when an
|
||||||
sessions.
|
incoming chat message contains a token matching one of the cached IDs. These are cached locally
|
||||||
|
(`emoteCache/`) and reused across sessions.
|
||||||
- **Cached:** Yes, in `emoteCache/`. A given emote is downloaded once per machine and reused.
|
- **Cached:** Yes, in `emoteCache/`. A given emote is downloaded once per machine and reused.
|
||||||
- **How to opt out:** Turn off the **Show emotes** option in Settings → Chat. With it disabled, the emote cache does not
|
- **How to opt out:** Turn off the **Show emotes** option in Settings → Chat. With it disabled, the
|
||||||
load and no requests to BetterTTV are made for the rest of the session.
|
emote cache does not load and no requests to BetterTTV are made for the rest of the session.
|
||||||
- **BetterTTV's privacy policy:** <https://betterttv.com/privacy>
|
- **BetterTTV's privacy policy:** <https://betterttv.com/privacy>
|
||||||
|
|
||||||
Source: `HellionChat/EmoteCache.cs`.
|
Source: `HellionChat/EmoteCache.cs`.
|
||||||
@@ -94,69 +104,73 @@ Source: `HellionChat/EmoteCache.cs`.
|
|||||||
### 2. Square Enix Lodestone font (removed in v1.0.4)
|
### 2. Square Enix Lodestone font (removed in v1.0.4)
|
||||||
|
|
||||||
Earlier versions of HellionChat (and upstream Chat 2) downloaded `FFXIV_Lodestone_SSF.ttf` from
|
Earlier versions of HellionChat (and upstream Chat 2) downloaded `FFXIV_Lodestone_SSF.ttf` from
|
||||||
`img.finalfantasyxiv.com` once during font setup. That code path was a leftover from upstream's removed webinterface
|
`img.finalfantasyxiv.com` once during font setup. That code path was a leftover from upstream's
|
||||||
feature and was no longer consumed anywhere. The in-game symbol glyphs (job icons, item glyphs, status effects) come
|
removed webinterface feature and was no longer consumed anywhere. The in-game symbol glyphs (job
|
||||||
from Dalamud's bundled symbol-font helper, not from the downloaded TTF.
|
icons, item glyphs, status effects) come from Dalamud's bundled symbol-font helper, not from the
|
||||||
|
downloaded TTF.
|
||||||
|
|
||||||
The download was removed in v1.0.4. As of that version HellionChat makes no automatic network call to Square Enix or to
|
The download was removed in v1.0.4. As of that version HellionChat makes no automatic network call
|
||||||
any `finalfantasyxiv.com` host.
|
to Square Enix or to any `finalfantasyxiv.com` host.
|
||||||
|
|
||||||
Cached `FFXIV_Lodestone_SSF.ttf` files left over from earlier versions remain in `pluginConfigs/HellionChat/` until
|
Cached `FFXIV_Lodestone_SSF.ttf` files left over from earlier versions remain in
|
||||||
manually deleted. They are no longer read.
|
`pluginConfigs/HellionChat/` until manually deleted. They are no longer read.
|
||||||
|
|
||||||
### Links you click yourself (no automatic traffic)
|
### Links you click yourself (no automatic traffic)
|
||||||
|
|
||||||
The settings panel contains a few buttons that open external pages in your browser when you click them: the upstream
|
The settings panel contains a few buttons that open external pages in your browser when you click
|
||||||
Chat 2 GitHub repo, the upstream maintainers' Ko-fi pages, the HellionChat issue tracker and `hellion-media.de`. Nothing
|
them: the upstream Chat 2 GitHub repo, the upstream maintainers' Ko-fi pages, the HellionChat issue
|
||||||
happens until you click. They are documented here for completeness, not because they generate background traffic.
|
tracker and `hellion-media.de`. Nothing happens until you click. They are documented here for
|
||||||
|
completeness, not because they generate background traffic.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## What the plugin does not do
|
## What the plugin does not do
|
||||||
|
|
||||||
- **No telemetry.** Source verified: no calls to AppInsights, Sentry, PostHog, Plausible, Google Analytics, Microsoft
|
- **No telemetry.** Source verified: no calls to AppInsights, Sentry, PostHog, Plausible, Google
|
||||||
Clarity or any comparable service exist in the codebase, nor in the direct dependencies the plugin pulls in. See
|
Analytics, Microsoft Clarity or any comparable service exist in the codebase, nor in the direct
|
||||||
`docs/THIRD_PARTY_NOTICES.md`.
|
dependencies the plugin pulls in. See `docs/THIRD_PARTY_NOTICES.md`.
|
||||||
- **No crash reporting.** Crashes go to Dalamud's local `xllog`, not to a remote endpoint controlled by HellionChat.
|
- **No crash reporting.** Crashes go to Dalamud's local `xllog`, not to a remote endpoint controlled
|
||||||
- **No usage counters.** The plugin does not count installs, sessions, feature usage, channel activity or anything else
|
by HellionChat.
|
||||||
for the maintainer.
|
- **No usage counters.** The plugin does not count installs, sessions, feature usage, channel
|
||||||
- **No phone-home update check.** Updates are delivered through Dalamud's plugin installer, which polls the custom-repo
|
activity or anything else for the maintainer.
|
||||||
`repo.json` on GitHub. That is GitHub's traffic and falls under GitHub's privacy policy. The plugin code does no
|
- **No phone-home update check.** Updates are delivered through Dalamud's plugin installer, which
|
||||||
separate update check.
|
polls the custom-repo `repo.json` on GitHub. That is GitHub's traffic and falls under GitHub's
|
||||||
- **No background sync.** Messages stay on your machine. No cloud backup, no sharing feature, no remote viewer.
|
privacy policy. The plugin code does no separate update check.
|
||||||
|
- **No background sync.** Messages stay on your machine. No cloud backup, no sharing feature, no
|
||||||
|
remote viewer.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Your data, your rights
|
## Your data, your rights
|
||||||
|
|
||||||
The GDPR gives you specific rights over data about you. Because HellionChat stores everything locally, those rights
|
The GDPR gives you specific rights over data about you. Because HellionChat stores everything
|
||||||
translate directly into plugin features:
|
locally, those rights translate directly into plugin features:
|
||||||
|
|
||||||
### Right to access (Art. 15)
|
### Right to access (Art. 15)
|
||||||
|
|
||||||
Use the export feature in the plugin settings. You can export to **Markdown**, **JSON** or **CSV**, filtered by channel,
|
Use the export feature in the plugin settings. You can export to **Markdown**, **JSON** or **CSV**,
|
||||||
date range or sender substring. The export goes through a Dalamud file dialog and writes wherever you point it, on your
|
filtered by channel, date range or sender substring. The export goes through a Dalamud file dialog
|
||||||
machine.
|
and writes wherever you point it, on your machine.
|
||||||
|
|
||||||
### Right to erasure (Art. 17)
|
### Right to erasure (Art. 17)
|
||||||
|
|
||||||
Two options:
|
Two options:
|
||||||
|
|
||||||
1. **Targeted deletion.** The "retroactive cleanup" feature lets you apply your current whitelist to the existing
|
1. **Targeted deletion.** The "retroactive cleanup" feature lets you apply your current whitelist to
|
||||||
database. It shows a preview of what will be removed before you confirm with Ctrl+Shift, runs in the background, and
|
the existing database. It shows a preview of what will be removed before you confirm with
|
||||||
calls `VACUUM` afterwards to actually shrink the file.
|
Ctrl+Shift, runs in the background, and calls `VACUUM` afterwards to actually shrink the file.
|
||||||
2. **Full deletion.** Close the game and delete the `pluginConfigs/HellionChat/` directory. The next plugin start will
|
2. **Full deletion.** Close the game and delete the `pluginConfigs/HellionChat/` directory. The next
|
||||||
produce a fresh, empty configuration.
|
plugin start will produce a fresh, empty configuration.
|
||||||
|
|
||||||
### Right to portability (Art. 20)
|
### Right to portability (Art. 20)
|
||||||
|
|
||||||
The JSON and CSV exports are open formats. The Markdown export is human-readable and machine-parseable. Nothing is
|
The JSON and CSV exports are open formats. The Markdown export is human-readable and
|
||||||
locked into a proprietary container.
|
machine-parseable. Nothing is locked into a proprietary container.
|
||||||
|
|
||||||
### Right to object / restrict processing (Art. 21, 18)
|
### Right to object / restrict processing (Art. 21, 18)
|
||||||
|
|
||||||
Adjust the channel whitelist or set retention to a low value. Both take effect immediately on new messages. Existing
|
Adjust the channel whitelist or set retention to a low value. Both take effect immediately on new
|
||||||
data needs the retroactive cleanup to apply retroactively, by design.
|
messages. Existing data needs the retroactive cleanup to apply retroactively, by design.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -168,32 +182,34 @@ data needs the retroactive cleanup to apply retroactively, by design.
|
|||||||
| Hellion Forge (Gitea, self-hosted by Hellion Online Media) | Plugin distribution via custom repo, issue tracker | Whatever the Gitea instance sees from any HTTPS request to a public repo | <https://hellion-media.de/datenschutz> |
|
| Hellion Forge (Gitea, self-hosted by Hellion Online Media) | Plugin distribution via custom repo, issue tracker | Whatever the Gitea instance sees from any HTTPS request to a public repo | <https://hellion-media.de/datenschutz> |
|
||||||
| Dalamud / XIVLauncher (goatcorp) | Plugin loader, font subsystem, repo polling | Whatever Dalamud reports for itself; out of HellionChat's scope | <https://github.com/goatcorp/Dalamud> |
|
| Dalamud / XIVLauncher (goatcorp) | Plugin loader, font subsystem, repo polling | Whatever Dalamud reports for itself; out of HellionChat's scope | <https://github.com/goatcorp/Dalamud> |
|
||||||
|
|
||||||
The Hellion Forge Gitea instance and the Dalamud/XIVLauncher loader are unavoidable for anyone using HellionChat through
|
The Hellion Forge Gitea instance and the Dalamud/XIVLauncher loader are unavoidable for anyone using
|
||||||
Dalamud at all. BetterTTV is the only third party HellionChat introduces on top of that baseline, and it is opt-out via
|
HellionChat through Dalamud at all. BetterTTV is the only third party HellionChat introduces on top
|
||||||
settings.
|
of that baseline, and it is opt-out via settings.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Dependencies that touch the network
|
## Dependencies that touch the network
|
||||||
|
|
||||||
For a full dependency inventory see `docs/THIRD_PARTY_NOTICES.md`. Of the direct dependencies the plugin pulls in:
|
For a full dependency inventory see `docs/THIRD_PARTY_NOTICES.md`. Of the direct dependencies the
|
||||||
|
plugin pulls in:
|
||||||
|
|
||||||
- `MessagePack`: local serialisation, no network.
|
- `MessagePack`: local serialisation, no network.
|
||||||
- `Microsoft.Data.Sqlite`: local SQLite access, no network.
|
- `Microsoft.Data.Sqlite`: local SQLite access, no network.
|
||||||
- `morelinq`: LINQ helpers, no network.
|
- `morelinq`: LINQ helpers, no network.
|
||||||
- `Pidgin`: parser combinators, no network.
|
- `Pidgin`: parser combinators, no network.
|
||||||
- `SixLabors.ImageSharp`: image decoding (used for the BetterTTV emote pipeline), no network on its own.
|
- `SixLabors.ImageSharp`: image decoding (used for the BetterTTV emote pipeline), no network on its
|
||||||
|
own.
|
||||||
|
|
||||||
The single network call listed under "Outbound network calls" is written directly in HellionChat's own source, not
|
The single network call listed under "Outbound network calls" is written directly in HellionChat's
|
||||||
delegated to a dependency.
|
own source, not delegated to a dependency.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Changes to this notice
|
## Changes to this notice
|
||||||
|
|
||||||
If a future release changes what HellionChat stores, sends or caches, this document will be updated and the change
|
If a future release changes what HellionChat stores, sends or caches, this document will be updated
|
||||||
called out in the changelog block of that release. The "Last reviewed" date at the top tracks the version this document
|
and the change called out in the changelog block of that release. The "Last reviewed" date at the
|
||||||
is accurate for.
|
top tracks the version this document is accurate for.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -204,10 +220,10 @@ For privacy-related questions specific to HellionChat:
|
|||||||
- Email: `kontakt@hellion-media.de`
|
- Email: `kontakt@hellion-media.de`
|
||||||
- Discord DM: `@j.j_kazama`
|
- Discord DM: `@j.j_kazama`
|
||||||
|
|
||||||
Security-relevant findings (for example, the plugin storing or sending something this document says it does not) go
|
Security-relevant findings (for example, the plugin storing or sending something this document says
|
||||||
through the private advisory in `SECURITY.md`, not a public issue.
|
it does not) go through the private advisory in `SECURITY.md`, not a public issue.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Maintained under **Hellion Forge**, the modding and plugin line of **Hellion Online Media** | Bad Harzburg |
|
Maintained under **Hellion Forge**, the modding and plugin line of **Hellion Online Media** | Bad
|
||||||
[hellion-media.de](https://hellion-media.de)
|
Harzburg | [hellion-media.de](https://hellion-media.de)
|
||||||
|
|||||||
@@ -14,27 +14,30 @@
|
|||||||
**Version 1.5.0** — Privacy-first chat plugin for FINAL FANTASY XIV / Dalamud, built on
|
**Version 1.5.0** — Privacy-first chat plugin for FINAL FANTASY XIV / Dalamud, built on
|
||||||
[Chat 2](https://github.com/Infiziert90/ChatTwo) (EUPL-1.2).
|
[Chat 2](https://github.com/Infiziert90/ChatTwo) (EUPL-1.2).
|
||||||
|
|
||||||
Hellion Chat is a privacy-first plugin built on the Chat 2 foundation. The majority of the engine comes from Chat 2
|
Hellion Chat is a privacy-first plugin built on the Chat 2 foundation. The majority of the engine
|
||||||
(message store, channel logic, hook system), and most keyboard shortcuts continue to work as you'd expect. What changes:
|
comes from Chat 2 (message store, channel logic, hook system), and most keyboard shortcuts continue
|
||||||
stricter privacy defaults out of the box, custom slash commands under `/hellionchat`, no web interface, and as of
|
to work as you'd expect. What changes: stricter privacy defaults out of the box, custom slash
|
||||||
v1.1.0, a theme engine as a step toward a distinct UI look and feel.
|
commands under `/hellionchat`, no web interface, and as of v1.1.0, a theme engine as a step toward a
|
||||||
|
distinct UI look and feel.
|
||||||
|
|
||||||
The data-handling focus is on GDPR/EU, US, and JP regulations, as far as practically applicable for a chat plugin:
|
The data-handling focus is on GDPR/EU, US, and JP regulations, as far as practically applicable for
|
||||||
per-channel retention periods, granular filters, and self-service data export. A full breakdown is available in
|
a chat plugin: per-channel retention periods, granular filters, and self-service data export. A full
|
||||||
[`PRIVACY.md`](PRIVACY.md).
|
breakdown is available in [`PRIVACY.md`](PRIVACY.md).
|
||||||
|
|
||||||
This is a standalone repository, licensed under EUPL-1.2. With v1.0.0 the standalone cut is complete: own namespace
|
This is a standalone repository, licensed under EUPL-1.2. With v1.0.0 the standalone cut is
|
||||||
`HellionChat.*`, own IPC channels, own source tree structure. Distribution via custom repo. Active upstream sync ended
|
complete: own namespace `HellionChat.*`, own IPC channels, own source tree structure. Distribution
|
||||||
with the v1.4.x cycle: Chat 2 is undergoing a fundamental rework and cherry-picks are no longer portable. From here,
|
via custom repo. Active upstream sync ended with the v1.4.x cycle: Chat 2 is undergoing a
|
||||||
Hellion Chat continues as an independent codebase — background and attribution in
|
fundamental rework and cherry-picks are no longer portable. From here, Hellion Chat continues as an
|
||||||
|
independent codebase — background and attribution in
|
||||||
[`docs/UPSTREAM_SYNC.md`](docs/UPSTREAM_SYNC.md).
|
[`docs/UPSTREAM_SYNC.md`](docs/UPSTREAM_SYNC.md).
|
||||||
|
|
||||||
## Acknowledgements
|
## Acknowledgements
|
||||||
|
|
||||||
Hellion Chat is built on [Chat 2](https://github.com/Infiziert90/ChatTwo) by
|
Hellion Chat is built on [Chat 2](https://github.com/Infiziert90/ChatTwo) by
|
||||||
**[Infiziert90 (Infi)](https://github.com/Infiziert90)** and **[Anna](https://github.com/anna-is-cute)**, who maintained
|
**[Infiziert90 (Infi)](https://github.com/Infiziert90)** and
|
||||||
the plugin for years before I ever saw the source code. The entire core architecture, the message store, the channel
|
**[Anna](https://github.com/anna-is-cute)**, who maintained the plugin for years before I ever saw
|
||||||
logic, the hook system, and much more all come from them. If Hellion Chat helps you, the credit for that belongs in
|
the source code. The entire core architecture, the message store, the channel logic, the hook
|
||||||
|
system, and much more all come from them. If Hellion Chat helps you, the credit for that belongs in
|
||||||
large part to Infi and Anna. A full acknowledgement is in [NOTICE.md](NOTICE.md).
|
large part to Infi and Anna. A full acknowledgement is in [NOTICE.md](NOTICE.md).
|
||||||
|
|
||||||
Hellion Chat is developed under **Hellion Forge**, the specialized modding and plugin branch of
|
Hellion Chat is developed under **Hellion Forge**, the specialized modding and plugin branch of
|
||||||
@@ -62,67 +65,73 @@ Hellion Chat is developed under **Hellion Forge**, the specialized modding and p
|
|||||||
|
|
||||||
### Privacy / Compliance
|
### Privacy / Compliance
|
||||||
|
|
||||||
- **Channel whitelist** for database persistence with privacy-first defaults. Out of the box, only your own
|
- **Channel whitelist** for database persistence with privacy-first defaults. Out of the box, only
|
||||||
conversations are stored (tells, party, FC, linkshells, cross-world linkshells, alliance, ExtraChat). Public chat, NPC
|
your own conversations are stored (tells, party, FC, linkshells, cross-world linkshells, alliance,
|
||||||
dialogue, system spam, and battle logs are discarded at the storage layer.
|
ExtraChat). Public chat, NPC dialogue, system spam, and battle logs are discarded at the storage
|
||||||
- **Per-channel retention periods** with a daily background cleanup. Tells: 365 days, own conversation channels: 90
|
layer.
|
||||||
days, global default: 30 days. The default is OFF — the plugin deletes nothing without explicit consent.
|
- **Per-channel retention periods** with a daily background cleanup. Tells: 365 days, own
|
||||||
- **Retroactive cleanup** with preview and Ctrl+Shift confirmation. Applies the current whitelist to an existing
|
conversation channels: 90 days, global default: 30 days. The default is OFF — the plugin deletes
|
||||||
database, runs in the background, and calls VACUUM afterward.
|
nothing without explicit consent.
|
||||||
- **Export** to Markdown, JSON, or CSV via the Dalamud file dialog (GDPR Art. 15 right of access). Filter by channel,
|
- **Retroactive cleanup** with preview and Ctrl+Shift confirmation. Applies the current whitelist to
|
||||||
date range, or sender substring.
|
an existing database, runs in the background, and calls VACUUM afterward.
|
||||||
|
- **Export** to Markdown, JSON, or CSV via the Dalamud file dialog (GDPR Art. 15 right of access).
|
||||||
|
Filter by channel, date range, or sender substring.
|
||||||
- **Full privacy overview** in [`PRIVACY.md`](PRIVACY.md) and third-party components in
|
- **Full privacy overview** in [`PRIVACY.md`](PRIVACY.md) and third-party components in
|
||||||
[`docs/THIRD_PARTY_NOTICES.md`](docs/THIRD_PARTY_NOTICES.md): what is stored, which two outbound calls exist
|
[`docs/THIRD_PARTY_NOTICES.md`](docs/THIRD_PARTY_NOTICES.md): what is stored, which two outbound
|
||||||
(BetterTTV opt-out, Square Enix Lodestone font), an explicit no-telemetry statement, and the mapping of GDPR rights
|
calls exist (BetterTTV opt-out, Square Enix Lodestone font), an explicit no-telemetry statement,
|
||||||
(Art. 15/17/18/20/21) to concrete plugin functions.
|
and the mapping of GDPR rights (Art. 15/17/18/20/21) to concrete plugin functions.
|
||||||
|
|
||||||
### Onboarding
|
### Onboarding
|
||||||
|
|
||||||
- **First-run wizard** with three profiles (Privacy-First, Relaxed, Full History) and a GDPR notice for the "Full
|
- **First-run wizard** with three profiles (Privacy-First, Relaxed, Full History) and a GDPR notice
|
||||||
History" option.
|
for the "Full History" option.
|
||||||
- **Configuration migration** seeds privacy defaults for existing users and shows a notification on the first plugin
|
- **Configuration migration** seeds privacy defaults for existing users and shows a notification on
|
||||||
start after an update. With v1.0.0, users on config version 12 or older also receive a one-time tab layout reset; the
|
the first plugin start after an update. With v1.0.0, users on config version 12 or older also
|
||||||
old tab configuration is backed up as `pluginConfigs/HellionChat.json.pre-v13-backup`.
|
receive a one-time tab layout reset; the old tab configuration is backed up as
|
||||||
- **Layout migration from Chat 2** moves configuration and database to `pluginConfigs/HellionChat/` without data loss.
|
`pluginConfigs/HellionChat.json.pre-v13-backup`.
|
||||||
Handles locked files gracefully (warns the user if Chat 2 is still loaded).
|
- **Layout migration from Chat 2** moves configuration and database to `pluginConfigs/HellionChat/`
|
||||||
|
without data loss. Handles locked files gracefully (warns the user if Chat 2 is still loaded).
|
||||||
- **Migrate3 recovery** heals partially migrated databases from old Chat 2 installations.
|
- **Migrate3 recovery** heals partially migrated databases from old Chat 2 installations.
|
||||||
|
|
||||||
### Look & Feel
|
### Look & Feel
|
||||||
|
|
||||||
- **Bilingual UI** (English and German) with live language switching. Hellion-specific strings are in
|
- **Bilingual UI** (English and German) with live language switching. Hellion-specific strings are
|
||||||
`HellionStrings.<lang>.resx`.
|
in `HellionStrings.<lang>.resx`.
|
||||||
- **Hellion HUD theme** with cyan-teal accents, slate-violet tabs, and amber highlights for active states.
|
- **Hellion HUD theme** with cyan-teal accents, slate-violet tabs, and amber highlights for active
|
||||||
- **Chat color presets** (v0.6.0) with seven built-in bundles in Settings → Appearance → Chat Colors: Classic (Chat 2
|
states.
|
||||||
default), High Contrast, Pastel, Dark Mode Tuned, Hellion (brand), plus bonus moods Night Blue and Indigo Violet.
|
- **Chat color presets** (v0.6.0) with seven built-in bundles in Settings → Appearance → Chat
|
||||||
One-click apply, battle channels remain untouched.
|
Colors: Classic (Chat 2 default), High Contrast, Pastel, Dark Mode Tuned, Hellion (brand), plus
|
||||||
|
bonus moods Night Blue and Indigo Violet. One-click apply, battle channels remain untouched.
|
||||||
- **Window opacity slider** for combat-friendly transparency.
|
- **Window opacity slider** for combat-friendly transparency.
|
||||||
- **Bundled Hellion font** (Exo 2, OFL-1.1) as an optional default instead of the system font.
|
- **Bundled Hellion font** (Exo 2, OFL-1.1) as an optional default instead of the system font.
|
||||||
- **Hellion logo** bundled in the plugin and displayed in the Dalamud plugin list.
|
- **Hellion logo** bundled in the plugin and displayed in the Dalamud plugin list.
|
||||||
|
|
||||||
#### Custom Themes (v1.1.0)
|
#### Custom Themes (v1.1.0)
|
||||||
|
|
||||||
HellionChat ships a theme engine with ten built-in themes (Hellion Arctic, Hellion Spectrum, Chat 2 Classic, Event
|
HellionChat ships a theme engine with ten built-in themes (Hellion Arctic, Hellion Spectrum, Chat 2
|
||||||
Horizon, Crystal Nocturne, Mint Grove, Night Blue, Indigo Violet, Forge Merchantman, Synthwave Sunset) and a JSON-based
|
Classic, Event Horizon, Crystal Nocturne, Mint Grove, Night Blue, Indigo Violet, Forge Merchantman,
|
||||||
authoring format for custom themes. Schema and step-by-step guide in
|
Synthwave Sunset) and a JSON-based authoring format for custom themes. Schema and step-by-step guide
|
||||||
[`docs/THEME-AUTHORING.md`](docs/THEME-AUTHORING.md). Hellion Spectrum is Deuteranopia/Protanopia-safe (red-green color
|
in [`docs/THEME-AUTHORING.md`](docs/THEME-AUTHORING.md). Hellion Spectrum is
|
||||||
blindness) based on the Wong/Okabe-Ito palette.
|
Deuteranopia/Protanopia-safe (red-green color blindness) based on the Wong/Okabe-Ito palette.
|
||||||
|
|
||||||
#### Plugin Integrations (v1.3.0)
|
#### Plugin Integrations (v1.3.0)
|
||||||
|
|
||||||
- **Honorific custom titles in the chat header.** When the Honorific plugin is active and a custom title is set, it is
|
- **Honorific custom titles in the chat header.** When the Honorific plugin is active and a custom
|
||||||
displayed in the chat header above the message log. Auto-detect with silent fallback: without Honorific the slot is
|
title is set, it is displayed in the chat header above the message log. Auto-detect with silent
|
||||||
invisible. Toggle in Settings → Integrations → Honorific. First cycle of a multi-stage plugin integration roadmap
|
fallback: without Honorific the slot is invisible. Toggle in Settings → Integrations → Honorific.
|
||||||
(context menu, NotificationMaster, RP status, ExtraChat, and XIVIM to follow).
|
First cycle of a multi-stage plugin integration roadmap (context menu, NotificationMaster, RP
|
||||||
|
status, ExtraChat, and XIVIM to follow).
|
||||||
|
|
||||||
### Pop-Out Convenience (v0.6.0)
|
### Pop-Out Convenience (v0.6.0)
|
||||||
|
|
||||||
- **Input bar in pop-out windows** as a global opt-in in Settings → Windows → Window Frame. When active, every pop-out
|
- **Input bar in pop-out windows** as a global opt-in in Settings → Windows → Window Frame. When
|
||||||
window has a compact input at the bottom with a channel-colored icon button and text field. No more switching back to
|
active, every pop-out window has a compact input at the bottom with a channel-colored icon button
|
||||||
the main window for a quick reply.
|
and text field. No more switching back to the main window for a quick reply.
|
||||||
- **Per-pop-out independent text buffer and history cursor.** Changing channels in a pop-out works globally like in the
|
- **Per-pop-out independent text buffer and history cursor.** Changing channels in a pop-out works
|
||||||
main window (FFXIV channel API), but half-typed input doesn't collide between the main window and pop-outs.
|
globally like in the main window (FFXIV channel API), but half-typed input doesn't collide between
|
||||||
- **Shared input history** across all windows via singleton service. Up/Down arrow keys navigate the same list of the
|
the main window and pop-outs.
|
||||||
last 30 entries everywhere.
|
- **Shared input history** across all windows via singleton service. Up/Down arrow keys navigate the
|
||||||
|
same list of the last 30 entries everywhere.
|
||||||
|
|
||||||
### Stability
|
### Stability
|
||||||
|
|
||||||
@@ -132,12 +141,13 @@ blindness) based on the Wong/Okabe-Ito palette.
|
|||||||
|
|
||||||
### What's missing compared to Chat 2
|
### What's missing compared to Chat 2
|
||||||
|
|
||||||
The web interface was removed in Hellion Chat 0.2.0. It serves a different use case than the focus of this fork — remote
|
The web interface was removed in Hellion Chat 0.2.0. It serves a different use case than the focus
|
||||||
access to chat from a second device — which conflicts directly with the privacy-first premise: a chat plugin that starts
|
of this fork — remote access to chat from a second device — which conflicts directly with the
|
||||||
a local HTTP server is too large an attack surface for my threat model. So it's gone.
|
privacy-first premise: a chat plugin that starts a local HTTP server is too large an attack surface
|
||||||
|
for my threat model. So it's gone.
|
||||||
|
|
||||||
If you want the full Chat 2 feature set, the upstream plugin serves you better. Hellion Chat is deliberately the slimmer
|
If you want the full Chat 2 feature set, the upstream plugin serves you better. Hellion Chat is
|
||||||
fork.
|
deliberately the slimmer fork.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -172,24 +182,26 @@ HellionChat/
|
|||||||
|
|
||||||
### Rules
|
### Rules
|
||||||
|
|
||||||
- **Code namespace is `HellionChat.*`.** Fully consolidated onto the plugin name since v1.0.0 — no remaining `ChatTwo.*`
|
- **Code namespace is `HellionChat.*`.** Fully consolidated onto the plugin name since v1.0.0 — no
|
||||||
anywhere in the source tree.
|
remaining `ChatTwo.*` anywhere in the source tree.
|
||||||
- **AssemblyName is `HellionChat`.** Own slot in `pluginConfigs/`, own file manifest, no shared state with Chat 2.
|
- **AssemblyName is `HellionChat`.** Own slot in `pluginConfigs/`, own file manifest, no shared
|
||||||
Parallel-loading upstream Chat 2 is actively blocked on startup (bilingual conflict message).
|
state with Chat 2. Parallel-loading upstream Chat 2 is actively blocked on startup (bilingual
|
||||||
- **IPC channels are `HellionChat.*`.** Six channels for third-party plugin integration (`Register`, `Available`,
|
conflict message).
|
||||||
`Unregister`, `Invoke`, `GetChatInputState`, `ChatInputStateChanged`). Details in [`docs/IPC.md`](docs/IPC.md).
|
- **IPC channels are `HellionChat.*`.** Six channels for third-party plugin integration (`Register`,
|
||||||
- **Hellion-specific strings in `HellionStrings.*.resx`**, strings carried over from Chat 2 in `Language.*.resx`. The
|
`Available`, `Unregister`, `Invoke`, `GetChatInputState`, `ChatInputStateChanged`). Details in
|
||||||
original `Language.*.resx` structure is preserved because the existing translations from the upstream Crowdin
|
[`docs/IPC.md`](docs/IPC.md).
|
||||||
community remain valuable.
|
- **Hellion-specific strings in `HellionStrings.*.resx`**, strings carried over from Chat 2 in
|
||||||
- **No direct access to `Plugin.Interface.UiBuilder.FontAtlas`** outside of `FontManager`. Font fallback and the Hellion
|
`Language.*.resx`. The original `Language.*.resx` structure is preserved because the existing
|
||||||
font are managed centrally.
|
translations from the upstream Crowdin community remain valuable.
|
||||||
|
- **No direct access to `Plugin.Interface.UiBuilder.FontAtlas`** outside of `FontManager`. Font
|
||||||
|
fallback and the Hellion font are managed centrally.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Database
|
## Database
|
||||||
|
|
||||||
SQLite, schema inherited from upstream Chat 2 (migration level v3). Hellion extensions live in `Configuration` as
|
SQLite, schema inherited from upstream Chat 2 (migration level v3). Hellion extensions live in
|
||||||
fields, not in the DB schema:
|
`Configuration` as fields, not in the DB schema:
|
||||||
|
|
||||||
| Column | Type | Description |
|
| Column | Type | Description |
|
||||||
| ---------------- | ------- | ---------------------------- |
|
| ---------------- | ------- | ---------------------------- |
|
||||||
@@ -229,15 +241,15 @@ Hellion Chat is distributed via a Dalamud **custom repository**.
|
|||||||
|
|
||||||
### Migration from Chat 2 (with existing history)
|
### Migration from Chat 2 (with existing history)
|
||||||
|
|
||||||
Chat 2 and Hellion Chat share the database file until Hellion Chat moves it to its own path on first start. Order
|
Chat 2 and Hellion Chat share the database file until Hellion Chat moves it to its own path on first
|
||||||
matters:
|
start. Order matters:
|
||||||
|
|
||||||
1. **Disable Chat 2** in `/xlplugins` (do not uninstall, just disable).
|
1. **Disable Chat 2** in `/xlplugins` (do not uninstall, just disable).
|
||||||
2. **Fully close FFXIV** so SQLite releases the file lock. A plugin reload alone is not enough.
|
2. **Fully close FFXIV** so SQLite releases the file lock. A plugin reload alone is not enough.
|
||||||
3. Restart the game.
|
3. Restart the game.
|
||||||
4. Add the custom repo as described above.
|
4. Add the custom repo as described above.
|
||||||
5. Install Hellion Chat. On first start, the configuration file and the entire database directory are moved into the
|
5. Install Hellion Chat. On first start, the configuration file and the entire database directory
|
||||||
HellionChat layout.
|
are moved into the HellionChat layout.
|
||||||
6. **Verify** under Settings → Privacy → Refresh preview that the message count looks plausible.
|
6. **Verify** under Settings → Privacy → Refresh preview that the message count looks plausible.
|
||||||
|
|
||||||
### Troubleshooting
|
### Troubleshooting
|
||||||
@@ -267,17 +279,18 @@ Start the game, enable Hellion Chat, and your history is back.
|
|||||||
|
|
||||||
### Updates
|
### Updates
|
||||||
|
|
||||||
Updates appear automatically in the plugin list once a new `vX.Y.Z` tag with a GitHub Release is published. No reinstall
|
Updates appear automatically in the plugin list once a new `vX.Y.Z` tag with a GitHub Release is
|
||||||
needed.
|
published. No reinstall needed.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Distribution
|
## Distribution
|
||||||
|
|
||||||
Hellion Chat is distributed via its own Dalamud custom repository (`repo.json` in the repo root). Pushing a `vX.Y.Z` tag
|
Hellion Chat is distributed via its own Dalamud custom repository (`repo.json` in the repo root).
|
||||||
triggers the [`release.yml`](.github/workflows/release.yml) workflow, which attaches the build output
|
Pushing a `vX.Y.Z` tag triggers the [`release.yml`](.github/workflows/release.yml) workflow, which
|
||||||
(`HellionChat/bin/Release/HellionChat/latest.zip`) along with the matching changelog block from `HellionChat.yaml` to
|
attaches the build output (`HellionChat/bin/Release/HellionChat/latest.zip`) along with the matching
|
||||||
the GitHub Release. Manual recovery path if the auto-trigger is missed: `gh workflow run release.yml -f tag=vX.Y.Z`.
|
changelog block from `HellionChat.yaml` to the GitHub Release. Manual recovery path if the
|
||||||
|
auto-trigger is missed: `gh workflow run release.yml -f tag=vX.Y.Z`.
|
||||||
|
|
||||||
An optional submission to the Dalamud main plugin repo (in addition to the custom repo) is on the
|
An optional submission to the Dalamud main plugin repo (in addition to the custom repo) is on the
|
||||||
[roadmap](docs/ROADMAP.md).
|
[roadmap](docs/ROADMAP.md).
|
||||||
@@ -286,19 +299,22 @@ An optional submission to the Dalamud main plugin repo (in addition to the custo
|
|||||||
|
|
||||||
## Project Status
|
## Project Status
|
||||||
|
|
||||||
**Version 1.5.0** — DI Foundation and Service Refactor. Major architecture cycle: the plugin bootstrap moves to a
|
**Version 1.5.0** — DI Foundation and Service Refactor. Major architecture cycle: the plugin
|
||||||
generic-host DI container (`Microsoft.Extensions.Hosting` + `IServiceCollection`) modelled on Lightless Sync. All
|
bootstrap moves to a generic-host DI container (`Microsoft.Extensions.Hosting` +
|
||||||
18 instance-class services migrate from a static `Plugin.LogProxy` locator to `Microsoft.Extensions.Logging.ILogger<T>`
|
`IServiceCollection`) modelled on Lightless Sync. All 18 instance-class services migrate from a
|
||||||
via constructor injection, with a custom `DalamudLogger` bridging the framework over to Dalamud's `IPluginLog`. The
|
static `Plugin.LogProxy` locator to `Microsoft.Extensions.Logging.ILogger<T>` via constructor
|
||||||
proxy stays for the eight buckets ctor-injection cannot reach (static helpers like `EmoteCache`, Dalamud-reflected
|
injection, with a custom `DalamudLogger` bridging the framework over to Dalamud's `IPluginLog`. The
|
||||||
`Configuration`, the `Message` data class, and static methods inside `FontManager` / `GameFunctions`). Plugin.cs
|
proxy stays for the eight buckets ctor-injection cannot reach (static helpers like `EmoteCache`,
|
||||||
finishes the cycle at 1012 lines — virtually identical to the pre-cycle 1013 — because the new Phase-1 host build
|
Dalamud-reflected `Configuration`, the `Message` data class, and static methods inside `FontManager`
|
||||||
and Plugin.X bridge wiring trade out exactly the service and window allocations that left `LoadAsync`. Cross-plugin
|
/ `GameFunctions`). Plugin.cs finishes the cycle at 1012 lines — virtually identical to the
|
||||||
baseline confirms no performance penalty vs Chat 2: HellionChat first-frame HITCH 77 ms median, Chat 2 74 ms.
|
pre-cycle 1013 — because the new Phase-1 host build and Plugin.X bridge wiring trade out exactly the
|
||||||
Lightless and XIVInstantMessenger sit around 7 ms by deferring their font-atlas build past `Finished loading` —
|
service and window allocations that left `LoadAsync`. Cross-plugin baseline confirms no performance
|
||||||
that pattern is the v1.5.1 follow-up item. One user-visible fix bundled in from upstream: pasting a slash command
|
penalty vs Chat 2: HellionChat first-frame HITCH 77 ms median, Chat 2 74 ms. Lightless and
|
||||||
into the chat input (Friend List "/tell" action, plugin-driven inserts) now replaces the existing input instead of
|
XIVInstantMessenger sit around 7 ms by deferring their font-atlas build past `Finished loading` —
|
||||||
concatenating onto whatever the user was typing. Migration v17 stays (no schema bump).
|
that pattern is the v1.5.1 follow-up item. One user-visible fix bundled in from upstream: pasting a
|
||||||
|
slash command into the chat input (Friend List "/tell" action, plugin-driven inserts) now replaces
|
||||||
|
the existing input instead of concatenating onto whatever the user was typing. Migration v17 stays
|
||||||
|
(no schema bump).
|
||||||
|
|
||||||
Hellion Chat is a standalone plugin, no longer a fork in the repository sense. Fully completed:
|
Hellion Chat is a standalone plugin, no longer a fork in the repository sense. Fully completed:
|
||||||
|
|
||||||
@@ -313,29 +329,31 @@ Hellion Chat is a standalone plugin, no longer a fork in the repository sense. F
|
|||||||
- Audit hardening (path traversal, retention race, DbViewer consistency)
|
- Audit hardening (path traversal, retention race, DbViewer consistency)
|
||||||
- About tab in Hellion branding, localized EN and DE, with license and disclaimer
|
- About tab in Hellion branding, localized EN and DE, with license and disclaimer
|
||||||
- AI disclosure documented (see [`docs/AI_DISCLOSURE.md`](docs/AI_DISCLOSURE.md))
|
- AI disclosure documented (see [`docs/AI_DISCLOSURE.md`](docs/AI_DISCLOSURE.md))
|
||||||
- Standalone cut: namespace `HellionChat.*`, IPC channels `HellionChat.*`, source tree restructure, conflict detection
|
- Standalone cut: namespace `HellionChat.*`, IPC channels `HellionChat.*`, source tree restructure,
|
||||||
against upstream Chat 2, SQLite CVE hardening (3.50.3)
|
conflict detection against upstream Chat 2, SQLite CVE hardening (3.50.3)
|
||||||
- Theme engine with ten built-in themes plus JSON authoring format (engine v1.1.0, catalog extended in v1.2.3, including
|
- Theme engine with ten built-in themes plus JSON authoring format (engine v1.1.0, catalog extended
|
||||||
CVD-safe Hellion Spectrum; Synthwave Sunset in v1.4.1)
|
in v1.2.3, including CVD-safe Hellion Spectrum; Synthwave Sunset in v1.4.1)
|
||||||
- ABGR cache on theme records: `HellionStyle.PushGlobal` reads pre-computed ABGR instead of converting RGBA→ABGR per
|
- ABGR cache on theme records: `HellionStyle.PushGlobal` reads pre-computed ABGR instead of
|
||||||
slot per frame (v1.4.1, ~13% render-time recovery)
|
converting RGBA→ABGR per slot per frame (v1.4.1, ~13% render-time recovery)
|
||||||
|
|
||||||
In progress: incremental modernization of UI look and feel beyond the theme engine. What's planned next and what's on
|
In progress: incremental modernization of UI look and feel beyond the theme engine. What's planned
|
||||||
the long-term list is in [`docs/ROADMAP.md`](docs/ROADMAP.md). Concrete scheduled items are also tracked in the
|
next and what's on the long-term list is in [`docs/ROADMAP.md`](docs/ROADMAP.md). Concrete scheduled
|
||||||
[Gitea issue tracker](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/issues) under the `roadmap` label.
|
items are also tracked in the
|
||||||
|
[Gitea issue tracker](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/issues) under
|
||||||
|
the `roadmap` label.
|
||||||
|
|
||||||
### On Release Cadence
|
### On Release Cadence
|
||||||
|
|
||||||
Anyone looking at the repo for the first time will notice a lot of releases and a high commit count in a short time.
|
Anyone looking at the repo for the first time will notice a lot of releases and a high commit count
|
||||||
Both are deliberate. The full reasoning — four factors behind it — is in
|
in a short time. Both are deliberate. The full reasoning — four factors behind it — is in
|
||||||
[`docs/LEARNING-JOURNEY.md`](docs/LEARNING-JOURNEY.md), section "How I release this fast".
|
[`docs/LEARNING-JOURNEY.md`](docs/LEARNING-JOURNEY.md), section "How I release this fast".
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Community & Support
|
## Community & Support
|
||||||
|
|
||||||
- **Hellion Forge Discord** (community for HellionChat and other Hellion Online Media plugins and tools):
|
- **Hellion Forge Discord** (community for HellionChat and other Hellion Online Media plugins and
|
||||||
[discord.gg/X9V7Kcv5gR](https://discord.gg/X9V7Kcv5gR)
|
tools): [discord.gg/X9V7Kcv5gR](https://discord.gg/X9V7Kcv5gR)
|
||||||
- Bug reports and feature requests:
|
- Bug reports and feature requests:
|
||||||
[Gitea Issues](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/issues)
|
[Gitea Issues](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/issues)
|
||||||
- Discord DM: `@j.j_kazama`
|
- Discord DM: `@j.j_kazama`
|
||||||
@@ -345,25 +363,26 @@ Both are deliberate. The full reasoning — four factors behind it — is in
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
EUPL-1.2 (same license as upstream Chat 2). Full text in [LICENSE](LICENSE), copyright notes with dual-holder block in
|
EUPL-1.2 (same license as upstream Chat 2). Full text in [LICENSE](LICENSE), copyright notes with
|
||||||
[COPYRIGHT](COPYRIGHT), personal acknowledgement to the upstream authors in [NOTICE.md](NOTICE.md).
|
dual-holder block in [COPYRIGHT](COPYRIGHT), personal acknowledgement to the upstream authors in
|
||||||
|
[NOTICE.md](NOTICE.md).
|
||||||
|
|
||||||
© 2023–2026 the Chat 2 authors ([Infi](https://github.com/Infiziert90), [Anna](https://github.com/anna-is-cute), and
|
© 2023–2026 the Chat 2 authors ([Infi](https://github.com/Infiziert90),
|
||||||
upstream contributors) for the engine, IPC, and storage layer. © 2026 Hellion Online Media for the Hellion Chat
|
[Anna](https://github.com/anna-is-cute), and upstream contributors) for the engine, IPC, and storage
|
||||||
extensions.
|
layer. © 2026 Hellion Online Media for the Hellion Chat extensions.
|
||||||
|
|
||||||
### Acknowledgments
|
### Acknowledgments
|
||||||
|
|
||||||
- **[Infi](https://github.com/Infiziert90) and [Anna](https://github.com/anna-is-cute) (ascclemens)** for the Chat 2
|
- **[Infi](https://github.com/Infiziert90) and [Anna](https://github.com/anna-is-cute)
|
||||||
engine, without which this fork would not exist.
|
(ascclemens)** for the Chat 2 engine, without which this fork would not exist.
|
||||||
- **Dalamud team** for the plugin framework.
|
- **Dalamud team** for the plugin framework.
|
||||||
- **Chat 2 Crowdin community** for the upstream string translations (see Settings → Info → "Chat 2 community
|
- **Chat 2 Crowdin community** for the upstream string translations (see Settings → Info → "Chat 2
|
||||||
translators").
|
community translators").
|
||||||
|
|
||||||
### FFXIV Disclaimer
|
### FFXIV Disclaimer
|
||||||
|
|
||||||
FINAL FANTASY XIV © SQUARE ENIX CO., LTD. All rights reserved. Hellion Chat is an unofficial, fan-made plugin and is not
|
FINAL FANTASY XIV © SQUARE ENIX CO., LTD. All rights reserved. Hellion Chat is an unofficial,
|
||||||
affiliated with, supported by, sponsored by, or approved by Square Enix.
|
fan-made plugin and is not affiliated with, supported by, sponsored by, or approved by Square Enix.
|
||||||
|
|
||||||
### AI Assistance
|
### AI Assistance
|
||||||
|
|
||||||
@@ -373,7 +392,8 @@ See [`docs/AI_DISCLOSURE.md`](docs/AI_DISCLOSURE.md) for the pair-level disclosu
|
|||||||
|
|
||||||
## Project Documents
|
## Project Documents
|
||||||
|
|
||||||
Standard repository documents live in the repo root; deeper documentation lives under [`docs/`](docs/).
|
Standard repository documents live in the repo root; deeper documentation lives under
|
||||||
|
[`docs/`](docs/).
|
||||||
|
|
||||||
### Repo Root
|
### Repo Root
|
||||||
|
|
||||||
@@ -404,5 +424,5 @@ Standard repository documents live in the repo root; deeper documentation lives
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Developed under **Hellion Forge**, the modding and plugin branch of **Hellion Online Media** | Bad Harzburg |
|
Developed under **Hellion Forge**, the modding and plugin branch of **Hellion Online Media** | Bad
|
||||||
[hellion-media.de](https://hellion-media.de)
|
Harzburg | [hellion-media.de](https://hellion-media.de)
|
||||||
|
|||||||
+8
-7
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
## Reporting a Vulnerability
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
If you find a security issue in HellionChat, please do not open a public Gitea issue. Use one of the private channels
|
If you find a security issue in HellionChat, please do not open a public Gitea issue. Use one of the
|
||||||
below so I can investigate and ship a fix before the details go public.
|
private channels below so I can investigate and ship a fix before the details go public.
|
||||||
|
|
||||||
**Preferred:**
|
**Preferred:**
|
||||||
|
|
||||||
@@ -20,7 +20,8 @@ I respond on weekdays during European business hours.
|
|||||||
|
|
||||||
### In scope
|
### In scope
|
||||||
|
|
||||||
- Code paths that touch user-controlled input (chat messages, plugin config, file paths the user can influence)
|
- Code paths that touch user-controlled input (chat messages, plugin config, file paths the user can
|
||||||
|
influence)
|
||||||
- The privacy filter in `MessageStore.cs` and the export pipeline
|
- The privacy filter in `MessageStore.cs` and the export pipeline
|
||||||
- The configuration migration logic
|
- The configuration migration logic
|
||||||
- The `EmoteCache` HTTP client and path handling
|
- The `EmoteCache` HTTP client and path handling
|
||||||
@@ -36,10 +37,10 @@ I respond on weekdays during European business hours.
|
|||||||
|
|
||||||
## Disclosure Window
|
## Disclosure Window
|
||||||
|
|
||||||
I aim to ship a fix within 14 days for high-severity issues and within 30 days for everything else. If a fix needs more
|
I aim to ship a fix within 14 days for high-severity issues and within 30 days for everything else.
|
||||||
time I will say so in the private thread.
|
If a fix needs more time I will say so in the private thread.
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
Everyone who reports a real issue gets listed in the changelog of the release that fixes it, unless they prefer to stay
|
Everyone who reports a real issue gets listed in the changelog of the release that fixes it, unless
|
||||||
anonymous. No bug bounty, nothing financial — this is a hobby plugin.
|
they prefer to stay anonymous. No bug bounty, nothing financial — this is a hobby plugin.
|
||||||
|
|||||||
+18
-17
@@ -1,7 +1,7 @@
|
|||||||
# Support
|
# Support
|
||||||
|
|
||||||
HellionChat is a small hobby project maintained by one person. There are a few different paths depending on what you
|
HellionChat is a small hobby project maintained by one person. There are a few different paths
|
||||||
need. Pick the one that matches.
|
depending on what you need. Pick the one that matches.
|
||||||
|
|
||||||
## Bugs and feature requests
|
## Bugs and feature requests
|
||||||
|
|
||||||
@@ -10,45 +10,46 @@ Gitea issues, using the templates:
|
|||||||
- [Bug report](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/issues/new?template=bug_report.yml)
|
- [Bug report](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/issues/new?template=bug_report.yml)
|
||||||
- [Feature request](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/issues/new?template=feature_request.yml)
|
- [Feature request](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/issues/new?template=feature_request.yml)
|
||||||
|
|
||||||
Please search [existing issues](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/issues?type=issue)
|
Please search
|
||||||
|
[existing issues](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/issues?type=issue)
|
||||||
first. Duplicates get closed and pointed at the original.
|
first. Duplicates get closed and pointed at the original.
|
||||||
|
|
||||||
## Security
|
## Security
|
||||||
|
|
||||||
Do **not** open a public issue for security-relevant findings. Use the private advisory route described in
|
Do **not** open a public issue for security-relevant findings. Use the private advisory route
|
||||||
[SECURITY.md](SECURITY.md):
|
described in [SECURITY.md](SECURITY.md):
|
||||||
|
|
||||||
- Email `kontakt@hellion-media.de` (preferred for security reports)
|
- Email `kontakt@hellion-media.de` (preferred for security reports)
|
||||||
- Discord DM `@j.j_kazama` for time-sensitive findings
|
- Discord DM `@j.j_kazama` for time-sensitive findings
|
||||||
|
|
||||||
## Privacy questions
|
## Privacy questions
|
||||||
|
|
||||||
Specific questions about what HellionChat does or does not store and send are covered in [PRIVACY.md](PRIVACY.md). For
|
Specific questions about what HellionChat does or does not store and send are covered in
|
||||||
follow-ups beyond that document:
|
[PRIVACY.md](PRIVACY.md). For follow-ups beyond that document:
|
||||||
|
|
||||||
- Email `kontakt@hellion-media.de`
|
- Email `kontakt@hellion-media.de`
|
||||||
|
|
||||||
## Quick questions and casual feedback
|
## Quick questions and casual feedback
|
||||||
|
|
||||||
- **Hellion Forge Discord** (community for HellionChat and other Hellion Online Media plugins and tools):
|
- **Hellion Forge Discord** (community for HellionChat and other Hellion Online Media plugins and
|
||||||
[discord.gg/X9V7Kcv5gR](https://discord.gg/X9V7Kcv5gR)
|
tools): [discord.gg/X9V7Kcv5gR](https://discord.gg/X9V7Kcv5gR)
|
||||||
- Discord DM: `@j.j_kazama`
|
- Discord DM: `@j.j_kazama`
|
||||||
|
|
||||||
Bug reports still go through the issue tracker so they can be tracked, but a quick "is this a bug or am I holding it
|
Bug reports still go through the issue tracker so they can be tracked, but a quick "is this a bug or
|
||||||
wrong" message is fine.
|
am I holding it wrong" message is fine.
|
||||||
|
|
||||||
## Upstream Chat 2 issues
|
## Upstream Chat 2 issues
|
||||||
|
|
||||||
If the issue exists in upstream Chat 2 too, please report it at
|
If the issue exists in upstream Chat 2 too, please report it at
|
||||||
[Infiziert90/ChatTwo](https://github.com/Infiziert90/ChatTwo/issues). That keeps the original maintainers in the loop
|
[Infiziert90/ChatTwo](https://github.com/Infiziert90/ChatTwo/issues). That keeps the original
|
||||||
and helps everyone who uses Chat 2 directly.
|
maintainers in the loop and helps everyone who uses Chat 2 directly.
|
||||||
|
|
||||||
## Response times
|
## Response times
|
||||||
|
|
||||||
Weekdays during European business hours. On weekends and FFXIV patch days, replies will be slower. A few days of silence
|
Weekdays during European business hours. On weekends and FFXIV patch days, replies will be slower. A
|
||||||
on a non-urgent issue is normal. Pinging once after a week is fine.
|
few days of silence on a non-urgent issue is normal. Pinging once after a week is fine.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Maintained under **Hellion Forge**, the modding and plugin line of **Hellion Online Media** | Bad Harzburg |
|
Maintained under **Hellion Forge**, the modding and plugin line of **Hellion Online Media** | Bad
|
||||||
[hellion-media.de](https://hellion-media.de)
|
Harzburg | [hellion-media.de](https://hellion-media.de)
|
||||||
|
|||||||
+25
-19
@@ -1,13 +1,15 @@
|
|||||||
# AI Assistance Disclosure
|
# AI Assistance Disclosure
|
||||||
|
|
||||||
HellionChat uses AI assistance per the [Dalamud Plugin AI Usage Policy](https://github.com/goatcorp/DalamudPluginsD17/)
|
HellionChat uses AI assistance per the
|
||||||
at the **Pair** level.
|
[Dalamud Plugin AI Usage Policy](https://github.com/goatcorp/DalamudPluginsD17/) at the **Pair**
|
||||||
|
level.
|
||||||
|
|
||||||
A note up front: HellionChat is currently not submitted to the official Dalamud plugin repository and technically has no
|
A note up front: HellionChat is currently not submitted to the official Dalamud plugin repository
|
||||||
obligation to disclose this. I would rather be upfront about how it is built.
|
and technically has no obligation to disclose this. I would rather be upfront about how it is built.
|
||||||
|
|
||||||
HellionChat is my entry point into game modding and plugin development. I have never written a plugin for a game before.
|
HellionChat is my entry point into game modding and plugin development. I have never written a
|
||||||
I work alone, so I get help where I need it. That is not something I want to hide.
|
plugin for a game before. I work alone, so I get help where I need it. That is not something I want
|
||||||
|
to hide.
|
||||||
|
|
||||||
## How I Actually Work
|
## How I Actually Work
|
||||||
|
|
||||||
@@ -18,12 +20,13 @@ I plan the architecture, decide what gets built, and own every design decision.
|
|||||||
- Read the Dalamud log output to verify behaviour
|
- Read the Dalamud log output to verify behaviour
|
||||||
- Run security and privacy audits on anything that touches user data
|
- Run security and privacy audits on anything that touches user data
|
||||||
|
|
||||||
One of the main reasons I use AI is consistency. I want the HellionChat code to match the style of the upstream Chat 2
|
One of the main reasons I use AI is consistency. I want the HellionChat code to match the style of
|
||||||
codebase and stay readable for anyone who opens the repo, not just for me. Claude helps me catch when I am drifting from
|
the upstream Chat 2 codebase and stay readable for anyone who opens the repo, not just for me.
|
||||||
upstream conventions or writing something that only makes sense in my own head.
|
Claude helps me catch when I am drifting from upstream conventions or writing something that only
|
||||||
|
makes sense in my own head.
|
||||||
|
|
||||||
The balance is shifting toward more hand-written work as I get more comfortable with Dalamud and plugin development in
|
The balance is shifting toward more hand-written work as I get more comfortable with Dalamud and
|
||||||
general.
|
plugin development in general.
|
||||||
|
|
||||||
## What AI Is Used For
|
## What AI Is Used For
|
||||||
|
|
||||||
@@ -34,23 +37,25 @@ general.
|
|||||||
|
|
||||||
## What AI Is Not Used For
|
## What AI Is Not Used For
|
||||||
|
|
||||||
- **Visual assets.** Logos, icons, banners, and screenshots are human-drawn or taken from the running game.
|
- **Visual assets.** Logos, icons, banners, and screenshots are human-drawn or taken from the
|
||||||
|
running game.
|
||||||
- **German translations.** Written by me as a native speaker.
|
- **German translations.** Written by me as a native speaker.
|
||||||
|
|
||||||
## What Is Where
|
## What Is Where
|
||||||
|
|
||||||
Upstream Chat 2 (by Infi & Anna, EUPL-1.2) is the foundation and was not produced with AI assistance.
|
Upstream Chat 2 (by Infi & Anna, EUPL-1.2) is the foundation and was not produced with AI
|
||||||
HellionChat-specific code lives in `HellionChat/Privacy/`, `HellionChat/Export/`,
|
assistance. HellionChat-specific code lives in `HellionChat/Privacy/`, `HellionChat/Export/`,
|
||||||
`HellionChat/Resources/HellionStrings*`, `Ui/SettingsTabs/Privacy.cs`, `Ui/FirstRunWizard.cs`, `Ui/HellionStyle.cs`,
|
`HellionChat/Resources/HellionStrings*`, `Ui/SettingsTabs/Privacy.cs`, `Ui/FirstRunWizard.cs`,
|
||||||
plus the Migrate3 recovery and plugin layout migration in `MessageStore.cs` and `Plugin.cs`. These were developed with
|
`Ui/HellionStyle.cs`, plus the Migrate3 recovery and plugin layout migration in `MessageStore.cs`
|
||||||
Pair-level assistance as described above.
|
and `Plugin.cs`. These were developed with Pair-level assistance as described above.
|
||||||
|
|
||||||
## If AI-Assisted Development Is a Dealbreaker for You
|
## If AI-Assisted Development Is a Dealbreaker for You
|
||||||
|
|
||||||
Fair enough. There are solid alternatives:
|
Fair enough. There are solid alternatives:
|
||||||
|
|
||||||
- [Chat 2](https://github.com/Infiziert90/ChatTwo), the upstream project HellionChat is built on
|
- [Chat 2](https://github.com/Infiziert90/ChatTwo), the upstream project HellionChat is built on
|
||||||
- [XIV Instant Messenger](https://github.com/NightmareXIV/XIVInstantMessenger), a different approach to FFXIV chat
|
- [XIV Instant Messenger](https://github.com/NightmareXIV/XIVInstantMessenger), a different approach
|
||||||
|
to FFXIV chat
|
||||||
|
|
||||||
Both are good projects. Use what fits you best.
|
Both are good projects. Use what fits you best.
|
||||||
|
|
||||||
@@ -71,4 +76,5 @@ Both are good projects. Use what fits you best.
|
|||||||
|
|
||||||
## Contact
|
## Contact
|
||||||
|
|
||||||
Questions about this disclosure: <https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/issues>
|
Questions about this disclosure:
|
||||||
|
<https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/issues>
|
||||||
|
|||||||
+404
-345
@@ -1,48 +1,48 @@
|
|||||||
# Changelog — Hellion Chat
|
# Changelog — Hellion Chat
|
||||||
|
|
||||||
All user-facing changes to Hellion Chat. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
All user-facing changes to Hellion Chat. Format follows
|
||||||
version numbers follow [Semantic Versioning](https://semver.org/).
|
[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
|
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
|
[Gitea Release page](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases) and
|
||||||
changelog block (`HellionChat/HellionChat.yaml` → `changelog:`). This file summarises releases as an overview and links
|
in the plugin changelog block (`HellionChat/HellionChat.yaml` → `changelog:`). This file summarises
|
||||||
to the release pages for details.
|
releases as an overview and links to the release pages for details.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Hellion Chat 1.5.0 — DI Foundation and Service Refactor (2026-05-17)
|
## 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
|
Major architecture cycle. The plugin bootstrap moves to a generic-host DI container
|
||||||
(`Microsoft.Extensions.Hosting` + `IServiceCollection`) modelled on Lightless Sync. Service
|
(`Microsoft.Extensions.Hosting` + `IServiceCollection`) modelled on Lightless Sync. Service logging
|
||||||
logging migrates from a static `Plugin.LogProxy` locator to typed
|
migrates from a static `Plugin.LogProxy` locator to typed `Microsoft.Extensions.Logging.ILogger<T>`
|
||||||
`Microsoft.Extensions.Logging.ILogger<T>` via constructor injection, bridged over Dalamud's
|
via constructor injection, bridged over Dalamud's `IPluginLog` by a custom `DalamudLogger` trio.
|
||||||
`IPluginLog` by a custom `DalamudLogger` trio.
|
|
||||||
|
|
||||||
### Under the hood
|
### Under the hood
|
||||||
|
|
||||||
- 18 instance-class services migrate to `ILogger<T>` via constructor injection across four
|
- 18 instance-class services migrate to `ILogger<T>` via constructor injection across four slices:
|
||||||
slices: data layer (`MessageStore`, `MessageManager`, `AutoTellTabsService`), IPC and
|
data layer (`MessageStore`, `MessageManager`, `AutoTellTabsService`), IPC and integrations
|
||||||
integrations (`HonorificService`, `IpcManager`, `TypingIpc`, `ExtraChat`, three
|
(`HonorificService`, `IpcManager`, `TypingIpc`, `ExtraChat`, three `GameFunctions` classes), UI
|
||||||
`GameFunctions` classes), UI window layer (`ChatLogWindow`, `DbViewer`, `Popout`, three
|
window layer (`ChatLogWindow`, `DbViewer`, `Popout`, three settings tabs), and root (`Commands`,
|
||||||
settings tabs), and root (`Commands`, `ThemeRegistry`, `PayloadHandler`).
|
`ThemeRegistry`, `PayloadHandler`).
|
||||||
- `Plugin.LogProxy` stays in place for the eight buckets ctor injection cannot reach:
|
- `Plugin.LogProxy` stays in place for the eight buckets ctor injection cannot reach: static helpers
|
||||||
static helpers (`EmoteCache`, `AutoTranslate`, `MemoryUtil`, `WrapperUtil`),
|
(`EmoteCache`, `AutoTranslate`, `MemoryUtil`, `WrapperUtil`), Dalamud-reflected types
|
||||||
Dalamud-reflected types (`Configuration`), the `Message` data class, and instance classes
|
(`Configuration`), the `Message` data class, and instance classes that only log from static
|
||||||
that only log from static methods (`FontManager`, one `GameFunctions` site).
|
methods (`FontManager`, one `GameFunctions` site).
|
||||||
- Plugin.cs finishes at 1012 lines — virtually identical to the pre-cycle 1013. The new
|
- Plugin.cs finishes at 1012 lines — virtually identical to the pre-cycle 1013. The new Phase-1 host
|
||||||
Phase-1 host build and `Plugin.X` bridge wiring trade out exactly the service and window
|
build and `Plugin.X` bridge wiring trade out exactly the service and window allocations that
|
||||||
allocations that previously lived in `LoadAsync`.
|
previously lived in `LoadAsync`.
|
||||||
- Cross-plugin baseline confirms no performance penalty against Chat 2: HellionChat
|
- Cross-plugin baseline confirms no performance penalty against Chat 2: HellionChat first-frame
|
||||||
first-frame HITCH 77 ms median, Chat 2 74 ms median. Lightless and XIVInstantMessenger sit
|
HITCH 77 ms median, Chat 2 74 ms median. Lightless and XIVInstantMessenger sit around 7 ms by
|
||||||
around 7 ms by deferring their font-atlas build past `Finished loading` — that pattern is
|
deferring their font-atlas build past `Finished loading` — that pattern is the v1.5.1 follow-up
|
||||||
the v1.5.1 follow-up item.
|
item.
|
||||||
|
|
||||||
### User-visible
|
### User-visible
|
||||||
|
|
||||||
- Slash-command insert fix: pasting a slash command into the chat input (Friend List
|
- Slash-command insert fix: pasting a slash command into the chat input (Friend List "/tell" action,
|
||||||
"/tell" action, plugin-driven inserts from Artisan, AllaganTools etc.) now replaces the
|
plugin-driven inserts from Artisan, AllaganTools etc.) now replaces the existing input instead of
|
||||||
existing input instead of concatenating onto whatever the user was typing. Cherry-picked
|
concatenating onto whatever the user was typing. Cherry-picked from ChatTwo upstream `ee7768ac`
|
||||||
from ChatTwo upstream `ee7768ac` with namespace adaptation.
|
with namespace adaptation.
|
||||||
|
|
||||||
Migration v17 stays (no schema bump).
|
Migration v17 stays (no schema bump).
|
||||||
|
|
||||||
@@ -52,23 +52,27 @@ 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)
|
## 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
|
Eleventh and final sub-patch of the v1.4.x Polish-Sweep series. Symbol picker for the chat input, a
|
||||||
for users with many active partners, and a closing cleanup sweep before v1.5.0 picks up the DI-container adoption.
|
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 —
|
- Symbol picker for the chat input: smile-icon button left of the channel indicator opens a popup
|
||||||
161 FFXIV PUA glyphs (Dalamud's SeIconChar enum) and 97 server-verified BMP symbols round-tripped through `/echo` and
|
with two tabs — 161 FFXIV PUA glyphs (Dalamud's SeIconChar enum) and 97 server-verified BMP
|
||||||
`/say` in a four-round probe. Cursor-aware splice, multi-insert keeps the popup open, recent-used strip floats the last
|
symbols round-tripped through `/echo` and `/say` in a four-round probe. Cursor-aware splice,
|
||||||
sixteen picks across both tabs. Toggle in Settings → Chat → Message behaviour, default on.
|
multi-insert keeps the popup open, recent-used strip floats the last sixteen picks across both
|
||||||
- Pinned auto-tell tabs reload their full history again. PreloadHistory had a hidden 500-row scan cap that overrode the
|
tabs. Toggle in Settings → Chat → Message behaviour, default on.
|
||||||
user-configurable `AutoTellTabsHistoryPreload` setting whenever you chatted with many partners; less-frequent pinned
|
- Pinned auto-tell tabs reload their full history again. PreloadHistory had a hidden 500-row scan
|
||||||
partners lost their backlog. The cap is removed.
|
cap that overrode the user-configurable `AutoTellTabsHistoryPreload` setting whenever you chatted
|
||||||
- Slash-command teardown cleanup: `/hellion`, `/hellionView`, `/hellionDebugger` (and `#if DEBUG /hellionSeString`) wrappers
|
with many partners; less-frequent pinned partners lost their backlog. The cap is removed.
|
||||||
are now cached as private fields so plugin teardown detaches the live registration instead of re-Register'ing with
|
- Slash-command teardown cleanup: `/hellion`, `/hellionView`, `/hellionDebugger` (and
|
||||||
identical args (latent maintenance hazard from v1.4.9).
|
`#if DEBUG /hellionSeString`) wrappers are now cached as private fields so plugin teardown
|
||||||
- v1.4.x Polish-Sweep wraps up here. The ImGuiListClipper render refactor that was on the v1.4.10 reserve list got dropped
|
detaches the live registration instead of re-Register'ing with identical args (latent maintenance
|
||||||
after cross-platform smoke showed the scroll rubber-band is a Wine/Linux render-pipeline quirk, not universal — Windows
|
hazard from v1.4.9).
|
||||||
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
|
- v1.4.x Polish-Sweep wraps up here. The ImGuiListClipper render refactor that was on the v1.4.10
|
||||||
DI-container adoption (Microsoft.Extensions.Hosting + ILogger<T>) modelled on Lightless.
|
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).
|
- Migration v17 stays (no schema bump).
|
||||||
|
|
||||||
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
||||||
@@ -77,35 +81,39 @@ 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)
|
## 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
|
Tenth sub-patch of the v1.4.x polish-sweep series. First-frame render cost drops from ~127 ms median
|
||||||
~76 ms median — comfortably under Dalamud's 100 ms HITCH warning threshold. The remaining ~13 ms gap to ChatTwo
|
down to ~76 ms median — comfortably under Dalamud's 100 ms HITCH warning threshold. The remaining
|
||||||
upstream (~63 ms median) is the cost of HellionChat-only features (sidebar tab view, custom status bar,
|
~13 ms gap to ChatTwo upstream (~63 ms median) is the cost of HellionChat-only features (sidebar tab
|
||||||
Honorific integration).
|
view, custom status bar, Honorific integration).
|
||||||
|
|
||||||
- First-frame defer: six non-essential rendering sections inside `ChatLogWindow` skip their first Draw and run
|
- First-frame defer: six non-essential rendering sections inside `ChatLogWindow` skip their first
|
||||||
one frame later. Covered sections are the bottom status bar, channel-name SeString chunks, window bounds
|
Draw and run one frame later. Covered sections are the bottom status bar, channel-name SeString
|
||||||
check, v0.6.1 hint banner, autocomplete and input-preview calculation. At 60 fps the user sees those sections
|
chunks, window bounds check, v0.6.1 hint banner, autocomplete and input-preview calculation. At 60
|
||||||
~17 ms after plugin reload — invisible inside the ~2.5 s font-atlas build window every reload runs through
|
fps the user sees those sections ~17 ms after plugin reload — invisible inside the ~2.5 s
|
||||||
anyway. Frame 1 stays well under 100 ms too (~40 ms), so no secondary HITCH warning appears.
|
font-atlas build window every reload runs through anyway. Frame 1 stays well under 100 ms too (~40
|
||||||
- Slash-command centralisation: `/hellion`, `/hellionView`, `/hellionSeString` and `/hellionDebugger` are now
|
ms), so no secondary HITCH warning appears.
|
||||||
registered during `LoadAsync` instead of inside the corresponding window constructors. The commands work
|
- Slash-command centralisation: `/hellion`, `/hellionView`, `/hellionSeString` and
|
||||||
before their target window is opened the first time, and Dalamud's plugin-manager configuration / open
|
`/hellionDebugger` are now registered during `LoadAsync` instead of inside the corresponding
|
||||||
buttons (`UiBuilder.OpenConfigUi` / `OpenMainUi`) hang on the same path.
|
window constructors. The commands work before their target window is opened the first time, and
|
||||||
- Plugin-load profiling logs stay on: `MessageStore.Connect`, `MessageStore.Migrate`, `FilterAllTabs` and the
|
Dalamud's plugin-manager configuration / open buttons (`UiBuilder.OpenConfigUi` / `OpenMainUi`)
|
||||||
auto-translate warm-up timing log are now Information level rather than Debug. They serve as a tripwire so a
|
hang on the same path.
|
||||||
future regression past 100 ms shows up directly in `/xllog` without re-enabling Debug.
|
- 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
|
- ChatTwo IPC compatibility layer: HellionChat now mirrors ChatTwo's full IPC surface
|
||||||
(`GetChatInputState`, `ChatInputStateChanged`, `Register`, `Unregister`, `Available`, `Invoke`) under the
|
(`GetChatInputState`, `ChatInputStateChanged`, `Register`, `Unregister`, `Available`, `Invoke`)
|
||||||
`ChatTwo.*` namespace in addition to our existing `HellionChat.*` provider gates. Third-party
|
under the `ChatTwo.*` namespace in addition to our existing `HellionChat.*` provider gates.
|
||||||
integrations that historically only subscribe to ChatTwo's IPC — for example Artisan's and AllaganTools'
|
Third-party integrations that historically only subscribe to ChatTwo's IPC — for example Artisan's
|
||||||
context-menu hooks — keep working without requiring a code change on their side. Conflict detection
|
and AllaganTools' context-menu hooks — keep working without requiring a code change on their side.
|
||||||
prevents ChatTwo from loading in parallel with HellionChat, so there is no slot-collision risk at
|
Conflict detection prevents ChatTwo from loading in parallel with HellionChat, so there is no
|
||||||
runtime.
|
slot-collision risk at runtime.
|
||||||
- Migration v17 stays (no schema bump).
|
- Migration v17 stays (no schema bump).
|
||||||
- Internal: hypothesis-triage during the R2 cycle falsified three of the four candidate root causes
|
- 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
|
(font-atlas sync, theme-apply ABGR-cache init, multiple-window render). Actual cause is `DrawList`
|
||||||
cost distributed across ~10 ImGui sections inside ChatLogWindow (5-20 ms each). The six selective defers
|
setup cost distributed across ~10 ImGui sections inside ChatLogWindow (5-20 ms each). The six
|
||||||
above are the pragmatic fix — a clean structural rewrite would belong in the v1.5.x DI-container cycle.
|
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).
|
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
||||||
|
|
||||||
@@ -113,28 +121,31 @@ 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)
|
## 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
|
Ninth sub-patch of the v1.4.x polish-sweep series. Hook-layer cluster (FTS5 full-text search,
|
||||||
investigation) plus three polish quick-wins.
|
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
|
- DbViewer full-text search: optional FTS5 index across the full chat history. Built asynchronously
|
||||||
the update with a progress toast (UI stays responsive, the toggle is disabled until the build completes). The local
|
on first run after the update with a progress toast (UI stays responsive, the toggle is disabled
|
||||||
page-filter remains the default mode. Multi-word queries match as exact phrases; power users can opt into raw FTS5
|
until the build completes). The local page-filter remains the default mode. Multi-word queries
|
||||||
`MATCH` syntax by wrapping their own double-quotes around the term.
|
match as exact phrases; power users can opt into raw FTS5 `MATCH` syntax by wrapping their own
|
||||||
- Custom theme files now auto-reload when edited while the theme is active. Save the JSON in your editor and the live
|
double-quotes around the term.
|
||||||
render picks up the change within a second — no need to re-click the theme in the picker. Disk-stat is throttled to
|
- Custom theme files now auto-reload when edited while the theme is active. Save the JSON in your
|
||||||
1 Hz so per-frame cost stays free.
|
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
|
- 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.
|
`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
|
- Status bar height is derived from `GetTextLineHeightWithSpacing()` plus a DPI-aware spacer so the
|
||||||
correctly at Windows display scaling above 100 %. Linux/Wayland default of 100 % is unaffected.
|
bar renders correctly at Windows display scaling above 100 %. Linux/Wayland default of 100 % is
|
||||||
- Receive-suppressed-tells routing was investigated this cycle and **postponed to v1.5.x**. When other plugins suppress
|
unaffected.
|
||||||
tells via `CheckMessageHandled`, FFXIV's chat pipeline skips the `RaptureLogModule.AddMsgSourceEntry` path, which means
|
- Receive-suppressed-tells routing was investigated this cycle and **postponed to v1.5.x**. When
|
||||||
HellionChat's `ContentIdResolverHook` does not fire and tell-partner identification breaks for AutoTellTab routing.
|
other plugins suppress tells via `CheckMessageHandled`, FFXIV's chat pipeline skips the
|
||||||
The proper fix sits next to the planned ad-block hook layer (`RaptureLogModule.ShowMiniTalkPlayer` and friends) where
|
`RaptureLogModule.AddMsgSourceEntry` path, which means HellionChat's `ContentIdResolverHook` does
|
||||||
the same patch surface comes up anyway.
|
not fire and tell-partner identification breaks for AutoTellTab routing. The proper fix sits next
|
||||||
- Internal: storage form of `messages.Id` clarified (declared BLOB but Microsoft.Data.Sqlite stores Guid parameters as
|
to the planned ad-block hook layer (`RaptureLogModule.ShowMiniTalkPlayer` and friends) where the
|
||||||
TEXT). FTS bulk insert and `LoadByGuids` join now match the TEXT storage form on both sides. Migration v17 stays
|
same patch surface comes up anyway.
|
||||||
(no schema bump).
|
- 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).
|
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
||||||
|
|
||||||
@@ -142,38 +153,43 @@ 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)
|
## 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
|
Eighth sub-patch of the v1.4.x polish-sweep series. First user-visible feature bundle since v1.4.5 —
|
||||||
that survive relog, opt-in Honorific glow rendering, a configurable sidebar, plus a Settings-Save channel-preservation
|
pinned tell tabs that survive relog, opt-in Honorific glow rendering, a configurable sidebar, plus a
|
||||||
fix surfaced during smoke testing.
|
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
|
- TempTell Pin: right-click a TempTell tab in the sidebar and choose "Pin Tab" / "Tab anpinnen".
|
||||||
plugin reload and character logout, keep their conversation history (loaded on demand from the message store on
|
Pinned tabs survive plugin reload and character logout, keep their conversation history (loaded on
|
||||||
rehydrate), and stay bound to the same `/tell` partner. Hard cap of 5 pinned tabs in a pool separate from the 15-tab
|
demand from the message store on rehydrate), and stay bound to the same `/tell` partner. Hard cap
|
||||||
auto-tell pool — total ceiling is 20 tabs. The sidebar groups pinned tabs into their own section with a divider header
|
of 5 pinned tabs in a pool separate from the 15-tab auto-tell pool — total ceiling is 20 tabs. The
|
||||||
- Honorific glow outlines now render via an 8-direction DrawList pre-pass when the title carries a Glow colour. Opt-in
|
sidebar groups pinned tabs into their own section with a divider header
|
||||||
via **Settings → Integrations → Render glow outlines (Honorific)** (default off). Honorific's gradient surface
|
- Honorific glow outlines now render via an 8-direction DrawList pre-pass when the title carries a
|
||||||
(`Color3`, `GradientColourSet`, `GradientAnimationStyle`) is parsed and stashed for a later cycle but renders as the
|
Glow colour. Opt-in via **Settings → Integrations → Render glow outlines (Honorific)** (default
|
||||||
primary colour until then — the v1.4.7 DTO already mirrors all four extra fields so the JSON roundtrip doesn't
|
off). Honorific's gradient surface (`Color3`, `GradientColourSet`, `GradientAnimationStyle`) is
|
||||||
silent-drop them
|
parsed and stashed for a later cycle but renders as the primary colour until then — the v1.4.7 DTO
|
||||||
- Sidebar width configurable in **Theme & Layout** (44–160 px, default 44 stays icon-only). The icon button stretches
|
already mirrors all four extra fields so the JSON roundtrip doesn't silent-drop them
|
||||||
with the configured width so a widened sidebar looks intentional, not a 36 px icon floating in empty space
|
- Sidebar width configurable in **Theme & Layout** (44–160 px, default 44 stays icon-only). The icon
|
||||||
- `Configuration.UpdateFrom` now preserves the runtime `CurrentChannel` across the persistent-tab merge alongside
|
button stretches with the configured width so a widened sidebar looks intentional, not a 36 px
|
||||||
`Messages` and `LastSendUnread`. `TabSwitched` deep-clones the seeded channel from the previous tab instead of sharing
|
icon floating in empty space
|
||||||
the same `UsedChannel` instance. Together these fix a regression where Settings-Save on a Party or Linkshell tab
|
- `Configuration.UpdateFrom` now preserves the runtime `CurrentChannel` across the persistent-tab
|
||||||
popped the chat input back to `/tell <pinned-partner>` on the next interaction
|
merge alongside `Messages` and `LastSendUnread`. `TabSwitched` deep-clones the seeded channel from
|
||||||
- `Util/ImGuiUtil.cs` `DrawArrows` IconButton id uses `(id + 1).ToString()` with explicit parentheses instead of the
|
the previous tab instead of sharing the same `UsedChannel` instance. Together these fix a
|
||||||
operator-precedence quirk `id + 1.ToString()` (which resolved to `id.ToString() + "1"`). Single live caller is
|
regression where Settings-Save on a Party or Linkshell tab popped the chat input back to
|
||||||
`Ui/DbViewer.cs:227` page-navigation
|
`/tell <pinned-partner>` on the next interaction
|
||||||
- Internal: `IPluginLogProxy` indirection over Dalamud's `IPluginLog` routes all ~91 `Plugin.Log` call sites through a
|
- `Util/ImGuiUtil.cs` `DrawArrows` IconButton id uses `(id + 1).ToString()` with explicit
|
||||||
testable proxy. `MessageStore.Migrate0` can now run in xUnit without loading `Dalamud.dll`, closing the gap F12.1 left
|
parentheses instead of the operator-precedence quirk `id + 1.ToString()` (which resolved to
|
||||||
in v1.4.6. Production wrapper `DalamudPluginLogProxy` and Build-Suite `FakePluginLogProxy` mirror the full
|
`id.ToString() + "1"`). Single live caller is `Ui/DbViewer.cs:227` page-navigation
|
||||||
`IPluginLog` surface (`Verbose`/`Debug`/`Information`/`Info`/`Warning`/`Error`/`Fatal`) with single-string,
|
- 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
|
`Exception+string`, and `params object[]` overloads
|
||||||
- Internal: TempTab counter switched from an `Interlocked` cached field to a derived `Tabs.Count(predicate)`. Pin-state
|
- Internal: TempTab counter switched from an `Interlocked` cached field to a derived
|
||||||
transitions (TryPin / Unpin / Promote) are cold-path and don't need lock-free reads; counter mutation surface dropped
|
`Tabs.Count(predicate)`. Pin-state transitions (TryPin / Unpin / Promote) are cold-path and don't
|
||||||
from 5 to 0 sites. Build-Suite floor 688 → 710 (+22)
|
need lock-free reads; counter mutation surface dropped from 5 to 0 sites. Build-Suite floor 688 →
|
||||||
- Schema bump v16 → v17 is additive: new `Tab.IsPinned` bool, default false. Existing v16 configs load cleanly and get
|
710 (+22)
|
||||||
their `Version` stamp bumped after the gate check
|
- 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).
|
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
||||||
|
|
||||||
@@ -181,45 +197,51 @@ 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)
|
## 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
|
Maintenance patch. No user-visible behaviour changes; tightens the development feedback loop, fixes
|
||||||
upstream-inherited bugs from ChatTwo `f35b7d3`, and prepares the code for the v1.4.7 backlog cleanup.
|
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
|
- `scripts/preflight.sh` gains Block E (`dotnet csharpier check`) and Block F (`markdownlint-cli2`)
|
||||||
markdown violations are caught at the pre-push gate. `.markdownlint.json` adds `MD024 siblings_only` and disables
|
so reflow drift and markdown violations are caught at the pre-push gate. `.markdownlint.json` adds
|
||||||
`MD036` so the bilingual forge-post bold-emphasis headings pass linting; the `.claude/` directory is excluded from the
|
`MD024 siblings_only` and disables `MD036` so the bilingual forge-post bold-emphasis headings pass
|
||||||
scan
|
linting; the `.claude/` directory is excluded from the scan
|
||||||
- `FontManager.AddFontWithFallback` catch-filter now covers `InvalidOperationException` and `ArgumentException` on top
|
- `FontManager.AddFontWithFallback` catch-filter now covers `InvalidOperationException` and
|
||||||
of the existing IO triad. The warning log carries the exception type name, so the diagnostic path knows which class of
|
`ArgumentException` on top of the existing IO triad. The warning log carries the exception type
|
||||||
atlas-toolkit throw triggered the NotoSansCjkRegular fallback
|
name, so the diagnostic path knows which class of atlas-toolkit throw triggered the
|
||||||
- `BrandingLinks` (5 URLs) and `Integrations/IntegrationLinks` (2 URLs) validate themselves on first module load via
|
NotoSansCjkRegular fallback
|
||||||
`[ModuleInitializer]` + a shared `UrlValidation.ValidateAll` helper. A malformed URL now throws
|
- `BrandingLinks` (5 URLs) and `Integrations/IntegrationLinks` (2 URLs) validate themselves on first
|
||||||
`InvalidOperationException` at plugin load with the source class and the broken URL in the message
|
module load via `[ModuleInitializer]` + a shared `UrlValidation.ValidateAll` helper. A malformed
|
||||||
- Cherry-picked from ChatTwo upstream `f35b7d3`: `Chat.SetChannel` no longer leaks the native `Utf8String` when the
|
URL now throws `InvalidOperationException` at plugin load with the source class and the broken URL
|
||||||
linkshell check rejects the channel. The validity check is now wrapped around the `ChangeChatChannel` call instead of
|
in the message
|
||||||
short-circuiting before `Dtor`. `ValidAnyLinkshell` is renamed to `IsChannelOrExistingLinkshell` and the
|
- Cherry-picked from ChatTwo upstream `f35b7d3`: `Chat.SetChannel` no longer leaks the native
|
||||||
`ChatLogWindow` call-site follows the rename
|
`Utf8String` when the linkshell check rejects the channel. The validity check is now wrapped
|
||||||
- Cherry-picked from ChatTwo upstream `f35b7d3`: `Tab.Clone` now deep-clones `UsedChannel` and `TellTarget`. The old
|
around the `ChangeChatChannel` call instead of short-circuiting before `Dtor`. `ValidAnyLinkshell`
|
||||||
`CurrentChannel = CurrentChannel` was a reference copy, so PopOut and Temp tabs mutated each other's channel state
|
is renamed to `IsChannelOrExistingLinkshell` and the `ChatLogWindow` call-site follows the rename
|
||||||
(incl. tell target). `TellTarget.From(t)` static factory is replaced with an instance `Clone()`; `UsedChannel.Clone()`
|
- Cherry-picked from ChatTwo upstream `f35b7d3`: `Tab.Clone` now deep-clones `UsedChannel` and
|
||||||
is new and runs deep-clone on both TellTarget references
|
`TellTarget`. The old `CurrentChannel = CurrentChannel` was a reference copy, so PopOut and Temp
|
||||||
- `ChatLogWindow` active-tab underline pill now scales with `ImGuiHelpers.GlobalScale` and rounds its DrawList
|
tabs mutated each other's channel state (incl. tell target). `TellTarget.From(t)` static factory
|
||||||
coordinates to physical pixels via `MathF.Round`, so the 2 px line stays crisp on 125 % and 150 % DPI setups instead
|
is replaced with an instance `Clone()`; `UsedChannel.Clone()` is new and runs deep-clone on both
|
||||||
of bleeding into a sub-pixel blur
|
TellTarget references
|
||||||
- `ImGuiUtil.IconButton` width parameter no longer subtracts HUD-scaled `CellPadding.X * 2` from the raw `int` width.
|
- `ChatLogWindow` active-tab underline pill now scales with `ImGuiHelpers.GlobalScale` and rounds
|
||||||
`ImGui.Button` handles its own frame padding internally, so the measured `buttonWidth` now passes through verbatim
|
its DrawList coordinates to physical pixels via `MathF.Round`, so the 2 px line stays crisp on 125
|
||||||
(inspired-by upstream `f35b7d3`, but our two call-sites need the parameter, so the param itself stays)
|
% and 150 % DPI setups instead of bleeding into a sub-pixel blur
|
||||||
- Internal: `HellionStyle` ChildBgAlpha threshold logic extracted to `HellionStyleHelpers.ResolveChildBgAlpha` with a
|
- `ImGuiUtil.IconButton` width parameter no longer subtracts HUD-scaled `CellPadding.X * 2` from the
|
||||||
build-suite mirror test that pins the 0.999f cutoff. `Plugin.SaveConfig` clones only the temp-tab subset in the
|
raw `int` width. `ImGui.Button` handles its own frame padding internally, so the measured
|
||||||
pre-serialization snapshot instead of the full tab list. `SettingsOverview` caches `ImGui.GetWindowDrawList()` once
|
`buttonWidth` now passes through verbatim (inspired-by upstream `f35b7d3`, but our two call-sites
|
||||||
per frame and passes the pointer down to `DrawCard`
|
need the parameter, so the param itself stays)
|
||||||
- Internal: `Dalamud.Utility.Util` static surface (`IsWine`, `OpenLink`) routed through a new `IPlatformUtil`
|
- Internal: `HellionStyle` ChildBgAlpha threshold logic extracted to
|
||||||
indirection. `MessageStore`'s `IsWine` probe is now reachable from the xUnit AppDomain via a `FakePlatformUtil`
|
`HellionStyleHelpers.ResolveChildBgAlpha` with a build-suite mirror test that pins the 0.999f
|
||||||
fixture (full isolated MessageStore construction still pending — `Plugin.Log.Information` in `Migrate0` is a separate
|
cutoff. `Plugin.SaveConfig` clones only the temp-tab subset in the pre-serialization snapshot
|
||||||
Dalamud-static surface, slated for v1.4.7)
|
instead of the full tab list. `SettingsOverview` caches `ImGui.GetWindowDrawList()` once per frame
|
||||||
- Built-in themes: Crystal Nocturne (royal sapphire and electric magenta over obsidian, by CRYSTALLITE) replaces Moonlit
|
and passes the pointer down to `DrawCard`
|
||||||
Bloom in the built-in roster. Users who had Moonlit Bloom selected fall back to the default Hellion Arctic on the
|
- Internal: `Dalamud.Utility.Util` static surface (`IsWine`, `OpenLink`) routed through a new
|
||||||
first plugin load; an existing custom JSON copy of Moonlit Bloom under `pluginConfigs/HellionChat/themes/` keeps
|
`IPlatformUtil` indirection. `MessageStore`'s `IsWine` probe is now reachable from the xUnit
|
||||||
working unchanged
|
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>
|
Modding & support: join Hellion Forge — <https://discord.gg/X9V7Kcv5gR>
|
||||||
|
|
||||||
@@ -229,26 +251,31 @@ Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
|||||||
|
|
||||||
## Hellion Chat 1.4.5 — UX and Robustness (2026-05-12)
|
## 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
|
Sixth sub-patch of the v1.4.x polish-sweep series. User-visible robustness fixes plus two doc/test
|
||||||
audit backlog. No schema bump, no migration.
|
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
|
- `ChatLogWindow.Draw` now surfaces a one-shot warning notification when the draw path throws. The
|
||||||
goes to `/xllog` via `Plugin.Log.Error`; the notification is suppressed for the rest of the plugin session so a
|
stack trace still goes to `/xllog` via `Plugin.Log.Error`; the notification is suppressed for the
|
||||||
recurring failure can't spam the notification stack frame-by-frame. Pattern-match to the existing `Plugin.cs:505-516`
|
rest of the plugin session so a recurring failure can't spam the notification stack
|
||||||
migration-blocker notification
|
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
|
- `FirstRunWizard` splits accept from close. `OnClose` no longer silently sets `FirstRunCompleted`,
|
||||||
leaves the wizard pending and it reopens on the next plugin load. A new footer "Later — keep defaults" button is the
|
so closing the X leaves the wizard pending and it reopens on the next plugin load. A new footer
|
||||||
explicit path to dismiss without picking a profile. Bilingual strings (EN + DE) plus a tooltip
|
"Later — keep defaults" button is the explicit path to dismiss without picking a profile.
|
||||||
- `InputHistoryService.Reset` is wired into `Plugin.DisposeAsync` alongside the existing pure-memory cleanups. Static
|
Bilingual strings (EN + DE) plus a tooltip
|
||||||
state used to survive a plugin reload — the next load now starts with an empty history
|
- `InputHistoryService.Reset` is wired into `Plugin.DisposeAsync` alongside the existing pure-memory
|
||||||
- `FontManager.GetHellionFontBytes` becomes `TryGetHellionFontBytes` with a nullable return. On miss (broken csproj,
|
cleanups. Static state used to survive a plugin reload — the next load now starts with an empty
|
||||||
hand-rolled dev build) the caller falls back to the system-font path that `UseHellionFont=false` already uses, plus a
|
history
|
||||||
`Plugin.Log.Warning`. The whole UiBuilder no longer throws if the embedded font resource is absent
|
- `FontManager.GetHellionFontBytes` becomes `TryGetHellionFontBytes` with a nullable return. On miss
|
||||||
- `Plugin.cs:167-168` gets a 4-line reasoning comment around the session-only `RemoveAll(IsTempTab)`: tells are usually
|
(broken csproj, hand-rolled dev build) the caller falls back to the system-font path that
|
||||||
privacy-filtered, resurrecting an empty crashed-session tab would trigger DB reconstruction on the next load.
|
`UseHellionFont=false` already uses, plus a `Plugin.Log.Warning`. The whole UiBuilder no longer
|
||||||
`TempTabCounter.InitFromList` mirrors the post-strip semantic in the Build-Suite with a pinning test
|
throws if the embedded font resource is absent
|
||||||
- `StatusBar.cs` drops the version slot when the chat window's content width minus the version text is below 200 px. The
|
- `Plugin.cs:167-168` gets a 4-line reasoning comment around the session-only
|
||||||
right-aligned version used to clip into the four left-side slots in narrow windows
|
`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>
|
Modding & support: join Hellion Forge — <https://discord.gg/X9V7Kcv5gR>
|
||||||
|
|
||||||
@@ -258,29 +285,32 @@ 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)
|
## 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
|
Fifth sub-patch of the v1.4.x polish-sweep series. Threading assumptions are documented per-method,
|
||||||
falls away in `AutoTellTabsService`, IPC-cleanup failures become visible, and the privacy filter now speaks up when an
|
a hot-path lock falls away in `AutoTellTabsService`, IPC-cleanup failures become visible, and the
|
||||||
unknown ChatType shows up.
|
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
|
- `AutoTellTabsService.ActiveTempTabCount` switches from a lock-protected LINQ `Count` to an
|
||||||
in sync with `Config.Tabs` from inside the existing mutation paths. `Initialize()` seeds the counter from the
|
`Interlocked` counter kept in sync with `Config.Tabs` from inside the existing mutation paths.
|
||||||
persisted Tabs list, and `SaveConfig`'s snapshot-restore path calls a new `ResyncTempTabCounter()` so the mid-step
|
`Initialize()` seeds the counter from the persisted Tabs list, and `SaveConfig`'s snapshot-restore
|
||||||
`RemoveAll` doesn't leave the counter drifting. Pure-helper test mirror lives in the Build-Suite repo
|
path calls a new `ResyncTempTabCounter()` so the mid-step `RemoveAll` doesn't leave the counter
|
||||||
- `HonorificService` per-method threading banners replace the block comment at the bottom of the file. Each IPC callback
|
drifting. Pure-helper test mirror lives in the Build-Suite repo
|
||||||
(`TryInitialPull`, `OnTitleChanged`, `OnReady`, `OnDisposing`, `TryUnsubscribe`) and the `CurrentTitle` field carry a
|
- `HonorificService` per-method threading banners replace the block comment at the bottom of the
|
||||||
one-line `// Thread:` annotation so the framework-thread invariant is visible at the call site
|
file. Each IPC callback (`TryInitialPull`, `OnTitleChanged`, `OnReady`, `OnDisposing`,
|
||||||
- `TryUnsubscribe` log-level upgraded from `Debug` to `Warning`. A silent unsubscribe failure leaks a live subscription
|
`TryUnsubscribe`) and the `CurrentTitle` field carry a one-line `// Thread:` annotation so the
|
||||||
across plugin reloads, which is exactly the kind of issue that should not be at Debug
|
framework-thread invariant is visible at the call site
|
||||||
- `AutoTranslate.PreloadCache` thread now has `IsBackground = true` and a thread name. Without `IsBackground` the warmup
|
- `TryUnsubscribe` log-level upgraded from `Debug` to `Warning`. A silent unsubscribe failure leaks
|
||||||
blocks plugin unload (typically 100-300 ms). Pattern-match to `MessageManager` (F6.1) and `Plugin.RetentionSweep`
|
a live subscription across plugin reloads, which is exactly the kind of issue that should not be
|
||||||
(F9.3), both since v1.4.0
|
at Debug
|
||||||
- `Configuration.IsAllowedForStorage` adds a one-line `Plugin.Log.Warning` for the first occurrence of any ChatType that
|
- `AutoTranslate.PreloadCache` thread now has `IsBackground = true` and a thread name. Without
|
||||||
isn't in `PrivacyPersistChannels`. Dedup via a `NonSerialized` `HashSet<ChatType>`, so the warning fires once per
|
`IsBackground` the warmup blocks plugin unload (typically 100-300 ms). Pattern-match to
|
||||||
runtime — not once per frame, not once per install. Failsafe routing through `PrivacyPersistUnknownChannels` is
|
`MessageManager` (F6.1) and `Plugin.RetentionSweep` (F9.3), both since v1.4.0
|
||||||
unchanged
|
- `Configuration.IsAllowedForStorage` adds a one-line `Plugin.Log.Warning` for the first occurrence
|
||||||
- `PrivacyPersistUnknownChannels` field default flipped from `false` to `true` for new installs via a constant in
|
of any ChatType that isn't in `PrivacyPersistChannels`. Dedup via a `NonSerialized`
|
||||||
`PrivacyDefaults`. Existing configs keep their explicit choice — the deserializer overrides the initializer. No schema
|
`HashSet<ChatType>`, so the warning fires once per runtime — not once per frame, not once per
|
||||||
bump, no migration, no first-run banner
|
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>
|
Modding & support: join Hellion Forge — <https://discord.gg/X9V7Kcv5gR>
|
||||||
|
|
||||||
@@ -290,22 +320,26 @@ 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)
|
## 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
|
Plugin lifecycle migrated to Dalamud's `IAsyncDalamudPlugin` API. The constructor now does only the
|
||||||
(config load, language init, conflict detection); migrations, service allocations, window construction and hook
|
bootstrap-essentials (config load, language init, conflict detection); migrations, service
|
||||||
subscription move to `LoadAsync`. Dalamud can keep its UI responsive while the heavy work runs.
|
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
|
- `IAsyncDalamudPlugin` two-phase load with per-line `CaptureFailure` in `DisposeAsync` (mirrors
|
||||||
pattern); idempotency guard protects against reload races
|
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
|
- Schema-gate replaces the v9 → v16 migration chain. Configs on schema v16+ load directly; older
|
||||||
"install v1.4.2 first" error so the historic migration path stays intact
|
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
|
- `AutoTranslate.PreloadCache` moved off the load path. First use may have a sub-second hitch
|
||||||
upstream chose differently, we accept first-use latency
|
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
|
- `FontManager.BuildFonts` is called sync at the start of `LoadAsync`; Dalamud rebuilds the font
|
||||||
pipeline so the custom Hellion-Exo2 font appears with a brief font-pop after load (matches ChatTwo's behaviour)
|
atlas on its own pipeline so the custom Hellion-Exo2 font appears with a brief font-pop after load
|
||||||
- Custom-repo URL moved to `gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat`. GitHub repo stays as a frozen
|
(matches ChatTwo's behaviour)
|
||||||
v1.4.2 snapshot; new releases ship from Gitea. Existing testers need to update the custom-repo URL once
|
- Custom-repo URL moved to `gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat`. GitHub repo
|
||||||
- Plugin-load time in this release sits at ~3.7 s median (5 reloads), comparable to v1.4.2. Async migration is
|
stays as a frozen v1.4.2 snapshot; new releases ship from Gitea. Existing testers need to update
|
||||||
foundational for v1.4.4 Lazy-Init optimisations rather than an immediate user-perceived win
|
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>
|
Modding & support: join Hellion Forge — <https://discord.gg/X9V7Kcv5gR>
|
||||||
|
|
||||||
@@ -315,17 +349,21 @@ Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
|||||||
|
|
||||||
## Hellion Chat 1.4.2 — ChatLog Frame-Hot-Path
|
## 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.
|
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.
|
- `DrawMessages` card-mode hoists `theme`/`drawList`/`winLeft`/`winRight`/`borderColorAbgr` out of
|
||||||
About 500 redundant calls per frame at 100 visible messages, multiplied by every pop-out window
|
the per-message loop. About 500 redundant calls per frame at 100 visible messages, multiplied by
|
||||||
- Auto-tell tab tint and icon use a per-tab cache. Hash computation and string allocation only happen when the tell
|
every pop-out window
|
||||||
target name or world drifts. `AutoTellTabTint` stays a pure hash helper; cache lives in a thin `TabTintCache` wrapper
|
- Auto-tell tab tint and icon use a per-tab cache. Hash computation and string allocation only
|
||||||
- Status bar gates its tab aggregation behind the same one-second cache it already used for the format strings. LINQ
|
happen when the tell target name or world drifts. `AutoTellTabTint` stays a pure hash helper;
|
||||||
`Sum` and `Count` replaced with a single `foreach` pass that runs on roughly 1 % of frames
|
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
|
Realistic frame-time recovery: 2-5 % in typical scenes, more on pop-out-heavy setups because the
|
||||||
scales per window.
|
card-border hoist scales per window.
|
||||||
|
|
||||||
Modding & support: join Hellion Forge — <https://discord.gg/X9V7Kcv5gR>
|
Modding & support: join Hellion Forge — <https://discord.gg/X9V7Kcv5gR>
|
||||||
|
|
||||||
@@ -335,23 +373,24 @@ Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
|||||||
|
|
||||||
## Hellion Chat 1.4.1 — Theme Engine Performance
|
## 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,
|
Second sub-patch of the v1.4.x Polish Sweep series. Heap pressure from the theme engine's per-frame
|
||||||
plus a tenth built-in theme and hardening for the custom-theme hot-reload.
|
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
|
- Theme records carry a pre-computed ABGR-packed cache for every color slot; cache is filled when
|
||||||
registered and refreshed defensively on every `Switch()`
|
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
|
- `HellionStyle.PushGlobal` reads ABGR values from the cache instead of calling
|
||||||
frame; ~13 % render-time recovery measured in typical scenes (plan estimate was 2–6 %, real ~10–15 %)
|
`ColourUtil.RgbaToAbgr` per slot per frame; ~13 % render-time recovery measured in typical scenes
|
||||||
- `ThemeRegistry` custom-theme reload distinguishes a recoverable file lock (editor mid-save) from a permanent IO
|
(plan estimate was 2–6 %, real ~10–15 %)
|
||||||
failure; locked themes keep their last-known-good snapshot and retry on the next lookup instead of dropping out of the
|
- `ThemeRegistry` custom-theme reload distinguishes a recoverable file lock (editor mid-save) from a
|
||||||
picker
|
permanent IO failure; locked themes keep their last-known-good snapshot and retry on the next
|
||||||
- New built-in: **Synthwave Sunset** — Hot Magenta + Cyan on midnight violet, 80s neon-grid vibes; tenth theme in the
|
lookup instead of dropping out of the picker
|
||||||
picker
|
- New built-in: **Synthwave Sunset** — Hot Magenta + Cyan on midnight violet, 80s neon-grid vibes;
|
||||||
- Author credits refreshed: brand themes are credited as "Hellion Forge"; **Mint Grove** and **Forge Merchantman** now
|
tenth theme in the picker
|
||||||
credited to **Carla Beleandis** as a community thanks
|
- 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
|
No schema bump, no user-visible behaviour change other than smoother frames on GC-sensitive setups
|
||||||
colour option.
|
and one additional colour option.
|
||||||
|
|
||||||
Modding & support: join Hellion Forge — <https://discord.gg/X9V7Kcv5gR>
|
Modding & support: join Hellion Forge — <https://discord.gg/X9V7Kcv5gR>
|
||||||
|
|
||||||
@@ -361,20 +400,20 @@ Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
|||||||
|
|
||||||
## Hellion Chat 1.4.0 — Critical Lifecycle Fixes
|
## 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
|
First sub-patch of the v1.4.x Polish Sweep series. Seven known lifecycle and race bugs eliminated
|
||||||
refactor sits on top.
|
before any performance refactor sits on top.
|
||||||
|
|
||||||
- MessageStore disposal no longer triggers GC.Collect globally; Pooling=false on the SQLite connection means there's
|
- MessageStore disposal no longer triggers GC.Collect globally; Pooling=false on the SQLite
|
||||||
nothing left to clean up by hand
|
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
|
- PendingMessage and RetentionSweep worker threads are explicitly marked IsBackground=true so the
|
||||||
unload during XIVLauncher reload without waiting for them
|
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
|
- EmoteCache image and gif loaders moved from async-void to async Task with a shared task tracker,
|
||||||
so an in-flight load can no longer write to a disposed EmoteImages entry
|
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
|
- 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
|
- Plugin.Dispose flushes any pending DeferredSaveFrames before tearing services down, so settings
|
||||||
last few frames before disable are no longer lost
|
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
|
- The v13→v14 config migration now reads the pre-v13 backup and carries HellionThemeWindowOpacity
|
||||||
WindowOpacity field instead of falling back to the default 0.85
|
into the new WindowOpacity field instead of falling back to the default 0.85
|
||||||
|
|
||||||
Modding & support: join Hellion Forge — <https://discord.gg/X9V7Kcv5gR>
|
Modding & support: join Hellion Forge — <https://discord.gg/X9V7Kcv5gR>
|
||||||
|
|
||||||
@@ -384,14 +423,14 @@ Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
|||||||
|
|
||||||
## Hellion Chat 1.3.0 — Plugin Integrations: Honorific
|
## Hellion Chat 1.3.0 — Plugin Integrations: Honorific
|
||||||
|
|
||||||
First step on the plugin-integration roadmap. HellionChat now listens to Honorific and shows your custom title in the
|
First step on the plugin-integration roadmap. HellionChat now listens to Honorific and shows your
|
||||||
chat header. The slot auto-hides when Honorific is not installed, when no custom title is active, or when you are using
|
custom title in the chat header. The slot auto-hides when Honorific is not installed, when no custom
|
||||||
the original FFXIV title.
|
title is active, or when you are using the original FFXIV title.
|
||||||
|
|
||||||
- New "Integrations" settings tab
|
- New "Integrations" settings tab
|
||||||
- Honorific integration with auto-detection and live updates
|
- Honorific integration with auto-detection and live updates
|
||||||
- "Coming soon" preview of the next five planned integrations: context menu actions, smart notifications, RP status
|
- "Coming soon" preview of the next five planned integrations: context menu actions, smart
|
||||||
block, ExtraChat channels, and quick DM compose
|
notifications, RP status block, ExtraChat channels, and quick DM compose
|
||||||
- Maintainer attribution buttons for Honorific repo and Caraxi
|
- Maintainer attribution buttons for Honorific repo and Caraxi
|
||||||
- New service-class pattern under HellionChat/Integrations/
|
- New service-class pattern under HellionChat/Integrations/
|
||||||
|
|
||||||
@@ -406,20 +445,22 @@ Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
|||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Four new built-in themes:
|
- Four new built-in themes:
|
||||||
- **Night Blue** — Royal Blue on deep marine, cool tech-dashboard mood
|
- **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)
|
- **Indigo Violet** — Royal Violet on deep indigo with a turquoise-mint counter (aurora glitter
|
||||||
- **Forge Merchantman** — Patina bronze on workshop slate with warm amber counter (Hellion Forge identity)
|
feel)
|
||||||
- **Hellion Spectrum** — Deuteran/Protan-safe channel colours using Wong/Okabe-Ito palette tones; channel identity
|
- **Forge Merchantman** — Patina bronze on workshop slate with warm amber counter (Hellion Forge
|
||||||
(Tell pink, Yell yellow, Shout orange, Party blue, FC green) preserved while keeping every channel separable under
|
identity)
|
||||||
red-green colour vision deficiency
|
- **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
|
- Built-in theme catalogue grown from five to nine
|
||||||
|
|
||||||
### Notes
|
### Notes
|
||||||
|
|
||||||
- No engine changes, no settings touched, no migration
|
- No engine changes, no settings touched, no migration
|
||||||
- Default theme unchanged (Hellion Arctic). Existing custom themes keep working.
|
- 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
|
- Hellion Spectrum covers the ~99 % of CVD cases that are red-green; a Tritan-safe variant could
|
||||||
if there is demand.
|
follow in a later cycle if there is demand.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -427,21 +468,23 @@ Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
|||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Settings cards re-sorted thematically: 9 cards remain, each card has one clear job and a one-line subtitle.
|
- Settings cards re-sorted thematically: 9 cards remain, each card has one clear job and a one-line
|
||||||
- **Theme & Layout** (new) collects the theme picker, window frame style (title bar, sidebar, hide button, pop-out title
|
subtitle.
|
||||||
bar) and the timestamp style options.
|
- **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.
|
- **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
|
- **Data Management** (new) collects retention windows, cleanup, export, the database viewer and the
|
||||||
advanced tools.
|
shift-click advanced tools.
|
||||||
- **Privacy** is now focused on the privacy filter alone.
|
- **Privacy** is now focused on the privacy filter alone.
|
||||||
- **Chat** absorbs the Auto-Tell-Tabs history-preload slider that used to live under Privacy.
|
- **Chat** absorbs the Auto-Tell-Tabs history-preload slider that used to live under Privacy.
|
||||||
- **General** groups the keybind mode under Input.
|
- **General** groups the keybind mode under Input.
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
- Legacy "Style override" option and the unused style-name field — both obsolete since the v1.1.0 themes engine.
|
- Legacy "Style override" option and the unused style-name field — both obsolete since the v1.1.0
|
||||||
- Legacy `WindowAlpha` slider — if you had it set, the value is auto-migrated to Theme & Layout → Window Style → Window
|
themes engine.
|
||||||
Transparency.
|
- Legacy `WindowAlpha` slider — if you had it set, the value is auto-migrated to Theme & Layout →
|
||||||
|
Window Style → Window Transparency.
|
||||||
- Unused `ShowThemeQuickPicker` schema field.
|
- Unused `ShowThemeQuickPicker` schema field.
|
||||||
|
|
||||||
### Migration
|
### Migration
|
||||||
@@ -456,82 +499,93 @@ Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Sidebar tab modernization: icon-only at fixed 44 px, tooltip on hover, vertical accent pill for active tab
|
- 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
|
- Top tabs: accent underline pill replaces background fill on active tab
|
||||||
- Per-tab custom icons in Settings → Tabs (15-glyph FontAwesome picker)
|
- 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
|
- 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
|
- 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
|
- 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
|
- Auto-Tell tabs: per-partner hashed icon (7-glyph pool:
|
||||||
(12-color palette) — 84 distinct icon+color combinations
|
envelope/star/heart/bell/bookmark/flag/fire) plus hashed color (12-color palette) — 84 distinct
|
||||||
- Unread indicator: pulsing red dot in the top-right corner of any sidebar tab icon with unread messages, 2-second
|
icon+color combinations
|
||||||
sine-wave pulse, respects `Configuration.ReduceMotion`
|
- 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
|
### Changed
|
||||||
|
|
||||||
- Migration v14 → v15: deprecated Configuration fields `HellionThemeEnabled` and `HellionThemeWindowOpacity` removed
|
- Migration v14 → v15: deprecated Configuration fields `HellionThemeEnabled` and
|
||||||
- Appearance settings cleaned: legacy theme-engine bindings replaced by Themes tab (introduced in v1.1.0)
|
`HellionThemeWindowOpacity` removed
|
||||||
|
- Appearance settings cleaned: legacy theme-engine bindings replaced by Themes tab (introduced in
|
||||||
|
v1.1.0)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Settings save no longer wipes chat history by default — the heavy `ClearAllTabs + FilterAllTabsAsync` cycle now only
|
- Settings save no longer wipes chat history by default — the heavy
|
||||||
runs when a filter-relevant setting actually changed (Privacy filter, persisted channels, per-tab channel selection).
|
`ClearAllTabs + FilterAllTabsAsync` cycle now only runs when a filter-relevant setting actually
|
||||||
Cosmetic changes keep the in-session chat intact
|
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
|
- Identifier-based `MessageList` restore in `Configuration.UpdateFrom` plus TempTab skip in
|
||||||
`ClearAllTabs`/`FilterAllTabs` ensure persistent tabs and Auto-Tell tabs both survive the save
|
`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 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
|
- 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
|
- Status bar version slot (`vX.Y.Z · Hellion`) no longer clips its rightmost character
|
||||||
|
|
||||||
### Notes
|
### Notes
|
||||||
|
|
||||||
- Polish phase (animations, theme crossfade, header quick-picker) follows in v1.3.0
|
- 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
|
- Top-Tab icon prefixes were considered but dropped: Dalamud's default font atlas does not include
|
||||||
codepoints, so mixed-font in a single TabItem label renders as tofu. Underline pill alone is the v1.2.0 visual
|
FontAwesome codepoints, so mixed-font in a single TabItem label renders as tofu. Underline pill
|
||||||
treatment for top tabs. Resolution would require Font-Atlas merge at FontManager level — out of scope.
|
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
|
## [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.
|
First major UI cycle after v1.0.0. Theme engine, five built-in themes, custom themes via JSON,
|
||||||
|
settings card grid.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- **Theme engine** with five built-in themes: Hellion Arctic (default), Chat 2 Classic, Event Horizon, Moonlit Bloom,
|
- **Theme engine** with five built-in themes: Hellion Arctic (default), Chat 2 Classic, Event
|
||||||
Mint Grove.
|
Horizon, Moonlit Bloom, Mint Grove.
|
||||||
- **Settings → Themes** with mini mockup preview per theme. Clicking a card instantly switches the entire plugin (chat,
|
- **Settings → Themes** with mini mockup preview per theme. Clicking a card instantly switches the
|
||||||
settings, pop-outs).
|
entire plugin (chat, settings, pop-outs).
|
||||||
- **Custom themes via JSON** in `pluginConfigs/HellionChat/themes/`. On first start, `example-theme.json` is placed
|
- **Custom themes via JSON** in `pluginConfigs/HellionChat/themes/`. On first start,
|
||||||
there as a template.
|
`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
|
- **Optional theme chat channel colours**: themes can ship their own channel colours. On switch, a
|
||||||
_Apply / Keep current_ — never applied automatically.
|
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 +
|
- **Settings card grid**: new overview on open, clicking a card navigates into the section's detail
|
||||||
ESC navigate back.
|
view. Breadcrumb + ESC navigate back.
|
||||||
- **`docs/THEME-AUTHORING.md`** as a guide for writing custom themes, with Hellion Forge branding.
|
- **`docs/THEME-AUTHORING.md`** as a guide for writing custom themes, with Hellion Forge branding.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- **Plugin icon** updated to Hellion Forge hammer (previously a ChatTwo derivative).
|
- **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
|
- **Settings detail view** uses the full width — the second tab list on the left is gone because the
|
||||||
handles navigation.
|
card overview handles navigation.
|
||||||
- **`HellionStyle.PushGlobal`** is now theme-driven (`PushGlobal(theme, opacity)`) instead of const-palette-driven.
|
- **`HellionStyle.PushGlobal`** is now theme-driven (`PushGlobal(theme, opacity)`) instead of
|
||||||
- **Configuration v13 → v14**: all users land on `hellion-arctic`. Those who prefer the upstream look can select
|
const-palette-driven.
|
||||||
`chat2-classic` in Settings → Themes.
|
- **Configuration v13 → v14**: all users land on `hellion-arctic`. Those who prefer the upstream
|
||||||
|
look can select `chat2-classic` in Settings → Themes.
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
|
|
||||||
- `Configuration.HellionThemeEnabled` and `HellionThemeWindowOpacity` remain readable for one release as a safety net
|
- `Configuration.HellionThemeEnabled` and `HellionThemeWindowOpacity` remain readable for one
|
||||||
but are no longer evaluated. Removal planned for v1.2.0.
|
release as a safety net but are no longer evaluated. Removal planned for v1.2.0.
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
- Custom theme JSON loader validates `schemaVersion`, required fields and hex format. Invalid themes are skipped with a
|
- Custom theme JSON loader validates `schemaVersion`, required fields and hex format. Invalid themes
|
||||||
warning; the plugin continues loading with built-ins.
|
are skipped with a warning; the plugin continues loading with built-ins.
|
||||||
|
|
||||||
### Internal
|
### Internal
|
||||||
|
|
||||||
- 51 local unit tests (theme records, registry, JSON round-trip, sanity per built-in theme). Tests are gitignored.
|
- 51 local unit tests (theme records, registry, JSON round-trip, sanity per built-in theme). Tests
|
||||||
|
are gitignored.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -539,18 +593,20 @@ First major UI cycle after v1.0.0. Theme engine, five built-in themes, custom th
|
|||||||
|
|
||||||
Four small polish items from the backlog bundled together:
|
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
|
- **Hide on New Game+ menu**: optional global toggle that hides Hellion Chat (and all other plugin
|
||||||
Settings, DB Viewer, pop-outs) while the NG+ menu is open. Settings → Window → Frame, default off. Skips the entire
|
windows such as Settings, DB Viewer, pop-outs) while the NG+ menu is open. Settings → Window →
|
||||||
`WindowSystem.Draw()` path analogous to the existing LoadingScreens pattern.
|
Frame, default off. Skips the entire `WindowSystem.Draw()` path analogous to the existing
|
||||||
- **Channel selector colouring**: optional tinting of the channel-select button (comment icon) next to the input field
|
LoadingScreens pattern.
|
||||||
in the current channel colour. Settings → Appearance → Chat Colours, default on. Consistent with the existing input
|
- **Channel selector colouring**: optional tinting of the channel-select button (comment icon) next
|
||||||
text colouring; ExtraChat override is carried over.
|
to the input field in the current channel colour. Settings → Appearance → Chat Colours, default
|
||||||
- **(De)buff icon aspect-ratio fix**: `PayloadHandler.InlineIcon` was squashing all hover icons to 32×32. Status icons
|
on. Consistent with the existing input text colouring; ExtraChat override is carried over.
|
||||||
with non-square dimensions (debuffs with an arrow indicator) are now shrunk aspect-preserving. Standalone float-math
|
- **(De)buff icon aspect-ratio fix**: `PayloadHandler.InlineIcon` was squashing all hover icons to
|
||||||
implementation with zero-size guard instead of a cherry-pick from the open ChatTwo PR #157 (which had an int-division
|
32×32. Status icons with non-square dimensions (debuffs with an arrow indicator) are now shrunk
|
||||||
trap).
|
aspect-preserving. Standalone float-math implementation with zero-size guard instead of a
|
||||||
- **HideState logging sweep**: all HideState transitions (Battle/Cutscene/User/Override plus pop-out mirroring) log at
|
cherry-pick from the open ChatTwo PR #157 (which had an int-division trap).
|
||||||
verbose level. Off by default; enable via `/xllog set HellionChat verbose` for bug-report diagnostics.
|
- **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)
|
[Release Notes 1.0.3](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/tag/v1.0.3)
|
||||||
|
|
||||||
@@ -558,14 +614,14 @@ Four small polish items from the backlog bundled together:
|
|||||||
|
|
||||||
## [1.0.1] — 2026-05-04 — Window Position Recovery
|
## [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
|
Fixes an off-screen-window scenario the user could end up in after a monitor disconnect or display
|
||||||
sessions. An automatic one-shot bounds check on the first draw after plugin load snaps the window back into the visible
|
layout change between sessions. An automatic one-shot bounds check on the first draw after plugin
|
||||||
viewport, and a new "Reset Window Position" button in Settings → Window → Frame serves as the manual escape hatch for
|
load snaps the window back into the visible viewport, and a new "Reset Window Position" button in
|
||||||
edge cases.
|
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
|
Bundled housekeeping since v1.0.0: documentation restructured into `docs/`, stale ChatTwo/\* paths
|
||||||
cleaned up, Pidgin parser library bumped from 3.3.0 to 3.5.1, GitHub Actions bumps for `actions/setup-dotnet` (4 → 5)
|
in repo configs cleaned up, Pidgin parser library bumped from 3.3.0 to 3.5.1, GitHub Actions bumps
|
||||||
and `github/codeql-action` (3 → 4).
|
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)
|
[Release Notes 1.0.1](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/tag/v1.0.1)
|
||||||
|
|
||||||
@@ -573,11 +629,11 @@ and `github/codeql-action` (3 → 4).
|
|||||||
|
|
||||||
## [1.0.0] — 2026-05-03 — Standalone Major Release
|
## [1.0.0] — 2026-05-03 — Standalone Major Release
|
||||||
|
|
||||||
First fully independent release. Code namespace, IPC channels and source tree structure consolidated under
|
First fully independent release. Code namespace, IPC channels and source tree structure consolidated
|
||||||
`HellionChat.*`. Plugin refuses to start alongside an active upstream Chat 2 (bilingual conflict message). SQLite native
|
under `HellionChat.*`. Plugin refuses to start alongside an active upstream Chat 2 (bilingual
|
||||||
pinned to 3.50.3 (CVE-2025-6965, CVE-2025-7709). Tab layout default for new installs and users on config version 12 or
|
conflict message). SQLite native pinned to 3.50.3 (CVE-2025-6965, CVE-2025-7709). Tab layout default
|
||||||
older restructured (5 thematic tabs instead of 6+ kitchen-sink). Sweep of critical and major findings from the codebase
|
for new installs and users on config version 12 or older restructured (5 thematic tabs instead of 6+
|
||||||
audit incorporated.
|
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)
|
[Release Notes 1.0.0](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/tag/v1.0.0)
|
||||||
|
|
||||||
@@ -585,9 +641,9 @@ audit incorporated.
|
|||||||
|
|
||||||
## [0.6.1] — 2026-05-03 — Pop-Out Discoverability & /tell Auto-Pop-Out
|
## [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
|
Pop-out button visible in the chat header, one-time hint banner for the pop-out feature. New setting
|
||||||
tabs directly as pop-out". Pop-out input is now active by default. Bug fixes: ghost windows on LRU-drop / logout, dead
|
"Open new /tell tabs directly as pop-out". Pop-out input is now active by default. Bug fixes: ghost
|
||||||
zone below the input bar when the hint banner is active.
|
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)
|
[Release Notes 0.6.1](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/tag/v0.6.1)
|
||||||
|
|
||||||
@@ -595,9 +651,10 @@ zone below the input bar when the hint banner is active.
|
|||||||
|
|
||||||
## [0.6.0] — 2026-05-03 — UX Polish: Pop-Out Input + Colour Presets
|
## [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
|
Two opt-in UX features. Pop-out windows optionally get a compact input bar with a channel-coloured
|
||||||
independent text buffer per pop-out. Seven built-in colour presets (Classic, High Contrast, Pastel, Dark Mode Tuned,
|
icon button and an independent text buffer per pop-out. Seven built-in colour presets (Classic, High
|
||||||
Hellion, Night Blue, Indigo Violet) for one-click apply. Configuration migration v10 → v11.
|
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)
|
[Release Notes 0.6.0](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/tag/v0.6.0)
|
||||||
|
|
||||||
@@ -605,9 +662,9 @@ Hellion, Night Blue, Indigo Violet) for one-click apply. Configuration migration
|
|||||||
|
|
||||||
## [0.5.4] — 2026-05-02 — WrapText Hardening
|
## [0.5.4] — 2026-05-02 — WrapText Hardening
|
||||||
|
|
||||||
`ImGuiUtil.WrapText` rewritten from pointer arithmetic to Span- and index-based control flow. Permanently closes the
|
`ImGuiUtil.WrapText` rewritten from pointer arithmetic to Span- and index-based control flow.
|
||||||
recurring CodeQL critical alert "unvalidated local pointer arithmetic". No user-visible behaviour change — word-wrap
|
Permanently closes the recurring CodeQL critical alert "unvalidated local pointer arithmetic". No
|
||||||
output is byte-identical to 0.5.3.
|
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)
|
[Release Notes 0.5.4](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/tag/v0.5.4)
|
||||||
|
|
||||||
@@ -615,8 +672,8 @@ output is byte-identical to 0.5.3.
|
|||||||
|
|
||||||
## [0.5.3] — 2026-05-02 — Pointer Arithmetic Hardening
|
## [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
|
First attempt at closing the CodeQL critical alert in `ImGuiUtil.WrapText`. Encoded byte buffer
|
||||||
`GetByteCount` before pointer arithmetic.
|
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)
|
[Release Notes 0.5.3](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/tag/v0.5.3)
|
||||||
|
|
||||||
@@ -624,7 +681,8 @@ First attempt at closing the CodeQL critical alert in `ImGuiUtil.WrapText`. Enco
|
|||||||
|
|
||||||
## Earlier Versions
|
## Earlier Versions
|
||||||
|
|
||||||
Releases before 0.5.3 (bootstrap phase 0.1.0 to 0.5.2) are available directly on the Gitea release stream:
|
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)
|
[All Releases](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases)
|
||||||
|
|
||||||
@@ -632,6 +690,7 @@ Releases before 0.5.3 (bootstrap phase 0.1.0 to 0.5.2) are available directly on
|
|||||||
|
|
||||||
## Maintenance Note
|
## Maintenance Note
|
||||||
|
|
||||||
The source of truth for the user-facing changelog is the `changelog:` block in `HellionChat/HellionChat.yaml`.
|
The source of truth for the user-facing changelog is the `changelog:` block in
|
||||||
`repo.json` and the GitHub release body are fed from there. This file (`docs/CHANGELOG.md`) is a curated summary with
|
`HellionChat/HellionChat.yaml`. `repo.json` and the GitHub release body are fed from there. This
|
||||||
links to the release pages and is updated manually on each version bump.
|
file (`docs/CHANGELOG.md`) is a curated summary with links to the release pages and is updated
|
||||||
|
manually on each version bump.
|
||||||
|
|||||||
+47
-37
@@ -1,11 +1,12 @@
|
|||||||
# Contributors — Hellion Chat
|
# Contributors — Hellion Chat
|
||||||
|
|
||||||
Hellion Chat is a one-person project on the code side. But without the people on this page, the bug fixes and UX
|
Hellion Chat is a one-person project on the code side. But without the people on this page, the bug
|
||||||
improvements that have landed since the early versions would not exist. Every entry here has made the plugin concretely
|
fixes and UX improvements that have landed since the early versions would not exist. Every entry
|
||||||
better.
|
here has made the plugin concretely better.
|
||||||
|
|
||||||
Attribution for the upstream Chat 2 authors (Infi and Anna) is intentionally in [`../NOTICE.md`](../NOTICE.md), not
|
Attribution for the upstream Chat 2 authors (Infi and Anna) is intentionally in
|
||||||
here. This file covers contributions to the Hellion Chat side specifically.
|
[`../NOTICE.md`](../NOTICE.md), not here. This file covers contributions to the Hellion Chat side
|
||||||
|
specifically.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -13,13 +14,14 @@ here. This file covers contributions to the Hellion Chat side specifically.
|
|||||||
|
|
||||||
### JonKazama (Florian Wathling) — Maintainer
|
### JonKazama (Florian Wathling) — Maintainer
|
||||||
|
|
||||||
Hellion Chat is my first FFXIV plugin and my first larger C#/Dalamud project. My professional background is web
|
Hellion Chat is my first FFXIV plugin and my first larger C#/Dalamud project. My professional
|
||||||
development (Next.js, React, TypeScript, Prisma). Plugin development in an unfamiliar codebase, ImGui, FFXIV game hooks
|
background is web development (Next.js, React, TypeScript, Prisma). Plugin development in an
|
||||||
and the entire Dalamud stack were new territory.
|
unfamiliar codebase, ImGui, FFXIV game hooks and the entire Dalamud stack were new territory.
|
||||||
|
|
||||||
Privacy-first defaults, per-channel retention, Auto-Tell-Tabs, pop-out input, ChatColours presets, the Hellion theme
|
Privacy-first defaults, per-channel retention, Auto-Tell-Tabs, pop-out input, ChatColours presets,
|
||||||
plus Exo 2 font, and the v1.0.0 standalone cut are the Hellion-specific surface areas I built on top of the Chat 2
|
the Hellion theme plus Exo 2 font, and the v1.0.0 standalone cut are the Hellion-specific surface
|
||||||
foundation. The learning story behind that is in [`LEARNING-JOURNEY.md`](LEARNING-JOURNEY.md).
|
areas I built on top of the Chat 2 foundation. The learning story behind that is in
|
||||||
|
[`LEARNING-JOURNEY.md`](LEARNING-JOURNEY.md).
|
||||||
|
|
||||||
Hellion Chat is part of [Hellion Online Media](https://hellion-media.de).
|
Hellion Chat is part of [Hellion Online Media](https://hellion-media.de).
|
||||||
|
|
||||||
@@ -27,38 +29,45 @@ Hellion Chat is part of [Hellion Online Media](https://hellion-media.de).
|
|||||||
|
|
||||||
## Testers
|
## Testers
|
||||||
|
|
||||||
A quick note: I do not test this plugin alone. The people listed here reported bugs before they hit more users, raised
|
A quick note: I do not test this plugin alone. The people listed here reported bugs before they hit
|
||||||
UX problems I had gone blind to, and brought in feature requests that pushed the plugin in directions I would not have
|
more users, raised UX problems I had gone blind to, and brought in feature requests that pushed the
|
||||||
gone on my own. That is not a given. External testers are worth their time.
|
plugin in directions I would not have gone on my own. That is not a given. External testers are
|
||||||
|
worth their time.
|
||||||
|
|
||||||
### Carl Beleandis (Carla) — Beta Tester
|
### Carl Beleandis (Carla) — Beta Tester
|
||||||
|
|
||||||
Carl has been testing since the bootstrap phase and has shaped both the pop-out mechanics and the theme direction.
|
Carl has been testing since the bootstrap phase and has shaped both the pop-out mechanics and the
|
||||||
Feedback comes direct and without detours, which is exactly what I need when testing.
|
theme direction. Feedback comes direct and without detours, which is exactly what I need when
|
||||||
|
testing.
|
||||||
|
|
||||||
Concrete contributions:
|
Concrete contributions:
|
||||||
|
|
||||||
- **Pop-out discoverability** — pointing out that pop-outs were only reachable via right-click triggered the header
|
- **Pop-out discoverability** — pointing out that pop-outs were only reachable via right-click
|
||||||
button and the one-time hint banner in v0.6.1. I knew the right-click path by heart and had stopped seeing that new
|
triggered the header button and the one-time hint banner in v0.6.1. I knew the right-click path by
|
||||||
users could not find the feature at all.
|
heart and had stopped seeing that new users could not find the feature at all.
|
||||||
- **/tell pop-out mode** — the request to open /tell tabs directly as a pop-out instead of going through the tab sidebar
|
- **/tell pop-out mode** — the request to open /tell tabs directly as a pop-out instead of going
|
||||||
landed in v0.6.1 as an opt-in settings toggle. Bonus: during implementation an old ghost-window bug surfaced (LRU drop
|
through the tab sidebar landed in v0.6.1 as an opt-in settings toggle. Bonus: during
|
||||||
left pop-out windows as ghosts), which got fixed at the same time.
|
implementation an old ghost-window bug surfaced (LRU drop left pop-out windows as ghosts), which
|
||||||
- **Theme variants with brightness gradations** — the request for a green family shifted my thinking from "one theme =
|
got fixed at the same time.
|
||||||
one colour" to "theme families with mood variants". On the [roadmap](ROADMAP.md) for a later cycle.
|
- **Theme variants with brightness gradations** — the request for a green family shifted my thinking
|
||||||
|
from "one theme = one colour" to "theme families with mood variants". On the [roadmap](ROADMAP.md)
|
||||||
|
for a later cycle.
|
||||||
|
|
||||||
### Jin (Jingliu) — Alpha Tester
|
### Jin (Jingliu) — Alpha Tester
|
||||||
|
|
||||||
Jin is the active tester from day one and pushed the pop-out workflow architecture in a different direction.
|
Jin is the active tester from day one and pushed the pop-out workflow architecture in a different
|
||||||
|
direction.
|
||||||
|
|
||||||
Concrete contributions:
|
Concrete contributions:
|
||||||
|
|
||||||
- **Pop-out tab with input bar** — the suggestion to be able to type in a pop-out (instead of just reading) triggered
|
- **Pop-out tab with input bar** — the suggestion to be able to type in a pop-out (instead of just
|
||||||
the v0.6.0 pop-out input bar. That was a larger refactor: the input layer from `ChatLogWindow` had to be opened up so
|
reading) triggered the v0.6.0 pop-out input bar. That was a larger refactor: the input layer from
|
||||||
it could also live in `Popout.cs`, with an independent text buffer and history cursor per pop-out. It dominated the
|
`ChatLogWindow` had to be opened up so it could also live in `Popout.cs`, with an independent text
|
||||||
cycle because the design had to be clean before any code could happen.
|
buffer and history cursor per pop-out. It dominated the cycle because the design had to be clean
|
||||||
- **TempTell persistence** — the request for /tell tabs to survive a relog via a pin toggle is on the
|
before any code could happen.
|
||||||
[roadmap](ROADMAP.md) for a later cycle. It touches the tab system architecturally and needs its own design work.
|
- **TempTell persistence** — the request for /tell tabs to survive a relog via a pin toggle is on
|
||||||
|
the [roadmap](ROADMAP.md) for a later cycle. It touches the tab system architecturally and needs
|
||||||
|
its own design work.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -69,15 +78,16 @@ Hellion-specific UI strings are maintained in `HellionChat/Resources/HellionStri
|
|||||||
- **German (DE):** JonKazama (native speaker, primary project language)
|
- **German (DE):** JonKazama (native speaker, primary project language)
|
||||||
|
|
||||||
Upstream language files (`Language.<lang>.resx`) are not covered here. They are maintained via the
|
Upstream language files (`Language.<lang>.resx`) are not covered here. They are maintained via the
|
||||||
[Chat 2 Crowdin project](https://github.com/Infiziert90/ChatTwo); Crowdin translators are listed in the plugin settings
|
[Chat 2 Crowdin project](https://github.com/Infiziert90/ChatTwo); Crowdin translators are listed in
|
||||||
under **Info → "Chat 2 community translators"**.
|
the plugin settings under **Info → "Chat 2 community translators"**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## How to Contribute
|
## How to Contribute
|
||||||
|
|
||||||
Bug reports, feature requests and feedback are welcome — the best place to reach me is the Hellion Forge Discord:
|
Bug reports, feature requests and feedback are welcome — the best place to reach me is the Hellion
|
||||||
[discord.gg/X9V7Kcv5gR](https://discord.gg/X9V7Kcv5gR). Join and ping me in the Hellion Chat channel.
|
Forge Discord: [discord.gg/X9V7Kcv5gR](https://discord.gg/X9V7Kcv5gR). Join and ping me in the
|
||||||
|
Hellion Chat channel.
|
||||||
|
|
||||||
For pull requests and contribution guidelines see [`../CONTRIBUTING.md`](../CONTRIBUTING.md), Code of Conduct in
|
For pull requests and contribution guidelines see [`../CONTRIBUTING.md`](../CONTRIBUTING.md), Code
|
||||||
[`../CODE_OF_CONDUCT.md`](../CODE_OF_CONDUCT.md).
|
of Conduct in [`../CODE_OF_CONDUCT.md`](../CODE_OF_CONDUCT.md).
|
||||||
|
|||||||
+47
-38
@@ -1,28 +1,31 @@
|
|||||||
# Hellion Chat IPC Integration Guide
|
# Hellion Chat IPC Integration Guide
|
||||||
|
|
||||||
This document describes the inter-plugin-communication (IPC) channels that Hellion Chat exposes to other Dalamud
|
This document describes the inter-plugin-communication (IPC) channels that Hellion Chat exposes to
|
||||||
plugins. Two integration surfaces are covered: the **Context Menu IPC** for adding custom items to Hellion Chat's
|
other Dalamud plugins. Two integration surfaces are covered: the **Context Menu IPC** for adding
|
||||||
right-click menus, and the **Typing State IPC** for reacting to the user's input-box activity.
|
custom items to Hellion Chat's right-click menus, and the **Typing State IPC** for reacting to the
|
||||||
|
user's input-box activity.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Compatibility with Chat 2
|
## Compatibility with Chat 2
|
||||||
|
|
||||||
Hellion Chat is a standalone fork of [Chat 2](https://github.com/Infiziert90/ChatTwo) (EUPL-1.2). The IPC surface is one
|
Hellion Chat is a standalone fork of [Chat 2](https://github.com/Infiziert90/ChatTwo) (EUPL-1.2).
|
||||||
of the parts the fork inherits directly: the same call shapes, the same tuple payloads, the same call semantics, the
|
The IPC surface is one of the parts the fork inherits directly: the same call shapes, the same tuple
|
||||||
same lifecycle. We did not redesign the API, we re-published it under our own plugin name.
|
payloads, the same call semantics, the same lifecycle. We did not redesign the API, we re-published
|
||||||
|
it under our own plugin name.
|
||||||
|
|
||||||
Concretely, this means:
|
Concretely, this means:
|
||||||
|
|
||||||
- **Tuple shapes are identical.** A subscriber that worked against Chat 2's `ChatTwo.Invoke` works against Hellion
|
- **Tuple shapes are identical.** A subscriber that worked against Chat 2's `ChatTwo.Invoke` works
|
||||||
Chat's `HellionChat.Invoke` without any code change beyond the channel string.
|
against Hellion Chat's `HellionChat.Invoke` without any code change beyond the channel string.
|
||||||
- **Lifecycle is identical.** The `Available` ping fires when the plugin becomes ready, your subscriber re-registers,
|
- **Lifecycle is identical.** The `Available` ping fires when the plugin becomes ready, your
|
||||||
and the registration ID is returned by the same `Register` call as before.
|
subscriber re-registers, and the registration ID is returned by the same `Register` call as
|
||||||
- **Channel-name prefix changed in v1.0.0.** Every `ChatTwo.*` channel name is now `HellionChat.*`. Existing third-party
|
before.
|
||||||
integrations need a one-line rename per channel string and nothing else.
|
- **Channel-name prefix changed in v1.0.0.** Every `ChatTwo.*` channel name is now `HellionChat.*`.
|
||||||
|
Existing third-party integrations need a one-line rename per channel string and nothing else.
|
||||||
|
|
||||||
If your plugin already supports Chat 2 and you want to add Hellion Chat support, the cleanest path is to bind both
|
If your plugin already supports Chat 2 and you want to add Hellion Chat support, the cleanest path
|
||||||
prefixes and treat whichever one becomes available first as the active host.
|
is to bind both prefixes and treat whichever one becomes available first as the active host.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -41,18 +44,20 @@ prefixes and treat whichever one becomes available first as the active host.
|
|||||||
|
|
||||||
## Context Menu IPC
|
## Context Menu IPC
|
||||||
|
|
||||||
Use this surface to draw your own selectables inside Hellion Chat's right-click context menus. All registrations are
|
Use this surface to draw your own selectables inside Hellion Chat's right-click context menus. All
|
||||||
called inside an ImGui `BeginMenu`, so anything you draw appears as a regular menu entry.
|
registrations are called inside an ImGui `BeginMenu`, so anything you draw appears as a regular menu
|
||||||
|
entry.
|
||||||
|
|
||||||
### Lifecycle
|
### Lifecycle
|
||||||
|
|
||||||
1. Subscribe to `HellionChat.Available`. The host fires this once when it loads or reloads, so your plugin can
|
1. Subscribe to `HellionChat.Available`. The host fires this once when it loads or reloads, so your
|
||||||
re-register without polling.
|
plugin can re-register without polling.
|
||||||
2. Call `HellionChat.Register` to obtain a registration ID. Save it. You need it to filter `Invoke` callbacks that
|
2. Call `HellionChat.Register` to obtain a registration ID. Save it. You need it to filter `Invoke`
|
||||||
target your registration and to call `Unregister` later.
|
callbacks that target your registration and to call `Unregister` later.
|
||||||
3. Subscribe to `HellionChat.Invoke` and draw your menu items inside the handler when the `id` matches your saved
|
3. Subscribe to `HellionChat.Invoke` and draw your menu items inside the handler when the `id`
|
||||||
registration ID.
|
matches your saved registration ID.
|
||||||
4. On plugin disable or unload, call `HellionChat.Unregister` with your saved ID and unsubscribe from `Invoke`.
|
4. On plugin disable or unload, call `HellionChat.Unregister` with your saved ID and unsubscribe
|
||||||
|
from `Invoke`.
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
@@ -137,12 +142,14 @@ If your plugin already integrates with `ChatTwo.*`, the rename is the only requi
|
|||||||
|
|
||||||
## Typing State IPC
|
## Typing State IPC
|
||||||
|
|
||||||
Use this surface when you need to know whether the player is currently interacting with Hellion Chat's input box. Useful
|
Use this surface when you need to know whether the player is currently interacting with Hellion
|
||||||
for typing indicators, keyboard-shortcut suppression, or HUD elements that hide while the user is typing.
|
Chat's input box. Useful for typing indicators, keyboard-shortcut suppression, or HUD elements that
|
||||||
|
hide while the user is typing.
|
||||||
|
|
||||||
### Tuple Payload
|
### Tuple Payload
|
||||||
|
|
||||||
Both `HellionChat.GetChatInputState` (poll) and `HellionChat.ChatInputStateChanged` (event) return the same tuple:
|
Both `HellionChat.GetChatInputState` (poll) and `HellionChat.ChatInputStateChanged` (event) return
|
||||||
|
the same tuple:
|
||||||
|
|
||||||
```cs
|
```cs
|
||||||
(bool InputVisible, bool InputFocused, bool HasText, bool IsTyping, int TextLength, ChatType ChannelType)
|
(bool InputVisible, bool InputFocused, bool HasText, bool IsTyping, int TextLength, ChatType ChannelType)
|
||||||
@@ -159,17 +166,19 @@ Both `HellionChat.GetChatInputState` (poll) and `HellionChat.ChatInputStateChang
|
|||||||
|
|
||||||
### Where `ChannelType` comes from
|
### Where `ChannelType` comes from
|
||||||
|
|
||||||
`ChannelType` is the `HellionChat.Code.ChatType` enum value representing the target channel for the current submission.
|
`ChannelType` is the `HellionChat.Code.ChatType` enum value representing the target channel for the
|
||||||
It is sourced from the active tab's `UsedChannel` (`HellionChat/Configuration.cs`), which the plugin keeps in sync by
|
current submission. It is sourced from the active tab's `UsedChannel`
|
||||||
hooking the in-game shell (`HellionChat/GameFunctions/Chat.cs`) and by resolving temporary overrides inside the chat UI
|
(`HellionChat/Configuration.cs`), which the plugin keeps in sync by hooking the in-game shell
|
||||||
(`HellionChat/Ui/ChatLogWindow.cs:597`). `InputChannel` values are converted into the exported `ChatType` via
|
(`HellionChat/GameFunctions/Chat.cs`) and by resolving temporary overrides inside the chat UI
|
||||||
`HellionChat/Code/InputChannelExt.ToChatType`.
|
(`HellionChat/Ui/ChatLogWindow.cs:597`). `InputChannel` values are converted into the exported
|
||||||
|
`ChatType` via `HellionChat/Code/InputChannelExt.ToChatType`.
|
||||||
|
|
||||||
### Behavior
|
### Behavior
|
||||||
|
|
||||||
- `ChatInputStateChanged` fires once immediately after subscribe so you do not need a separate `GetChatInputState` poll
|
- `ChatInputStateChanged` fires once immediately after subscribe so you do not need a separate
|
||||||
for the initial snapshot.
|
`GetChatInputState` poll for the initial snapshot.
|
||||||
- After that it fires only when one or more fields actually change, so it is safe to subscribe without rate-limiting.
|
- After that it fires only when one or more fields actually change, so it is safe to subscribe
|
||||||
|
without rate-limiting.
|
||||||
- `GetChatInputState` is available for one-shot polls, e.g. on plugin enable.
|
- `GetChatInputState` is available for one-shot polls, e.g. on plugin enable.
|
||||||
|
|
||||||
### Example 2
|
### Example 2
|
||||||
@@ -223,7 +232,7 @@ Same shape as the Context Menu surface — only the channel-name prefix needs th
|
|||||||
|
|
||||||
## License & Attribution
|
## License & Attribution
|
||||||
|
|
||||||
This guide and the IPC surface it documents derive directly from the Chat 2 codebase. Hellion Chat is licensed under
|
This guide and the IPC surface it documents derive directly from the Chat 2 codebase. Hellion Chat
|
||||||
[EUPL-1.2](LICENSE), and credit for the original IPC design and implementation goes to
|
is licensed under [EUPL-1.2](LICENSE), and credit for the original IPC design and implementation
|
||||||
**[Infiziert90 (Infi)](https://github.com/Infiziert90)** and **[Anna](https://github.com/anna-is-cute)**,— see
|
goes to **[Infiziert90 (Infi)](https://github.com/Infiziert90)** and
|
||||||
[`NOTICE.md`](NOTICE.md) for full attribution.
|
**[Anna](https://github.com/anna-is-cute)**,— see [`NOTICE.md`](NOTICE.md) for full attribution.
|
||||||
|
|||||||
+189
-159
@@ -2,40 +2,43 @@
|
|||||||
|
|
||||||
## Background
|
## Background
|
||||||
|
|
||||||
I am self-taught. Hellion Chat is my first FFXIV plugin and my first larger C# project. My professional background is
|
I am self-taught. Hellion Chat is my first FFXIV plugin and my first larger C# project. My
|
||||||
web development (Next.js, React, TypeScript, Prisma, MySQL) — browser world with a JavaScript toolchain. I knew C# only
|
professional background is web development (Next.js, React, TypeScript, Prisma, MySQL) — browser
|
||||||
superficially before this project, ImGui not at all, and Dalamud only as an end user through other plugins.
|
world with a JavaScript toolchain. I knew C# only superficially before this project, ImGui not at
|
||||||
|
all, and Dalamud only as an end user through other plugins.
|
||||||
|
|
||||||
When I get stuck somewhere, I use AI tools like Claude Code as a pair assistant. What that looks like exactly and which
|
When I get stuck somewhere, I use AI tools like Claude Code as a pair assistant. What that looks
|
||||||
classification I use is documented transparently in [`AI_DISCLOSURE.md`](AI_DISCLOSURE.md).
|
like exactly and which classification I use is documented transparently in
|
||||||
|
[`AI_DISCLOSURE.md`](AI_DISCLOSURE.md).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Why a chat plugin at all?
|
## Why a chat plugin at all?
|
||||||
|
|
||||||
Hellion Chat is not meant to replace Chat 2. Chat 2 delivers a complete chat experience with full history, filters,
|
Hellion Chat is not meant to replace Chat 2. Chat 2 delivers a complete chat experience with full
|
||||||
search and replay. For most users that is exactly the right thing.
|
history, filters, search and replay. For most users that is exactly the right thing.
|
||||||
|
|
||||||
### Two million messages in two years
|
### Two million messages in two years
|
||||||
|
|
||||||
My desire for a tighter default was honestly personal at first. After two years with Chat 2 my database had grown to
|
My desire for a tighter default was honestly personal at first. After two years with Chat 2 my
|
||||||
over two million messages, the majority of them /say, /shout and /yell from complete strangers in Limsa. That is exactly
|
database had grown to over two million messages, the majority of them /say, /shout and /yell from
|
||||||
what makes Chat 2's full history useful, and most users are happy to keep it. My own preference wanted a smaller
|
complete strangers in Limsa. That is exactly what makes Chat 2's full history useful, and most users
|
||||||
default. So I built this fork.
|
are happy to keep it. My own preference wanted a smaller default. So I built this fork.
|
||||||
|
|
||||||
### Greeter in several clubs
|
### Greeter in several clubs
|
||||||
|
|
||||||
There was a second use case: I am active as a greeter in several FFXIV clubs. The vanilla chat interface is not enough
|
There was a second use case: I am active as a greeter in several FFXIV clubs. The vanilla chat
|
||||||
for greeter work. Parallel /tell conversations write into a single tab at the same time, and I constantly lose track of
|
interface is not enough for greeter work. Parallel /tell conversations write into a single tab at
|
||||||
who wrote what. Auto-Tell-Tabs (one of the early Hellion Chat features) came directly from this workflow: one tab per
|
the same time, and I constantly lose track of who wrote what. Auto-Tell-Tabs (one of the early
|
||||||
conversation partner, automatically spawned, with a manual greeted status. The privacy hygiene benefit was a nice bonus,
|
Hellion Chat features) came directly from this workflow: one tab per conversation partner,
|
||||||
|
automatically spawned, with a manual greeted status. The privacy hygiene benefit was a nice bonus,
|
||||||
not the trigger.
|
not the trigger.
|
||||||
|
|
||||||
### Hellion Online Media
|
### Hellion Online Media
|
||||||
|
|
||||||
The privacy defaults also reflect a position from my main work. Hellion Online Media is my sole proprietorship, and data
|
The privacy defaults also reflect a position from my main work. Hellion Online Media is my sole
|
||||||
protection toward clients is not a marketing slogan there but operationally relevant. This fork is the plugin form of
|
proprietorship, and data protection toward clients is not a marketing slogan there but operationally
|
||||||
the same stance.
|
relevant. This fork is the plugin form of the same stance.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -45,90 +48,99 @@ Three reasons, in descending order of importance.
|
|||||||
|
|
||||||
### Defaults are not negotiable, including mine
|
### Defaults are not negotiable, including mine
|
||||||
|
|
||||||
Privacy-first as a default is a minority position. Chat 2 rightly serves the broad majority with full history as the
|
Privacy-first as a default is a minority position. Chat 2 rightly serves the broad majority with
|
||||||
default. Changing those defaults upstream would have been wrong. I would have flipped the standard for a large user base
|
full history as the default. Changing those defaults upstream would have been wrong. I would have
|
||||||
that wanted it as it was. A clean separation through a dedicated plugin slot was the more respectful path.
|
flipped the standard for a large user base that wanted it as it was. A clean separation through a
|
||||||
|
dedicated plugin slot was the more respectful path.
|
||||||
|
|
||||||
### The web interface had to go
|
### The web interface had to go
|
||||||
|
|
||||||
It is a central Chat 2 feature for remote access from a second device. A PR removing it has no chance in a
|
It is a central Chat 2 feature for remote access from a second device. A PR removing it has no
|
||||||
well-maintained upstream project, and that is correct. But exactly that web interface conflicts with the privacy-first
|
chance in a well-maintained upstream project, and that is correct. But exactly that web interface
|
||||||
premise of this fork: a chat plugin that starts a local HTTP server is too large an attack surface for my threat model.
|
conflicts with the privacy-first premise of this fork: a chat plugin that starts a local HTTP server
|
||||||
So out it went.
|
is too large an attack surface for my threat model. So out it went.
|
||||||
|
|
||||||
### Velocity
|
### Velocity
|
||||||
|
|
||||||
A solo-maintainer project with a small tester pool can iterate faster than an established plugin with a large user base.
|
A solo-maintainer project with a small tester pool can iterate faster than an established plugin
|
||||||
That is not a criticism of upstream but a different optimization. I do not need roadmap alignment, reviewer
|
with a large user base. That is not a criticism of upstream but a different optimization. I do not
|
||||||
availability, or to spread audit consequences like the web interface removal across multiple releases.
|
need roadmap alignment, reviewer availability, or to spread audit consequences like the web
|
||||||
|
interface removal across multiple releases.
|
||||||
|
|
||||||
EUPL-1.2 explicitly allows all of this with clear attribution. The code is open under the same license as Chat 2. Infi,
|
EUPL-1.2 explicitly allows all of this with clear attribution. The code is open under the same
|
||||||
Anna, or anyone else can look in, take ideas, ask questions, or simply ignore the fork. All three are fine with me.
|
license as Chat 2. Infi, Anna, or anyone else can look in, take ideas, ask questions, or simply
|
||||||
|
ignore the fork. All three are fine with me.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## How I release this fast
|
## How I release this fast
|
||||||
|
|
||||||
Anyone looking at the repo sees a lot of releases and a high commit count in a short time. Both tend to read as red
|
Anyone looking at the repo sees a lot of releases and a high commit count in a short time. Both tend
|
||||||
flags from the outside: AI slop, salami tactics, code spam. In Hellion Chat both are deliberate decisions, and I would
|
to read as red flags from the outside: AI slop, salami tactics, code spam. In Hellion Chat both are
|
||||||
rather explain them once than justify them later.
|
deliberate decisions, and I would rather explain them once than justify them later.
|
||||||
|
|
||||||
### Groundwork, long before the fork existed
|
### Groundwork, long before the fork existed
|
||||||
|
|
||||||
Before I typed the first line into `HellionChat/`, I spent weeks as a reader. Using Chat 2 in-game and playing around
|
Before I typed the first line into `HellionChat/`, I spent weeks as a reader. Using Chat 2 in-game
|
||||||
with it. Going through issues in the upstream tracker, especially the closed ones, because that is where you see how
|
and playing around with it. Going through issues in the upstream tracker, especially the closed
|
||||||
Infi and Anna narrow down bugs. Reading commits, including older ones, to understand _why_ an architecture decision was
|
ones, because that is where you see how Infi and Anna narrow down bugs. Reading commits, including
|
||||||
made, not just _that_ it was made. If I know today where things live in the codebase, it is not because I navigate
|
older ones, to understand _why_ an architecture decision was made, not just _that_ it was made. If I
|
||||||
codebases particularly fast but because I read the code beforehand.
|
know today where things live in the codebase, it is not because I navigate codebases particularly
|
||||||
|
fast but because I read the code beforehand.
|
||||||
|
|
||||||
That sounds obvious. It is not. The usual order for solo forks is fork first, understand later. I did it the other way
|
That sounds obvious. It is not. The usual order for solo forks is fork first, understand later. I
|
||||||
around.
|
did it the other way around.
|
||||||
|
|
||||||
One thing I noticed reading the codebase closely: some patterns felt familiar in ways I had not expected, structural
|
One thing I noticed reading the codebase closely: some patterns felt familiar in ways I had not
|
||||||
choices and comment styles that show up across a lot of modern plugin and tooling code regardless of how it was written.
|
expected, structural choices and comment styles that show up across a lot of modern plugin and
|
||||||
Nothing worth reading into. Coding workflows have changed a lot in the last few years across the board, and the traces
|
tooling code regardless of how it was written. Nothing worth reading into. Coding workflows have
|
||||||
of that show up everywhere. It did make me less self-conscious about my own workflow.
|
changed a lot in the last few years across the board, and the traces of that show up everywhere. It
|
||||||
|
did make me less self-conscious about my own workflow.
|
||||||
|
|
||||||
### Infi and Anna's codebase
|
### Infi and Anna's codebase
|
||||||
|
|
||||||
Hellion Chat builds on a foundation that is already flat. Chat 2 is cleanly structured, naming conventions are
|
Hellion Chat builds on a foundation that is already flat. Chat 2 is cleanly structured, naming
|
||||||
consistent, and the separation between layers (storage, UI, game hooks, IPC) is clearly drawn. That is not a given in
|
conventions are consistent, and the separation between layers (storage, UI, game hooks, IPC) is
|
||||||
open-source plugin land, and it is the main reason Hellion-specific features often slot in "almost natively". I do not
|
clearly drawn. That is not a given in open-source plugin land, and it is the main reason
|
||||||
have to untangle spaghetti before I can put something of my own next to it.
|
Hellion-specific features often slot in "almost natively". I do not have to untangle spaghetti
|
||||||
|
before I can put something of my own next to it.
|
||||||
|
|
||||||
Side note: even during the first codebase walkthrough with Claude, the comment came up several times that the
|
Side note: even during the first codebase walkthrough with Claude, the comment came up several times
|
||||||
architecture is unusually tidy and has several extension points prepared. That carries weight because it comes from
|
that the architecture is unusually tidy and has several extension points prepared. That carries
|
||||||
outside, but the actual credit goes to Infi and Anna, not Claude.
|
weight because it comes from outside, but the actual credit goes to Infi and Anna, not Claude.
|
||||||
|
|
||||||
### Atomic work, small commits
|
### Atomic work, small commits
|
||||||
|
|
||||||
One commit, one logical change. If I fix a bug, rename a variable and add a comment at the same time, that is three
|
One commit, one logical change. If I fix a bug, rename a variable and add a comment at the same
|
||||||
commits, not one. Sounds like micro-management, it is not. If a bug surfaces in six months and I need `git bisect`, I
|
time, that is three commits, not one. Sounds like micro-management, it is not. If a bug surfaces in
|
||||||
find the broken change in two minutes instead of two hours. With a 4000-line mega-commit I get to guess which of the
|
six months and I need `git bisect`, I find the broken change in two minutes instead of two hours.
|
||||||
hundred changes is the broken one.
|
With a 4000-line mega-commit I get to guess which of the hundred changes is the broken one.
|
||||||
|
|
||||||
I kept this style deliberately also because Infi works the same way upstream. Sometimes a six-line commit, sometimes
|
I kept this style deliberately also because Infi works the same way upstream. Sometimes a six-line
|
||||||
just a typo fix. That is not a weakness, it is a decision for readable Git history. Keeping the style in the fork is a
|
commit, sometimes just a typo fix. That is not a weakness, it is a decision for readable Git
|
||||||
respect move: anyone comparing both repos should have the same reading rhythm.
|
history. Keeping the style in the fork is a respect move: anyone comparing both repos should have
|
||||||
|
the same reading rhythm.
|
||||||
|
|
||||||
Personal bonus: small commits force me to think through and name each step individually. If I cannot explain what a
|
Personal bonus: small commits force me to think through and name each step individually. If I cannot
|
||||||
commit does in two sentences, the change is probably not clear enough yet. At beginner level that is a built-in sanity
|
explain what a commit does in two sentences, the change is probably not clear enough yet. At
|
||||||
check I would not have with a big-bang commit.
|
beginner level that is a built-in sanity check I would not have with a big-bang commit.
|
||||||
|
|
||||||
### AI as an accelerator, honestly
|
### AI as an accelerator, honestly
|
||||||
|
|
||||||
Yes, AI helps with velocity, and not a little. Without CodeRabbit I would not have found critical bugs like
|
Yes, AI helps with velocity, and not a little. Without CodeRabbit I would not have found critical
|
||||||
`Equals/GetHashCode` anti-patterns, hook subscription leaks and TOCTOU races. I am simply too inexperienced for that
|
bugs like `Equals/GetHashCode` anti-patterns, hook subscription leaks and TOCTOU races. I am simply
|
||||||
class of findings, and I write that exactly as it is.
|
too inexperienced for that class of findings, and I write that exactly as it is.
|
||||||
|
|
||||||
What I do not do: blindly take code because a tool marked it as a fix. On several CodeRabbit findings, the original
|
What I do not do: blindly take code because a tool marked it as a fix. On several CodeRabbit
|
||||||
commits from Infi or Anna even included a Stack Overflow link explaining why a particular spot looks the way it does. I
|
findings, the original commits from Infi or Anna even included a Stack Overflow link explaining why
|
||||||
read those before touching anything. Understand first, then change, then commit. That is the difference between "AI
|
a particular spot looks the way it does. I read those before touching anything. Understand first,
|
||||||
gives me code, I push" and "AI shows me where it breaks, I decide".
|
then change, then commit. That is the difference between "AI gives me code, I push" and "AI shows me
|
||||||
|
where it breaks, I decide".
|
||||||
|
|
||||||
Classification and concrete examples of AI usage are in [`AI_DISCLOSURE.md`](AI_DISCLOSURE.md). This section was only
|
Classification and concrete examples of AI usage are in [`AI_DISCLOSURE.md`](AI_DISCLOSURE.md). This
|
||||||
about the velocity aspect: research plus a clean codebase plus atomic commits plus AI-assisted review sparring are the
|
section was only about the velocity aspect: research plus a clean codebase plus atomic commits plus
|
||||||
four factors together. No single one explains the pace on its own.
|
AI-assisted review sparring are the four factors together. No single one explains the pace on its
|
||||||
|
own.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -136,48 +148,53 @@ four factors together. No single one explains the pace on its own.
|
|||||||
|
|
||||||
### Type system? Less of a shock than expected
|
### Type system? Less of a shock than expected
|
||||||
|
|
||||||
C# after TypeScript was more comfortable than expected. Properties instead of getters/setters are clean, nullable
|
C# after TypeScript was more comfortable than expected. Properties instead of getters/setters are
|
||||||
reference types feel like `strict: true` in TypeScript. What was unfamiliar was having to think explicitly about value
|
clean, nullable reference types feel like `strict: true` in TypeScript. What was unfamiliar was
|
||||||
types versus reference types (`struct` vs. `class` with real behavioural consequences), and generics with constraints
|
having to think explicitly about value types versus reference types (`struct` vs. `class` with real
|
||||||
are syntactically different enough that I stumble on them while reading. `async`/`await` is semantically similar, but
|
behavioural consequences), and generics with constraints are syntactically different enough that I
|
||||||
threading models are more explicit in C#: `Task.Run`, `ConfigureAwait`, synchronization contexts. That cost me several
|
stumble on them while reading. `async`/`await` is semantically similar, but threading models are
|
||||||
bugs before I understood when the main thread (in plugin land: the framework tick) is actually critical.
|
more explicit in C#: `Task.Run`, `ConfigureAwait`, synchronization contexts. That cost me several
|
||||||
|
bugs before I understood when the main thread (in plugin land: the framework tick) is actually
|
||||||
|
critical.
|
||||||
|
|
||||||
### Build toolchain: similar, but different
|
### Build toolchain: similar, but different
|
||||||
|
|
||||||
`dotnet` CLI, csproj XML, NuGet are functionally not far from npm and tsconfig. But the XML format of csproj is a
|
`dotnet` CLI, csproj XML, NuGet are functionally not far from npm and tsconfig. But the XML format
|
||||||
different language than JSON configs. The lock file (`packages.lock.json`) had to be actively enabled
|
of csproj is a different language than JSON configs. The lock file (`packages.lock.json`) had to be
|
||||||
(`RestorePackagesWithLockFile=true`); that is not the default. In the web stack, lock-file-first is standard, in the
|
actively enabled (`RestorePackagesWithLockFile=true`); that is not the default. In the web stack,
|
||||||
.NET stack apparently not. That was a real surprise.
|
lock-file-first is standard, in the .NET stack apparently not. That was a real surprise.
|
||||||
|
|
||||||
### ImGui is a different world
|
### ImGui is a different world
|
||||||
|
|
||||||
Immediate-mode rendering has nothing in common with React component trees. There is no virtual DOM, no reconciliation,
|
Immediate-mode rendering has nothing in common with React component trees. There is no virtual DOM,
|
||||||
no "component state". Every frame the code redraws the UI from scratch, and state lives either in local variables I
|
no reconciliation, no "component state". Every frame the code redraws the UI from scratch, and state
|
||||||
manage myself or in ImGui's own ID stack logic.
|
lives either in local variables I manage myself or in ImGui's own ID stack logic.
|
||||||
|
|
||||||
What is two lines of `useState` in React is a member field plus manual ID stamps on widgets in ImGui, otherwise two
|
What is two lines of `useState` in React is a member field plus manual ID stamps on widgets in
|
||||||
selectables in the same loop collide because they fall back to the same ID. The ID stack collision in `SearchSelector`
|
ImGui, otherwise two selectables in the same loop collide because they fall back to the same ID. The
|
||||||
(fixed in v1.0.0) was exactly that symptom: all selectables fell back to the same ambiguous ID until I mixed the row
|
ID stack collision in `SearchSelector` (fixed in v1.0.0) was exactly that symptom: all selectables
|
||||||
index into the PushID. Classic "why is the wrong entry getting clicked" bug that you only find once you understand how
|
fell back to the same ambiguous ID until I mixed the row index into the PushID. Classic "why is the
|
||||||
ImGui handles IDs internally.
|
wrong entry getting clicked" bug that you only find once you understand how ImGui handles IDs
|
||||||
|
internally.
|
||||||
|
|
||||||
### Dalamud specifics
|
### Dalamud specifics
|
||||||
|
|
||||||
Plugin lifecycle, IPC subscriber pattern, hook system for game functions, game object threading. Much of that was only
|
Plugin lifecycle, IPC subscriber pattern, hook system for game functions, game object threading.
|
||||||
understandable through reading the upstream codebase and through [dalamud.dev](https://dalamud.dev). Search results for
|
Much of that was only understandable through reading the upstream codebase and through
|
||||||
"Dalamud" often turn up outdated API examples from old versions. dalamud.dev is the reliable source. If someone is just
|
[dalamud.dev](https://dalamud.dev). Search results for "Dalamud" often turn up outdated API examples
|
||||||
starting out: go there, not to Stack Overflow.
|
from old versions. dalamud.dev is the reliable source. If someone is just starting out: go there,
|
||||||
|
not to Stack Overflow.
|
||||||
|
|
||||||
### The day DalamudPackager cost me a day
|
### The day DalamudPackager cost me a day
|
||||||
|
|
||||||
Dalamud SDK 15 ships its own default packager that writes icons and image URLs into the manifest. I had carried over a
|
Dalamud SDK 15 ships its own default packager that writes icons and image URLs into the manifest. I
|
||||||
`DalamudPackager.targets` file from the upstream repo with a `HandleImages` override, and it was overriding the SDK
|
had carried over a `DalamudPackager.targets` file from the upstream repo with a `HandleImages`
|
||||||
default. Result: the manifest had no `IconUrl` anymore, and the plugin appeared in the plugin list without an icon.
|
override, and it was overriding the SDK default. Result: the manifest had no `IconUrl` anymore, and
|
||||||
|
the plugin appeared in the plugin list without an icon.
|
||||||
|
|
||||||
The symptom was easy to spot, the cause cost a day. I had treated the override file as mandatory when it was not.
|
The symptom was easy to spot, the cause cost a day. I had treated the override file as mandatory
|
||||||
Removed in v0.5.2, SDK default running since then. Lesson: start with defaults, add overrides only when the default
|
when it was not. Removed in v0.5.2, SDK default running since then. Lesson: start with defaults, add
|
||||||
demonstrably does not fit.
|
overrides only when the default demonstrably does not fit.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -185,73 +202,82 @@ demonstrably does not fit.
|
|||||||
|
|
||||||
### Refactoring in an unfamiliar codebase
|
### Refactoring in an unfamiliar codebase
|
||||||
|
|
||||||
The standalone cut in v1.0.0 migrated the entire `ChatTwo.*` identity to `HellionChat.*`. That sounds like find and
|
The standalone cut in v1.0.0 migrated the entire `ChatTwo.*` identity to `HellionChat.*`. That
|
||||||
replace. It was not.
|
sounds like find and replace. It was not.
|
||||||
|
|
||||||
In concrete terms: code namespace across all 80 source files plus 100 using directives plus two FQN aliases plus the
|
In concrete terms: code namespace across all 80 source files plus 100 using directives plus two FQN
|
||||||
resource designer strings. Six IPC channels renamed (breaking change for third-party plugins, no known integrations).
|
aliases plus the resource designer strings. Six IPC channels renamed (breaking change for
|
||||||
Repo folder structure (`ChatTwo/` -> `HellionChat/`) including csproj, sln, all GitHub workflows and dependabot.yml.
|
third-party plugins, no known integrations). Repo folder structure (`ChatTwo/` -> `HellionChat/`)
|
||||||
Public-facing branding in README, repo.json and yaml reformulated to standalone framing.
|
including csproj, sln, all GitHub workflows and dependabot.yml. Public-facing branding in README,
|
||||||
|
repo.json and yaml reformulated to standalone framing.
|
||||||
|
|
||||||
It was not a solo find-and-replace because Unicode string paths in workflow YAMLs need different quoting than C#
|
It was not a solo find-and-replace because Unicode string paths in workflow YAMLs need different
|
||||||
strings. Because resource designer files have generated content that not every toolchain tracks. And because the
|
quoting than C# strings. Because resource designer files have generated content that not every
|
||||||
`ChatTwo.*` IPC channel names are strings in `GetIpcSubscriber` calls: no symbol, no compile error if you miss one. That
|
toolchain tracks. And because the `ChatTwo.*` IPC channel names are strings in `GetIpcSubscriber`
|
||||||
is when you find out what stays quiet.
|
calls: no symbol, no compile error if you miss one. That is when you find out what stays quiet.
|
||||||
|
|
||||||
### Security is no longer abstract
|
### Security is no longer abstract
|
||||||
|
|
||||||
Before this project, supply chain security was academic for me. Three concrete lessons changed that.
|
Before this project, supply chain security was academic for me. Three concrete lessons changed that.
|
||||||
|
|
||||||
**SQLite native binary.** I had to pin to 3.50.3 (`SQLitePCLRaw.lib.e_sqlite3` override) because `Microsoft.Data.Sqlite`
|
**SQLite native binary.** I had to pin to 3.50.3 (`SQLitePCLRaw.lib.e_sqlite3` override) because
|
||||||
was pulling in a transitively referenced library at a version containing CVE-2025-6965 (memory corruption via aggregate
|
`Microsoft.Data.Sqlite` was pulling in a transitively referenced library at a version containing
|
||||||
term overflow) and CVE-2025-7709. The managed wrapper was new; the native library was not. Lesson: transitive
|
CVE-2025-6965 (memory corruption via aggregate term overflow) and CVE-2025-7709. The managed wrapper
|
||||||
dependencies do not audit themselves, you have to look.
|
was new; the native library was not. Lesson: transitive dependencies do not audit themselves, you
|
||||||
|
have to look.
|
||||||
|
|
||||||
**Lock file drift.** `packages.lock.json` honoured via `RestorePackagesWithLockFile=true` in the csproj prevents
|
**Lock file drift.** `packages.lock.json` honoured via `RestorePackagesWithLockFile=true` in the
|
||||||
transitive versions from silently drifting between my machine and CI. I only understood why this is not the default
|
csproj prevents transitive versions from silently drifting between my machine and CI. I only
|
||||||
after a build output mismatch between local and GitHub Actions.
|
understood why this is not the default after a build output mismatch between local and GitHub
|
||||||
|
Actions.
|
||||||
|
|
||||||
**WrapText and the CodeQL alert that cost three releases.** CodeQL flagged a critical alert in `ImGuiUtil.WrapText` for
|
**WrapText and the CodeQL alert that cost three releases.** CodeQL flagged a critical alert in
|
||||||
unvalidated local pointer arithmetic. v0.5.2 validated an edge case. Alert came back. v0.5.3 checked buffer length via
|
`ImGuiUtil.WrapText` for unvalidated local pointer arithmetic. v0.5.2 validated an edge case. Alert
|
||||||
`GetByteCount` before the pointer math. Alert came back. v0.5.4 rebuilt the whole algorithm on `Span` and int offsets
|
came back. v0.5.3 checked buffer length via `GetByteCount` before the pointer math. Alert came back.
|
||||||
with a 16 KiB cap on the ArrayPool rent. Only then did it go quiet.
|
v0.5.4 rebuilt the whole algorithm on `Span` and int offsets with a 16 KiB cap on the ArrayPool
|
||||||
|
rent. Only then did it go quiet.
|
||||||
|
|
||||||
Lesson: when a static analyser complains three times in a row, the analyser is not oversensitive. The data flow logic
|
Lesson: when a static analyser complains three times in a row, the analyser is not oversensitive.
|
||||||
is.
|
The data flow logic is.
|
||||||
|
|
||||||
### CodeRabbit as an external code reviewer
|
### CodeRabbit as an external code reviewer
|
||||||
|
|
||||||
The v1.0.0 sweep surfaced 3 critical and 21 major findings. Three classes were particularly instructive:
|
The v1.0.0 sweep surfaced 3 critical and 21 major findings. Three classes were particularly
|
||||||
|
instructive:
|
||||||
|
|
||||||
- **`Equals` methods comparing `GetHashCode()`.** Classic hash collision anti-pattern. Sounds like "if hashes are equal
|
- **`Equals` methods comparing `GetHashCode()`.** Classic hash collision anti-pattern. Sounds like
|
||||||
the objects are equal", which is exactly backwards. Hashes can collide; the objects are not equal.
|
"if hashes are equal the objects are equal", which is exactly backwards. Hashes can collide; the
|
||||||
- **`Dispose` methods that only unsubscribe part of their subscriptions.** Leak on every plugin reload. In normal use
|
objects are not equal.
|
||||||
you do not notice it immediately; in a long-running test you do.
|
- **`Dispose` methods that only unsubscribe part of their subscriptions.** Leak on every plugin
|
||||||
- **TOCTOU races.** Between a bounds check and a read another thread can swap out the array underneath you
|
reload. In normal use you do not notice it immediately; in a long-running test you do.
|
||||||
(`GlobalParametersCache`, `AutoTranslate`).
|
- **TOCTOU races.** Between a bounds check and a read another thread can swap out the array
|
||||||
|
underneath you (`GlobalParametersCache`, `AutoTranslate`).
|
||||||
|
|
||||||
I had at best read the theory on all of these before, never diagnosed them in my own code. CodeRabbit was the moment
|
I had at best read the theory on all of these before, never diagnosed them in my own code.
|
||||||
where "academic knowledge" became "okay, that is my code, that is my bug".
|
CodeRabbit was the moment where "academic knowledge" became "okay, that is my code, that is my bug".
|
||||||
|
|
||||||
### External testers are worth their weight
|
### External testers are worth their weight
|
||||||
|
|
||||||
Carla's feedback on pop-out discoverability triggered the header button in v0.6.1. That pop-outs were only reachable via
|
Carla's feedback on pop-out discoverability triggered the header button in v0.6.1. That pop-outs
|
||||||
right-click was something I as maintainer had stopped seeing; I knew the path by heart. Carl's request for theme
|
were only reachable via right-click was something I as maintainer had stopped seeing; I knew the
|
||||||
variants with brightness gradations shifted my thinking from "one theme = one colour" to "theme families with mood
|
path by heart. Carl's request for theme variants with brightness gradations shifted my thinking from
|
||||||
variants". Jingliu asked for TempTell persistence, which puts the tab system architecturally into question.
|
"one theme = one colour" to "theme families with mood variants". Jingliu asked for TempTell
|
||||||
|
persistence, which puts the tab system architecturally into question.
|
||||||
|
|
||||||
Solo I would not have seen any of those three things. Full stop.
|
Solo I would not have seen any of those three things. Full stop.
|
||||||
|
|
||||||
### release.yml and the YAML rabbit hole
|
### release.yml and the YAML rabbit hole
|
||||||
|
|
||||||
The `release.yml` workflow simply did not fire on the first v0.6.0 tag push. I dug through permissions, secret scopes
|
The `release.yml` workflow simply did not fire on the first v0.6.0 tag push. I dug through
|
||||||
and tag trigger configuration for hours before I understood what was actually happening: the PowerShell heredoc footer
|
permissions, secret scopes and tag trigger configuration for hours before I understood what was
|
||||||
in the "Generate release body" step contained a `---` Markdown horizontal rule at column 1, and that terminated the YAML
|
actually happening: the PowerShell heredoc footer in the "Generate release body" step contained a
|
||||||
block scalar of `run: |`. GitHub could not parse the workflow file, so the push-tag trigger never registered.
|
`---` Markdown horizontal rule at column 1, and that terminated the YAML block scalar of `run: |`.
|
||||||
|
GitHub could not parse the workflow file, so the push-tag trigger never registered.
|
||||||
|
|
||||||
Fix: extracted the footer into an external `.github/release-footer.md`, workflow reads it via `Get-Content`. Lesson: if
|
Fix: extracted the footer into an external `.github/release-footer.md`, workflow reads it via
|
||||||
a workflow does not trigger, verify first that GitHub can even parse the file. That was one of the bugs where I laughed
|
`Get-Content`. Lesson: if a workflow does not trigger, verify first that GitHub can even parse the
|
||||||
briefly after the fix and then asked myself how many other YAML files I had that might have the same trap in them.
|
file. That was one of the bugs where I laughed briefly after the fix and then asked myself how many
|
||||||
|
other YAML files I had that might have the same trap in them.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -259,29 +285,31 @@ briefly after the fix and then asked myself how many other YAML files I had that
|
|||||||
|
|
||||||
### Performance profiling in a game context
|
### Performance profiling in a game context
|
||||||
|
|
||||||
The FPS drop bug from upstream Chat 2 ([#145](https://github.com/Infiziert90/ChatTwo/issues/145)) has not been
|
The FPS drop bug from upstream Chat 2 ([#145](https://github.com/Infiziert90/ChatTwo/issues/145))
|
||||||
reproduced or verified in Hellion Chat. v1.0.0 applied several fixes on the suspected paths (DbViewer O(N²) -> O(N),
|
has not been reproduced or verified in Hellion Chat. v1.0.0 applied several fixes on the suspected
|
||||||
AutoTranslate lock serialisation, EmoteCache HttpClient reuse), but systematic measurement under load is missing. I
|
paths (DbViewer O(N²) -> O(N), AutoTranslate lock serialisation, EmoteCache HttpClient reuse), but
|
||||||
still need to learn how to properly measure what is actually consuming the frame budget in a plugin context.
|
systematic measurement under load is missing. I still need to learn how to properly measure what is
|
||||||
|
actually consuming the frame budget in a plugin context.
|
||||||
|
|
||||||
### Native interop and pointer math
|
### Native interop and pointer math
|
||||||
|
|
||||||
Even after the WrapText Span refactor in v0.5.4, pointer math makes me uneasy. ImGui forces you into `unsafe` code in
|
Even after the WrapText Span refactor in v0.5.4, pointer math makes me uneasy. ImGui forces you into
|
||||||
several places, and the safety margin from the "unbounded ArrayPool allocation" class of bugs is narrower than I would
|
`unsafe` code in several places, and the safety margin from the "unbounded ArrayPool allocation"
|
||||||
like. I want to get better at that before touching deeper ImGui custom drawing.
|
class of bugs is narrower than I would like. I want to get better at that before touching deeper
|
||||||
|
ImGui custom drawing.
|
||||||
|
|
||||||
### Test discipline for plugin code
|
### Test discipline for plugin code
|
||||||
|
|
||||||
The repo currently has no test project. That is a deliberate decision, not a forgotten one. Testing plugin code with
|
The repo currently has no test project. That is a deliberate decision, not a forgotten one. Testing
|
||||||
FFXIV hooks and Dalamud lifecycle cleanly is non-trivial, and I had not found an approach that made sense without a
|
plugin code with FFXIV hooks and Dalamud lifecycle cleanly is non-trivial, and I had not found an
|
||||||
large mocking scaffold. Privacy filter and configuration migration would be good test candidates because they are
|
approach that made sense without a large mocking scaffold. Privacy filter and configuration
|
||||||
isolated. On the list, but not a quick win.
|
migration would be good test candidates because they are isolated. On the list, but not a quick win.
|
||||||
|
|
||||||
### Linux quirks under Wine
|
### Linux quirks under Wine
|
||||||
|
|
||||||
XDG compliance, libnotify integration, WireGuard network detection, all on the [roadmap](ROADMAP.md), and all
|
XDG compliance, libnotify integration, WireGuard network detection, all on the
|
||||||
technically still unclear. Wine and sandboxed plugin code do not share all system APIs, and I do not know where the
|
[roadmap](ROADMAP.md), and all technically still unclear. Wine and sandboxed plugin code do not
|
||||||
pitfalls are until I have found them.
|
share all system APIs, and I do not know where the pitfalls are until I have found them.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -303,10 +331,12 @@ I use Claude Code as an assistant, not as a replacement for my own work.
|
|||||||
- Tester communication and roadmap prioritisation
|
- Tester communication and roadmap prioritisation
|
||||||
- Reviewing, verifying, pushing
|
- Reviewing, verifying, pushing
|
||||||
|
|
||||||
Classification and concrete examples are in [`AI_DISCLOSURE.md`](AI_DISCLOSURE.md). It matters to me that users and
|
Classification and concrete examples are in [`AI_DISCLOSURE.md`](AI_DISCLOSURE.md). It matters to me
|
||||||
potential contributors understand how the code came together, especially for a plugin that handles user data.
|
that users and potential contributors understand how the code came together, especially for a plugin
|
||||||
|
that handles user data.
|
||||||
|
|
||||||
Yes, AI. Yes, alone. Both mentioned more than strictly necessary. Welcome to the open-source plugin climate.
|
Yes, AI. Yes, alone. Both mentioned more than strictly necessary. Welcome to the open-source plugin
|
||||||
|
climate.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+238
-202
@@ -1,251 +1,281 @@
|
|||||||
# Hellion Chat — Roadmap
|
# Hellion Chat — Roadmap
|
||||||
|
|
||||||
Planned work after the v1.0.0 standalone cut. This list is intentionally high-level: concrete specs, size estimates and
|
Planned work after the v1.0.0 standalone cut. This list is intentionally high-level: concrete specs,
|
||||||
repro steps live in the internal backlog. External tracking runs via
|
size estimates and repro steps live in the internal backlog. External tracking runs via
|
||||||
[Gitea Issues](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/issues) with the `roadmap` label once an
|
[Gitea Issues](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/issues) with the
|
||||||
item is scheduled for a cycle.
|
`roadmap` label once an item is scheduled for a cycle.
|
||||||
|
|
||||||
Order reflects priority, not a guarantee. Items may shift or be dropped entirely if they turn out to be a poor fit for
|
Order reflects priority, not a guarantee. Items may shift or be dropped entirely if they turn out to
|
||||||
the plugin's privacy-first scope during brainstorming.
|
be a poor fit for the plugin's privacy-first scope during brainstorming.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Next Cycle (v1.5.1)
|
## Next Cycle (v1.5.1)
|
||||||
|
|
||||||
**Honorific Full Gradient Port plus FontAtlas-Defer for a 10× HITCH cut.** v1.5.0 closed the DI-container cycle with
|
**Honorific Full Gradient Port plus FontAtlas-Defer for a 10× HITCH cut.** v1.5.0 closed the
|
||||||
no performance penalty against Chat 2 (77 ms vs 74 ms median first-frame HITCH), but the cross-plugin baseline against
|
DI-container cycle with no performance penalty against Chat 2 (77 ms vs 74 ms median first-frame
|
||||||
Lightless Sync and XIVInstantMessenger surfaced a clean optimisation: both plugins defer their font-atlas build until
|
HITCH), but the cross-plugin baseline against Lightless Sync and XIVInstantMessenger surfaced a
|
||||||
after `Finished loading` and sit at 6-7 ms HITCH, an order of magnitude below the ~75 ms floor that Chat 2 and HellionChat
|
clean optimisation: both plugins defer their font-atlas build until after `Finished loading` and sit
|
||||||
share. v1.5.1 ports that pattern. Plus the Honorific gradient render path — DTO is gradient-ready since v1.4.7, only the
|
at 6-7 ms HITCH, an order of magnitude below the ~75 ms floor that Chat 2 and HellionChat share.
|
||||||
Wave / Pulse animation port remains. After that, First-Run-Wizard rework with curated defaults beyond the three privacy
|
v1.5.1 ports that pattern. Plus the Honorific gradient render path — DTO is gradient-ready since
|
||||||
profiles, then FR localisation (Hezcal native-speaker review confirmed), then the Plugin Integrations Wave 2-6
|
v1.4.7, only the Wave / Pulse animation port remains. After that, First-Run-Wizard rework with
|
||||||
(Context-Menu, NotificationMaster, Moodles, ExtraChat, XIVIM Quick-DM). Wine/Linux scroll-rubber-band spike sits as a
|
curated defaults beyond the three privacy profiles, then FR localisation (Hezcal native-speaker
|
||||||
low-priority Linux-only investigation at the tail.
|
review confirmed), then the Plugin Integrations Wave 2-6 (Context-Menu, NotificationMaster, Moodles,
|
||||||
|
ExtraChat, XIVIM Quick-DM). Wine/Linux scroll-rubber-band spike sits as a low-priority Linux-only
|
||||||
|
investigation at the tail.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## v1.5.0 — DI Foundation and Service Refactor (released 2026-05-17)
|
## v1.5.0 — DI Foundation and Service Refactor (released 2026-05-17)
|
||||||
|
|
||||||
Major architecture cycle. Plugin bootstrap moves to a generic-host DI container
|
Major architecture cycle. Plugin bootstrap moves to a generic-host DI container
|
||||||
(`Microsoft.Extensions.Hosting` + `IServiceCollection`) modelled on Lightless Sync's `PluginHostFactory`. Service
|
(`Microsoft.Extensions.Hosting` + `IServiceCollection`) modelled on Lightless Sync's
|
||||||
logging migrates from the static `Plugin.LogProxy` locator (the F12.2 shim from v1.4.7) to typed
|
`PluginHostFactory`. Service logging migrates from the static `Plugin.LogProxy` locator (the F12.2
|
||||||
`Microsoft.Extensions.Logging.ILogger<T>` via constructor injection, bridged over Dalamud's `IPluginLog` by a custom
|
shim from v1.4.7) to typed `Microsoft.Extensions.Logging.ILogger<T>` via constructor injection,
|
||||||
`DalamudLogger` trio. 18 instance-class services move to ctor-injected loggers across four slices: data layer,
|
bridged over Dalamud's `IPluginLog` by a custom `DalamudLogger` trio. 18 instance-class services
|
||||||
IPC/integrations, UI window layer, and root. `Plugin.LogProxy` stays for the eight buckets ctor injection cannot
|
move to ctor-injected loggers across four slices: data layer, IPC/integrations, UI window layer, and
|
||||||
reach — static helpers (`EmoteCache`, `AutoTranslate`, `MemoryUtil`, `WrapperUtil`), Dalamud-reflected types
|
root. `Plugin.LogProxy` stays for the eight buckets ctor injection cannot reach — static helpers
|
||||||
(`Configuration`), the `Message` data class, and instance classes that only log from static methods (`FontManager`,
|
(`EmoteCache`, `AutoTranslate`, `MemoryUtil`, `WrapperUtil`), Dalamud-reflected types
|
||||||
one `GameFunctions` site). Plugin.cs finishes at 1012 lines, virtually identical to the pre-cycle 1013 (-1 netto): the
|
(`Configuration`), the `Message` data class, and instance classes that only log from static methods
|
||||||
new Phase-1 host build and `Plugin.X` bridge wiring trade out exactly the service and window allocations that previously
|
(`FontManager`, one `GameFunctions` site). Plugin.cs finishes at 1012 lines, virtually identical to
|
||||||
lived in `LoadAsync`. Cross-plugin baseline (10 reload-stress runs, 51 active plugins): HellionChat first-frame HITCH
|
the pre-cycle 1013 (-1 netto): the new Phase-1 host build and `Plugin.X` bridge wiring trade out
|
||||||
77 ms median, Chat 2 v1.40.2 74 ms median — no DI penalty. The deferred-font-atlas pattern from Lightless and
|
exactly the service and window allocations that previously lived in `LoadAsync`. Cross-plugin
|
||||||
XIVInstantMessenger is the v1.5.1 follow-up. User-visible: slash-command insert fix cherry-picked from ChatTwo upstream
|
baseline (10 reload-stress runs, 51 active plugins): HellionChat first-frame HITCH 77 ms median,
|
||||||
`ee7768ac` — pasting a slash command into the chat input now replaces existing input instead of concatenating.
|
Chat 2 v1.40.2 74 ms median — no DI penalty. The deferred-font-atlas pattern from Lightless and
|
||||||
Migration v17 stays.
|
XIVInstantMessenger is the v1.5.1 follow-up. User-visible: slash-command insert fix cherry-picked
|
||||||
|
from ChatTwo upstream `ee7768ac` — pasting a slash command into the chat input now replaces existing
|
||||||
|
input instead of concatenating. Migration v17 stays.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## v1.4.10 — Symbol-Picker and Tell-History Fix (released 2026-05-16)
|
## v1.4.10 — Symbol-Picker and Tell-History Fix (released 2026-05-16)
|
||||||
|
|
||||||
Eleventh and final sub-patch of the v1.4.x Polish Sweep series. Symbol picker for the chat input — popup with two tabs
|
Eleventh and final sub-patch of the v1.4.x Polish Sweep series. Symbol picker for the chat input —
|
||||||
(161 FFXIV PUA glyphs via Dalamud's SeIconChar plus 97 server-verified BMP symbols probed through `/echo` and `/say` in
|
popup with two tabs (161 FFXIV PUA glyphs via Dalamud's SeIconChar plus 97 server-verified BMP
|
||||||
a four-round whitelist build) — cursor-aware splice, multi-insert, recent-used strip across both tabs, Settings toggle
|
symbols probed through `/echo` and `/say` in a four-round whitelist build) — cursor-aware splice,
|
||||||
in Chat → Message behaviour. Mid-cycle hotfix for pinned auto-tell tabs: PreloadHistory used to cap the SQL scan at
|
multi-insert, recent-used strip across both tabs, Settings toggle in Chat → Message behaviour.
|
||||||
500 rows regardless of the user's `AutoTellTabsHistoryPreload` setting, so active users with many partners lost the
|
Mid-cycle hotfix for pinned auto-tell tabs: PreloadHistory used to cap the SQL scan at 500 rows
|
||||||
backlog of less-frequent pinned partners; the cap is gone, the `(Receiver, Date)` index keeps SQL fast, the client-side
|
regardless of the user's `AutoTellTabsHistoryPreload` setting, so active users with many partners
|
||||||
loop respects the user setting as the upper bound. Slash-command teardown cleanup wires the v1.4.9 wrappers through
|
lost the backlog of less-frequent pinned partners; the cap is gone, the `(Receiver, Date)` index
|
||||||
private fields so dispose detaches the live registration instead of re-registering with identical args. The original
|
keeps SQL fast, the client-side loop respects the user setting as the upper bound. Slash-command
|
||||||
Reserve-A `ImGuiListClipper` refactor for `DrawMessages` was cancelled after cross-platform smoke showed the scroll
|
teardown cleanup wires the v1.4.9 wrappers through private fields so dispose detaches the live
|
||||||
rubber-band is a Wine/Linux render-pipeline quirk, not universal — Windows-side testing on v1.4.9 confirmed no lag.
|
registration instead of re-registering with identical args. The original Reserve-A
|
||||||
Migration v17 stays.
|
`ImGuiListClipper` refactor for `DrawMessages` was cancelled after cross-platform smoke showed the
|
||||||
|
scroll rubber-band is a Wine/Linux render-pipeline quirk, not universal — Windows-side testing on
|
||||||
|
v1.4.9 confirmed no lag. Migration v17 stays.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## v1.4.9 — Plugin-Load Render Polish (released 2026-05-15)
|
## v1.4.9 — Plugin-Load Render Polish (released 2026-05-15)
|
||||||
|
|
||||||
Tenth sub-patch of the v1.4.x Polish Sweep series. First-frame HITCH drops from ~127 ms median to ~76 ms median (4-reload
|
Tenth sub-patch of the v1.4.x Polish Sweep series. First-frame HITCH drops from ~127 ms median to
|
||||||
sample), comfortably under Dalamud's 100 ms warning threshold. Mechanism: a single `_firstFrameDone` flag inside
|
~76 ms median (4-reload sample), comfortably under Dalamud's 100 ms warning threshold. Mechanism: a
|
||||||
`ChatLogWindow` defers six non-essential rendering sections (bottom status bar, channel-name SeString chunks, window
|
single `_firstFrameDone` flag inside `ChatLogWindow` defers six non-essential rendering sections
|
||||||
bounds check, v0.6.1 hint banner, autocomplete, input-preview calculation) from frame 0 to frame 1. User sees those
|
(bottom status bar, channel-name SeString chunks, window bounds check, v0.6.1 hint banner,
|
||||||
sections ~17 ms (60 fps) later, invisible inside the ~2.5 s font-atlas build window after every reload. Slash-command
|
autocomplete, input-preview calculation) from frame 0 to frame 1. User sees those sections ~17 ms
|
||||||
registration moved from individual window constructors to a central `SetupCommands` / `TearDownCommands` pair in
|
(60 fps) later, invisible inside the ~2.5 s font-atlas build window after every reload.
|
||||||
`Plugin.cs` — `/hellion`, `/hellionView`, `/hellionSeString` and `/hellionDebugger` work before their target windows are
|
Slash-command registration moved from individual window constructors to a central `SetupCommands` /
|
||||||
opened the first time, and Dalamud's plugin-manager `OpenConfigUi` / `OpenMainUi` buttons hang on the same path.
|
`TearDownCommands` pair in `Plugin.cs` — `/hellion`, `/hellionView`, `/hellionSeString` and
|
||||||
Plugin-load profiling logs (auto-translate warmup, `MessageStore.Connect`, `MessageStore.Migrate`, `FilterAllTabs`) stay
|
`/hellionDebugger` work before their target windows are opened the first time, and Dalamud's
|
||||||
on at Information level as a regression tripwire. The release also ships a ChatTwo IPC compatibility layer: HellionChat
|
plugin-manager `OpenConfigUi` / `OpenMainUi` buttons hang on the same path. Plugin-load profiling
|
||||||
mirrors ChatTwo's full IPC surface (`GetChatInputState`, `ChatInputStateChanged`, `Register`, `Unregister`, `Available`,
|
logs (auto-translate warmup, `MessageStore.Connect`, `MessageStore.Migrate`, `FilterAllTabs`) stay
|
||||||
`Invoke`) under the `ChatTwo.*` namespace in addition to our existing `HellionChat.*` provider gates, so third-party
|
on at Information level as a regression tripwire. The release also ships a ChatTwo IPC compatibility
|
||||||
integrations that only subscribe to ChatTwo's IPC (Artisan, AllaganTools) keep working without a code change on their
|
layer: HellionChat mirrors ChatTwo's full IPC surface (`GetChatInputState`, `ChatInputStateChanged`,
|
||||||
side. Conflict detection prevents ChatTwo from loading in parallel, so there is no slot-collision risk at runtime.
|
`Register`, `Unregister`, `Available`, `Invoke`) under the `ChatTwo.*` namespace in addition to our
|
||||||
Migration v17 stays (no schema bump). Hypothesis-triage falsified
|
existing `HellionChat.*` provider gates, so third-party integrations that only subscribe to
|
||||||
three of four candidate root causes (font-atlas sync fallback, theme-apply ABGR-cache init, multiple-window render via
|
ChatTwo's IPC (Artisan, AllaganTools) keep working without a code change on their side. Conflict
|
||||||
lazy-init) — actual cost distributes evenly across ~10 ImGui sections inside ChatLogWindow, so structural rewrite is
|
detection prevents ChatTwo from loading in parallel, so there is no slot-collision risk at runtime.
|
||||||
deferred to v1.5.x DI-container cycle.
|
Migration v17 stays (no schema bump). Hypothesis-triage falsified three of four candidate root
|
||||||
|
causes (font-atlas sync fallback, theme-apply ABGR-cache init, multiple-window render via lazy-init)
|
||||||
|
— actual cost distributes evenly across ~10 ImGui sections inside ChatLogWindow, so structural
|
||||||
|
rewrite is deferred to v1.5.x DI-container cycle.
|
||||||
|
|
||||||
## v1.4.8 — Hook-Layer and Polish Quick-Wins (released 2026-05-14)
|
## v1.4.8 — Hook-Layer and Polish Quick-Wins (released 2026-05-14)
|
||||||
|
|
||||||
Ninth sub-patch of the v1.4.x Polish Sweep series. Database Viewer gains an optional FTS5 full-text search across the
|
Ninth sub-patch of the v1.4.x Polish Sweep series. Database Viewer gains an optional FTS5 full-text
|
||||||
full chat history, built asynchronously on first run after the update with a progress toast; the local page-filter
|
search across the full chat history, built asynchronously on first run after the update with a
|
||||||
remains the default mode. Custom theme files auto-reload when edited while the theme is active (1 Hz disk-stat throttle,
|
progress toast; the local page-filter remains the default mode. Custom theme files auto-reload when
|
||||||
so per-frame cost is free). Retention sweep no longer blocks the framework thread — `Framework.Run(...).Wait()` is
|
edited while the theme is active (1 Hz disk-stat throttle, so per-frame cost is free). Retention
|
||||||
replaced by `Framework.RunOnTick(...)`, removing the ~194 ms hitch per sweep. Status-bar height is now derived from
|
sweep no longer blocks the framework thread — `Framework.Run(...).Wait()` is replaced by
|
||||||
`GetTextLineHeightWithSpacing()` plus a DPI-aware spacer so the bar renders correctly at Windows display scaling above
|
`Framework.RunOnTick(...)`, removing the ~194 ms hitch per sweep. Status-bar height is now derived
|
||||||
100 %. Receive-suppressed-tells routing was investigated and **postponed to v1.5.x**: when other plugins suppress tells
|
from `GetTextLineHeightWithSpacing()` plus a DPI-aware spacer so the bar renders correctly at
|
||||||
via `CheckMessageHandled`, FFXIV's chat-pipeline skips the `RaptureLogModule.AddMsgSourceEntry` path, which means the
|
Windows display scaling above 100 %. Receive-suppressed-tells routing was investigated and
|
||||||
`ContentIdResolverHook` does not fire and tell-partner identification breaks. The fix belongs next to the planned ad-block
|
**postponed to v1.5.x**: when other plugins suppress tells via `CheckMessageHandled`, FFXIV's
|
||||||
hook layer where the same patch surface comes up anyway. Migration v17 stays (no schema bump). H3 leaves a foundation
|
chat-pipeline skips the `RaptureLogModule.AddMsgSourceEntry` path, which means the
|
||||||
note in the Vault (`Projekte/FFXIV/Hellion Chat/v1.5.x Ad-Block Foundation.md`) covering the NoSoliciting filter +
|
`ContentIdResolverHook` does not fire and tell-partner identification breaks. The fix belongs next
|
||||||
|
to the planned ad-block hook layer where the same patch surface comes up anyway. Migration v17 stays
|
||||||
|
(no schema bump). H3 leaves a foundation note in the Vault
|
||||||
|
(`Projekte/FFXIV/Hellion Chat/v1.5.x Ad-Block Foundation.md`) covering the NoSoliciting filter +
|
||||||
bubble-layer hook pattern as a ready-made template for the v1.5.x cycle.
|
bubble-layer hook pattern as a ready-made template for the v1.5.x cycle.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## v1.4.7 — Backlog Cleanup and Mid-Features (released 2026-05-13)
|
## v1.4.7 — Backlog Cleanup and Mid-Features (released 2026-05-13)
|
||||||
|
|
||||||
Eighth sub-patch of the v1.4.x Polish Sweep series. First user-visible feature bundle since v1.4.5. TempTell tabs can
|
Eighth sub-patch of the v1.4.x Polish Sweep series. First user-visible feature bundle since v1.4.5.
|
||||||
now be pinned via right-click; pinned tabs survive plugin reload and character logout, keep their conversation history
|
TempTell tabs can now be pinned via right-click; pinned tabs survive plugin reload and character
|
||||||
(loaded on demand from the message store on rehydrate), and stay bound to the same `/tell` partner. A hard cap of 5
|
logout, keep their conversation history (loaded on demand from the message store on rehydrate), and
|
||||||
pinned tabs lives in a pool separate from the 15-tab auto-tell pool, total ceiling 20. The sidebar groups pinned tabs
|
stay bound to the same `/tell` partner. A hard cap of 5 pinned tabs lives in a pool separate from
|
||||||
into their own section with a divider header, and the sidebar width itself is now configurable in **Theme & Layout**
|
the 15-tab auto-tell pool, total ceiling 20. The sidebar groups pinned tabs into their own section
|
||||||
between 44 and 160 px. Honorific glow outlines render when the title carries a Glow colour, opt-in via **Settings →
|
with a divider header, and the sidebar width itself is now configurable in **Theme & Layout**
|
||||||
Integrations → Render glow outlines (Honorific)** (default off). Honorific's gradient (Color3 / GradientColourSet / Wave
|
between 44 and 160 px. Honorific glow outlines render when the title carries a Glow colour, opt-in
|
||||||
/ Pulse) is parsed but rendered statically — a later cycle will port the full animation algorithm or land an upstream
|
via **Settings → Integrations → Render glow outlines (Honorific)** (default off). Honorific's
|
||||||
IPC PR for the resolved frame colour. `Configuration.UpdateFrom` now preserves the runtime `CurrentChannel` across the
|
gradient (Color3 / GradientColourSet / Wave / Pulse) is parsed but rendered statically — a later
|
||||||
persistent-tab merge, and `TabSwitched` deep-clones the seeded channel instead of sharing the previous tab's
|
cycle will port the full animation algorithm or land an upstream IPC PR for the resolved frame
|
||||||
`UsedChannel` — together they fix a Settings-Save regression where the chat input could pop back to
|
colour. `Configuration.UpdateFrom` now preserves the runtime `CurrentChannel` across the
|
||||||
`/tell <pinned-partner>` after touching settings on a Party or Linkshell tab. Internal items: `IPluginLogProxy`
|
persistent-tab merge, and `TabSwitched` deep-clones the seeded channel instead of sharing the
|
||||||
indirection over Dalamud's `IPluginLog` routes all ~91 `Plugin.Log` call sites through a testable proxy, closing the
|
previous tab's `UsedChannel` — together they fix a Settings-Save regression where the chat input
|
||||||
F12.1 test-isolation gap (`MessageStore.Migrate0` runs in xUnit now). TempTab counter switched from `Interlocked` cached
|
could pop back to `/tell <pinned-partner>` after touching settings on a Party or Linkshell tab.
|
||||||
field to derived `Tabs.Count(predicate)`. Migration v16 → v17 is additive (new `Tab.IsPinned` flag). Build-Suite floor
|
Internal items: `IPluginLogProxy` indirection over Dalamud's `IPluginLog` routes all ~91
|
||||||
688 → 710 (+22 tests across Pin-lifecycle predicates, pool limits, Tab.Clone roundtrip, MessageStore Migrate0
|
`Plugin.Log` call sites through a testable proxy, closing the F12.1 test-isolation gap
|
||||||
construction, and Honorific TitleData JSON roundtrip).
|
(`MessageStore.Migrate0` runs in xUnit now). TempTab counter switched from `Interlocked` cached
|
||||||
|
field to derived `Tabs.Count(predicate)`. Migration v16 → v17 is additive (new `Tab.IsPinned` flag).
|
||||||
|
Build-Suite floor 688 → 710 (+22 tests across Pin-lifecycle predicates, pool limits, Tab.Clone
|
||||||
|
roundtrip, MessageStore Migrate0 construction, and Honorific TitleData JSON roundtrip).
|
||||||
|
|
||||||
## v1.4.6 — Code Hygiene and Refactor (released 2026-05-12)
|
## v1.4.6 — Code Hygiene and Refactor (released 2026-05-12)
|
||||||
|
|
||||||
Seventh sub-patch of the v1.4.x Polish Sweep series. Maintenance patch — no user-visible behaviour changes; tightens the
|
Seventh sub-patch of the v1.4.x Polish Sweep series. Maintenance patch — no user-visible behaviour
|
||||||
development feedback loop and pulls in two ChatTwo upstream bugfixes. `scripts/preflight.sh` gains a csharpier reflow
|
changes; tightens the development feedback loop and pulls in two ChatTwo upstream bugfixes.
|
||||||
check (Block E) and a markdownlint pass (Block F), so style drift and markdown violations are blocked at the pre-push
|
`scripts/preflight.sh` gains a csharpier reflow check (Block E) and a markdownlint pass (Block F),
|
||||||
gate. `FontManager.AddFontWithFallback` catch-filter now spans `InvalidOperationException` and `ArgumentException` on
|
so style drift and markdown violations are blocked at the pre-push gate.
|
||||||
top of the existing IO triad, with the exception type name in the warning log so the diagnostic path can see which
|
`FontManager.AddFontWithFallback` catch-filter now spans `InvalidOperationException` and
|
||||||
atlas-toolkit throw triggered the fallback. `BrandingLinks` and `IntegrationLinks` run a `[ModuleInitializer]` URL
|
`ArgumentException` on top of the existing IO triad, with the exception type name in the warning log
|
||||||
validation pass on plugin load; a typo in a future URL rotation now throws at startup instead of failing silently when a
|
so the diagnostic path can see which atlas-toolkit throw triggered the fallback. `BrandingLinks` and
|
||||||
user clicks the broken button. Cherry-picked from ChatTwo upstream `f35b7d3`: `Chat.SetChannel` no longer leaks the
|
`IntegrationLinks` run a `[ModuleInitializer]` URL validation pass on plugin load; a typo in a
|
||||||
native `Utf8String` when the linkshell check rejects the channel (rename to `IsChannelOrExistingLinkshell` plus
|
future URL rotation now throws at startup instead of failing silently when a user clicks the broken
|
||||||
wrap-not-return), and `Tab.Clone` now deep-clones `UsedChannel` and `TellTarget` (the previous reference copy let PopOut
|
button. Cherry-picked from ChatTwo upstream `f35b7d3`: `Chat.SetChannel` no longer leaks the native
|
||||||
and Temp tabs mutate each other's channel state). The `ChatLogWindow` active-tab underline pill scales with
|
`Utf8String` when the linkshell check rejects the channel (rename to `IsChannelOrExistingLinkshell`
|
||||||
`ImGuiHelpers.GlobalScale` and rounds to physical pixels for crisp rendering above 100 % DPI. Internal items:
|
plus wrap-not-return), and `Tab.Clone` now deep-clones `UsedChannel` and `TellTarget` (the previous
|
||||||
`HellionStyle` ChildBgAlpha extracted to a testable helper, `Plugin.SaveConfig` clones only the temp-tab subset in the
|
reference copy let PopOut and Temp tabs mutate each other's channel state). The `ChatLogWindow`
|
||||||
snapshot path, `SettingsOverview` caches the draw-list per frame, `Dalamud.Utility.Util` static surface routed through
|
active-tab underline pill scales with `ImGuiHelpers.GlobalScale` and rounds to physical pixels for
|
||||||
an `IPlatformUtil` indirection (`MessageStore`'s `IsWine` probe is now testable in isolation). No schema bump, no
|
crisp rendering above 100 % DPI. Internal items: `HellionStyle` ChildBgAlpha extracted to a testable
|
||||||
migration.
|
helper, `Plugin.SaveConfig` clones only the temp-tab subset in the snapshot path, `SettingsOverview`
|
||||||
|
caches the draw-list per frame, `Dalamud.Utility.Util` static surface routed through an
|
||||||
|
`IPlatformUtil` indirection (`MessageStore`'s `IsWine` probe is now testable in isolation). No
|
||||||
|
schema bump, no migration.
|
||||||
|
|
||||||
## v1.4.5 — UX and Robustness (released 2026-05-12)
|
## v1.4.5 — UX and Robustness (released 2026-05-12)
|
||||||
|
|
||||||
Sixth sub-patch of the v1.4.x Polish Sweep series. User-visible robustness polish plus two doc/test polish items from
|
Sixth sub-patch of the v1.4.x Polish Sweep series. User-visible robustness polish plus two doc/test
|
||||||
the audit backlog. Chat-log draw failures now surface as a one-shot notification instead of failing silently. The
|
polish items from the audit backlog. Chat-log draw failures now surface as a one-shot notification
|
||||||
first-run wizard splits accept from close: `OnClose` no longer silently sets `FirstRunCompleted`, and a new footer
|
instead of failing silently. The first-run wizard splits accept from close: `OnClose` no longer
|
||||||
"Later — keep defaults" button is the explicit path to dismiss without picking a profile. `InputHistoryService` clears
|
silently sets `FirstRunCompleted`, and a new footer "Later — keep defaults" button is the explicit
|
||||||
on plugin dispose so the previous session's typed commands don't bleed into the next load. `FontManager` falls back to
|
path to dismiss without picking a profile. `InputHistoryService` clears on plugin dispose so the
|
||||||
the system font path if the embedded Hellion font resource is missing (broken-csproj / dev-build only). The status bar
|
previous session's typed commands don't bleed into the next load. `FontManager` falls back to the
|
||||||
hides the version slot when the chat window is too narrow to fit all five slots without overlap. Plus
|
system font path if the embedded Hellion font resource is missing (broken-csproj / dev-build only).
|
||||||
`Plugin.cs:167-168` gains an explicit session-only Auto-Tell-Tab invariant comment with a `TempTabCounter.InitFromList`
|
The status bar hides the version slot when the chat window is too narrow to fit all five slots
|
||||||
pin in the Build-Suite. No schema bump, no migration.
|
without overlap. Plus `Plugin.cs:167-168` gains an explicit session-only Auto-Tell-Tab invariant
|
||||||
|
comment with a `TempTabCounter.InitFromList` pin in the Build-Suite. No schema bump, no migration.
|
||||||
|
|
||||||
## v1.4.4 — Threading and IPC Safety Polish (released 2026-05-12)
|
## v1.4.4 — Threading and IPC Safety Polish (released 2026-05-12)
|
||||||
|
|
||||||
Fifth sub-patch of the v1.4.x Polish Sweep series. `AutoTellTabsService.ActiveTempTabCount` switches from a
|
Fifth sub-patch of the v1.4.x Polish Sweep series. `AutoTellTabsService.ActiveTempTabCount` switches
|
||||||
lock-protected LINQ `Count` to an `Interlocked` counter kept in sync from inside the existing mutation paths;
|
from a lock-protected LINQ `Count` to an `Interlocked` counter kept in sync from inside the existing
|
||||||
`Initialize()` seeds from the persisted Tabs list and `SaveConfig`'s snapshot-restore path calls a new
|
mutation paths; `Initialize()` seeds from the persisted Tabs list and `SaveConfig`'s
|
||||||
`ResyncTempTabCounter()` after the mid-step `RemoveAll`. `HonorificService` carries per-method threading banners and
|
snapshot-restore path calls a new `ResyncTempTabCounter()` after the mid-step `RemoveAll`.
|
||||||
`TryUnsubscribe`'s log level moves from Debug to Warning. `AutoTranslate.PreloadCache` is marked `IsBackground = true`
|
`HonorificService` carries per-method threading banners and `TryUnsubscribe`'s log level moves from
|
||||||
so plugin unload no longer waits for it. `Configuration.IsAllowedForStorage` logs once per unknown ChatType via a
|
Debug to Warning. `AutoTranslate.PreloadCache` is marked `IsBackground = true` so plugin unload no
|
||||||
`NonSerialized` `HashSet`, and `PrivacyPersistUnknownChannels` default flips to `true` for new installs. No schema bump,
|
longer waits for it. `Configuration.IsAllowedForStorage` logs once per unknown ChatType via a
|
||||||
no migration.
|
`NonSerialized` `HashSet`, and `PrivacyPersistUnknownChannels` default flips to `true` for new
|
||||||
|
installs. No schema bump, no migration.
|
||||||
|
|
||||||
## v1.4.3 — Plugin-Load Async-Init + Repo-Cutover (released 2026-05-08)
|
## v1.4.3 — Plugin-Load Async-Init + Repo-Cutover (released 2026-05-08)
|
||||||
|
|
||||||
Fourth and largest sub-patch of the v1.4.x Polish Sweep series. Plugin migrated to Dalamud's `IAsyncDalamudPlugin` API:
|
Fourth and largest sub-patch of the v1.4.x Polish Sweep series. Plugin migrated to Dalamud's
|
||||||
the constructor handles only bootstrap essentials (config load, language init, conflict detection); migrations, service
|
`IAsyncDalamudPlugin` API: the constructor handles only bootstrap essentials (config load, language
|
||||||
allocations, window construction and hook subscription move to `LoadAsync`. Schema gate replaces the v9 → v16 migration
|
init, conflict detection); migrations, service allocations, window construction and hook
|
||||||
chain; configs on schema v16+ load directly, older configs trigger an "install v1.4.2 first" error.
|
subscription move to `LoadAsync`. Schema gate replaces the v9 → v16 migration chain; configs on
|
||||||
`AutoTranslate.PreloadCache` moved off the load path. `FontManager.BuildFonts` runs sync at the start of `LoadAsync`;
|
schema v16+ load directly, older configs trigger an "install v1.4.2 first" error.
|
||||||
Dalamud rebuilds the font atlas on its own pipeline. Custom-repo URL cut over to `gitea.hellion-forge.cloud`; the GitHub
|
`AutoTranslate.PreloadCache` moved off the load path. `FontManager.BuildFonts` runs sync at the
|
||||||
repo remains as a frozen v1.4.2 snapshot. Plugin load time sits at ~3.7 s median (5 reloads), comparable to v1.4.2 — the
|
start of `LoadAsync`; Dalamud rebuilds the font atlas on its own pipeline. Custom-repo URL cut over
|
||||||
async migration is a foundation for v1.4.4 lazy-init optimisations rather than an immediate user-perceived win.
|
to `gitea.hellion-forge.cloud`; the GitHub repo remains as a frozen v1.4.2 snapshot. Plugin load
|
||||||
|
time sits at ~3.7 s median (5 reloads), comparable to v1.4.2 — the async migration is a foundation
|
||||||
|
for v1.4.4 lazy-init optimisations rather than an immediate user-perceived win.
|
||||||
|
|
||||||
## v1.4.2 — ChatLog Frame-Hot-Path (released 2026-05-08)
|
## v1.4.2 — ChatLog Frame-Hot-Path (released 2026-05-08)
|
||||||
|
|
||||||
Third sub-patch of the v1.4.x Polish Sweep series. Per-frame allocations eliminated from the ChatLogWindow render path
|
Third sub-patch of the v1.4.x Polish Sweep series. Per-frame allocations eliminated from the
|
||||||
and the settings status bar. Card-mode border loop in `DrawMessages` hoists five invariants into a pre-loop hoist;
|
ChatLogWindow render path and the settings status bar. Card-mode border loop in `DrawMessages`
|
||||||
`AutoTellTabTint` gets a per-tab cache via `TabTintCache` (separate validation keys per cache, no cross-invalidation);
|
hoists five invariants into a pre-loop hoist; `AutoTellTabTint` gets a per-tab cache via
|
||||||
status bar moves the cache-gate check before the aggregation and replaces LINQ `Sum`+`Count` with a single-pass foreach.
|
`TabTintCache` (separate validation keys per cache, no cross-invalidation); status bar moves the
|
||||||
|
cache-gate check before the aggregation and replaces LINQ `Sum`+`Count` with a single-pass foreach.
|
||||||
|
|
||||||
## v1.4.1 — Theme Engine Performance (released 2026-05-08)
|
## v1.4.1 — Theme Engine Performance (released 2026-05-08)
|
||||||
|
|
||||||
Second sub-patch of the v1.4.x Polish Sweep series. ABGR cache pre-computed on theme records; `HellionStyle.PushGlobal`
|
Second sub-patch of the v1.4.x Polish Sweep series. ABGR cache pre-computed on theme records;
|
||||||
reads from the cache instead of converting per slot per frame. **~13 % render-time recovery** in smoke tests (plan
|
`HellionStyle.PushGlobal` reads from the cache instead of converting per slot per frame. **~13 %
|
||||||
estimate of 2–6 % was conservative; real result ~10–15 %). Custom-theme hot-reload survives transient file locks via
|
render-time recovery** in smoke tests (plan estimate of 2–6 % was conservative; real result ~10–15
|
||||||
last-known-good snapshot. Plus: Synthwave Sunset as the tenth built-in, author credits consolidated under Hellion Forge,
|
%). Custom-theme hot-reload survives transient file locks via last-known-good snapshot. Plus:
|
||||||
Mint Grove + Forge Merchantman credited to Carla Beleandis as a community thanks.
|
Synthwave Sunset as the tenth built-in, author credits consolidated under Hellion Forge, Mint
|
||||||
|
Grove + Forge Merchantman credited to Carla Beleandis as a community thanks.
|
||||||
|
|
||||||
## v1.4.0 — Critical Lifecycle Fixes (released 2026-05-07)
|
## v1.4.0 — Critical Lifecycle Fixes (released 2026-05-07)
|
||||||
|
|
||||||
First sub-patch of the v1.4.x Polish Sweep series. Seven P0 findings from audit passes 3 and 4 resolved: async-void
|
First sub-patch of the v1.4.x Polish Sweep series. Seven P0 findings from audit passes 3 and 4
|
||||||
loads, missing `IsBackground` flags, `GC.Collect` in Dispose, deferred-save race and pre-v13 backup lookup for
|
resolved: async-void loads, missing `IsBackground` flags, `GC.Collect` in Dispose, deferred-save
|
||||||
`WindowOpacity`. No schema bumps, no user-facing behaviour changes other than reload and shutdown running noticeably
|
race and pre-v13 backup lookup for `WindowOpacity`. No schema bumps, no user-facing behaviour
|
||||||
cleaner.
|
changes other than reload and shutdown running noticeably cleaner.
|
||||||
|
|
||||||
## v1.3.0 — Plugin Integrations: Honorific (released 2026-05-07)
|
## v1.3.0 — Plugin Integrations: Honorific (released 2026-05-07)
|
||||||
|
|
||||||
First cycle of the plugin integrations roadmap. Honorific custom titles displayed in the chat header with auto-detect
|
First cycle of the plugin integrations roadmap. Honorific custom titles displayed in the chat header
|
||||||
and silent fallback. New Integrations settings tab. Pattern-setter for the five following cycles (Context Menu,
|
with auto-detect and silent fallback. New Integrations settings tab. Pattern-setter for the five
|
||||||
NotificationMaster, RP Status Block, ExtraChat, XIVIM).
|
following cycles (Context Menu, NotificationMaster, RP Status Block, ExtraChat, XIVIM).
|
||||||
|
|
||||||
Spec: [Plugin Integrations Overview](../Hellion%20Chat%20Plugin-Integrationen.md)
|
Spec: [Plugin Integrations Overview](../Hellion%20Chat%20Plugin-Integrationen.md)
|
||||||
|
|
||||||
## v1.2.3 — Theme Expansion (released 2026-05-06)
|
## v1.2.3 — Theme Expansion (released 2026-05-06)
|
||||||
|
|
||||||
Four new built-in themes: Night Blue, Indigo Violet, Forge Merchantman, Hellion Spectrum (Deuteran/Protan-safe). No
|
Four new built-in themes: Night Blue, Indigo Violet, Forge Merchantman, Hellion Spectrum
|
||||||
engine changes. See `docs/CHANGELOG.md`.
|
(Deuteran/Protan-safe). No engine changes. See `docs/CHANGELOG.md`.
|
||||||
|
|
||||||
(v1.2.2 was burned because the `repo.json` manifest was not bumped in sync on the first push — re-released as v1.2.3
|
(v1.2.2 was burned because the `repo.json` manifest was not bumped in sync on the first push —
|
||||||
with full manifest synchronisation.)
|
re-released as v1.2.3 with full manifest synchronisation.)
|
||||||
|
|
||||||
## v1.2.1 — Settings Cleanup (released 2026-05-06)
|
## v1.2.1 — Settings Cleanup (released 2026-05-06)
|
||||||
|
|
||||||
Settings re-sorted thematically (9 cards), 4 dead settings removed, auto-migration v15 → v16 without data loss.
|
Settings re-sorted thematically (9 cards), 4 dead settings removed, auto-migration v15 → v16 without
|
||||||
|
data loss.
|
||||||
|
|
||||||
## v1.2.0 — Layout Refresh (released 2026-05-05)
|
## v1.2.0 — Layout Refresh (released 2026-05-05)
|
||||||
|
|
||||||
Top tabs refresh, sidebar tab icons, bottom status bar, card rows as default message render, auto-tell tab hashing.
|
Top tabs refresh, sidebar tab icons, bottom status bar, card rows as default message render,
|
||||||
|
auto-tell tab hashing.
|
||||||
|
|
||||||
## v1.1.0 — Theme Foundation (released 2026-05-05)
|
## v1.1.0 — Theme Foundation (released 2026-05-05)
|
||||||
|
|
||||||
Theme engine with five built-in themes, settings card grid, custom themes via JSON, theme authoring docs. Plugin icon
|
Theme engine with five built-in themes, settings card grid, custom themes via JSON, theme authoring
|
||||||
updated to Hellion Forge hammer. See `docs/CHANGELOG.md` for details.
|
docs. Plugin icon updated to Hellion Forge hammer. See `docs/CHANGELOG.md` for details.
|
||||||
|
|
||||||
Items from the original v1.1.0 plan (ad-block / spam filter, receive-suppressed-tells toggle) were deferred in favour of
|
Items from the original v1.1.0 plan (ad-block / spam filter, receive-suppressed-tells toggle) were
|
||||||
the theme engine — both items live on in the mid-term block.
|
deferred in favour of the theme engine — both items live on in the mid-term block.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Mid-Term (v1.4.x+)
|
## Mid-Term (v1.4.x+)
|
||||||
|
|
||||||
- **Plugin Integrations Roadmap (Cycles 2–6)** — six plugin integrations planned; Honorific (Cycle 1) is live, followed
|
- **Plugin Integrations Roadmap (Cycles 2–6)** — six plugin integrations planned; Honorific
|
||||||
by Context Menu, NotificationMaster, RP Status Block, ExtraChat and XIVIM in their own cycles. Spec and cycle order in
|
(Cycle 1) is live, followed by Context Menu, NotificationMaster, RP Status Block, ExtraChat and
|
||||||
|
XIVIM in their own cycles. Spec and cycle order in
|
||||||
[Plugin Integrations Overview](../Hellion%20Chat%20Plugin-Integrationen.md).
|
[Plugin Integrations Overview](../Hellion%20Chat%20Plugin-Integrationen.md).
|
||||||
- **Ad-Block / Spam Filter** — hybrid concept combining a lightweight built-in filter with optional `NoSoliciting` IPC
|
- **Ad-Block / Spam Filter** — hybrid concept combining a lightweight built-in filter with optional
|
||||||
integration. Addresses ad-spam in public channels and tells. Deferred from the v1.1.0 plan.
|
`NoSoliciting` IPC integration. Addresses ad-spam in public channels and tells. Deferred from the
|
||||||
- **Receive-Suppressed-Tells Toggle** — auto-tell tabs trigger even when a third-party plugin (e.g. XIVMessenger)
|
v1.1.0 plan.
|
||||||
globally suppresses /tell display. Same hook layer as ad-block, so they are bundled.
|
- **Receive-Suppressed-Tells Toggle** — auto-tell tabs trigger even when a third-party plugin (e.g.
|
||||||
- **Database Viewer Inline Search** — full-text search in the DB viewer via SQLite FTS5. Currently only date and channel
|
XIVMessenger) globally suppresses /tell display. Same hook layer as ad-block, so they are bundled.
|
||||||
filters are available.
|
- **Database Viewer Inline Search** — full-text search in the DB viewer via SQLite FTS5. Currently
|
||||||
- **TempTell Persistence** — pin toggle on TempTell tabs so selected tells survive a relog. Tester request from Jingliu.
|
only date and channel filters are available.
|
||||||
- **FontManager Async Refactor** — move `LoadGameSymFontAsync` out of the blocking plugin constructor. Fix cold-start
|
- **TempTell Persistence** — pin toggle on TempTell tabs so selected tells survive a relog. Tester
|
||||||
hitching on first plugin load (low severity; plugin is functional).
|
request from Jingliu.
|
||||||
- **Separate Opacity Active vs. Inactive** — second slider for inactive window opacity. Upstream declines this; we can
|
- **FontManager Async Refactor** — move `LoadGameSymFontAsync` out of the blocking plugin
|
||||||
decide differently here.
|
constructor. Fix cold-start hitching on first plugin load (low severity; plugin is functional).
|
||||||
- **Failed-Tell Notification** — visible message on /tell failure (offline, restricted instance, blacklisted,
|
- **Separate Opacity Active vs. Inactive** — second slider for inactive window opacity. Upstream
|
||||||
world-mismatch) instead of silent failure.
|
declines this; we can decide differently here.
|
||||||
- **Per-Tab Sound Notification** — sound toggle and optionally a custom .wav per tab, with mute-in-combat option.
|
- **Failed-Tell Notification** — visible message on /tell failure (offline, restricted instance,
|
||||||
|
blacklisted, world-mismatch) instead of silent failure.
|
||||||
|
- **Per-Tab Sound Notification** — sound toggle and optionally a custom .wav per tab, with
|
||||||
|
mute-in-combat option.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -265,27 +295,28 @@ the theme engine — both items live on in the mid-term block.
|
|||||||
|
|
||||||
### UX and Tab Management
|
### UX and Tab Management
|
||||||
|
|
||||||
- **Regex Tab Routing** — route plugin output spam into dedicated tabs, auto-sort tells from specific people. Clearly
|
- **Regex Tab Routing** — route plugin output spam into dedicated tabs, auto-sort tells from
|
||||||
scoped against ad-block: routing sorts into views, blocking hides globally.
|
specific people. Clearly scoped against ad-block: routing sorts into views, blocking hides
|
||||||
|
globally.
|
||||||
- **Auto-Detect Duties** — tab switch on duty start via condition flag.
|
- **Auto-Detect Duties** — tab switch on duty start via condition flag.
|
||||||
- **UX Bundle** — vertical tab bar as a layout option, Shift+Mousewheel to scroll tab headers without activating them,
|
- **UX Bundle** — vertical tab bar as a layout option, Shift+Mousewheel to scroll tab headers
|
||||||
global hotkey to close the active tab.
|
without activating them, global hotkey to close the active tab.
|
||||||
- **Configure Tab Title** — configurable tab title format (name / name + abbreviated world / full name / custom),
|
- **Configure Tab Title** — configurable tab title format (name / name + abbreviated world / full
|
||||||
overridable per tab.
|
name / custom), overridable per tab.
|
||||||
- **Name Display Options** — analogous to FFXIV vanilla (full name, first name abbreviated, initials), per-channel
|
- **Name Display Options** — analogous to FFXIV vanilla (full name, first name abbreviated,
|
||||||
override possible.
|
initials), per-channel override possible.
|
||||||
- **Item & Flag Linking** — outgoing: Shift-click on an item/flag sends it to the focused plugin input. Incoming: item
|
- **Item & Flag Linking** — outgoing: Shift-click on an item/flag sends it to the focused plugin
|
||||||
links and map coordinates are clickable.
|
input. Incoming: item links and map coordinates are clickable.
|
||||||
- **Color Currently Selected Input Channel** — tint the channel-selector button in the input bar with the current
|
- **Color Currently Selected Input Channel** — tint the channel-selector button in the input bar
|
||||||
channel colour.
|
with the current channel colour.
|
||||||
- **Plugin-Disclosure Pre-Send Filter** — configurable word/regex list blocks sending with a pre-send confirmation.
|
- **Plugin-Disclosure Pre-Send Filter** — configurable word/regex list blocks sending with a
|
||||||
Protects against accidentally mentioning plugins in public channels.
|
pre-send confirmation. Protects against accidentally mentioning plugins in public channels.
|
||||||
- **Chat Clear on Name Change** — on character name change, migrate or wipe local history; default is wipe for maximum
|
- **Chat Clear on Name Change** — on character name change, migrate or wipe local history; default
|
||||||
privacy.
|
is wipe for maximum privacy.
|
||||||
- **Hide Plugin Window on NG+ Screen** — extend hide logic to cover additional addon names.
|
- **Hide Plugin Window on NG+ Screen** — extend hide logic to cover additional addon names.
|
||||||
- **Kick from Novice Network** — mentor niche; context menu entry with confirmation.
|
- **Kick from Novice Network** — mentor niche; context menu entry with confirmation.
|
||||||
- **Text-to-Speech for /tell** — incoming tells via TTS, optionally per sender, with channel filter and mute-in-combat.
|
- **Text-to-Speech for /tell** — incoming tells via TTS, optionally per sender, with channel filter
|
||||||
Low priority.
|
and mute-in-combat. Low priority.
|
||||||
|
|
||||||
### Distribution and Branding
|
### Distribution and Branding
|
||||||
|
|
||||||
@@ -297,24 +328,29 @@ the theme engine — both items live on in the mid-term block.
|
|||||||
|
|
||||||
## Bug Verifications
|
## Bug Verifications
|
||||||
|
|
||||||
Carried over from the upstream issue tracker; not yet reproduced or verified in Hellion Chat 1.0.0. Will be tested
|
Carried over from the upstream issue tracker; not yet reproduced or verified in Hellion Chat 1.0.0.
|
||||||
against the current state when opportunity allows.
|
Will be tested against the current state when opportunity allows.
|
||||||
|
|
||||||
- **Right-Click Whisper Error** in Field Ops / Special Instances (Eureka, Bozja, Occult Crescent, DRS) — upstream
|
- **Right-Click Whisper Error** in Field Ops / Special Instances (Eureka, Bozja, Occult Crescent,
|
||||||
[#168](https://github.com/Infiziert90/ChatTwo/issues/168). Reply helper appears to swallow the `@World` suffix.
|
DRS) — upstream [#168](https://github.com/Infiziert90/ChatTwo/issues/168). Reply helper appears to
|
||||||
- **FPS Drops with Plugin Active** — upstream [#145](https://github.com/Infiziert90/ChatTwo/issues/145). 10–20 % drop
|
swallow the `@World` suffix.
|
||||||
since upstream v1.29.19.0. v1.0.0 includes several fixes on the suspected paths; repro test against the current state
|
- **FPS Drops with Plugin Active** — upstream
|
||||||
is open.
|
[#145](https://github.com/Infiziert90/ChatTwo/issues/145). 10–20 % drop since upstream v1.29.19.0.
|
||||||
- **Add Blacklist from Plugin Window** — upstream [#140](https://github.com/Infiziert90/ChatTwo/issues/140). Right-click
|
v1.0.0 includes several fixes on the suspected paths; repro test against the current state is
|
||||||
add-to-blacklist throws "Cannot locate character with that name"; works via vanilla chat.
|
open.
|
||||||
- **DB Viewer Column Sort** — State column sorts lexicographically instead of numerically (10 before 2). XIVIM
|
- **Add Blacklist from Plugin Window** — upstream
|
||||||
[#82](https://github.com/NightmareXIV/XIVInstantMessenger/issues/82); repro in Hellion Chat open.
|
[#140](https://github.com/Infiziert90/ChatTwo/issues/140). Right-click add-to-blacklist throws
|
||||||
|
"Cannot locate character with that name"; works via vanilla chat.
|
||||||
|
- **DB Viewer Column Sort** — State column sorts lexicographically instead of numerically (10 before
|
||||||
|
2). XIVIM [#82](https://github.com/NightmareXIV/XIVInstantMessenger/issues/82); repro in Hellion
|
||||||
|
Chat open.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Licence Boundary
|
## Licence Boundary
|
||||||
|
|
||||||
Hellion Chat is licensed under EUPL-1.2. Concept imports from AGPL-3.0 plugins (e.g. XIV Instant Messenger) are
|
Hellion Chat is licensed under EUPL-1.2. Concept imports from AGPL-3.0 plugins (e.g. XIV Instant
|
||||||
architectural inspiration only — no code was ported. Code imports from the upstream codebase are complete as of v1.4.x
|
Messenger) are architectural inspiration only — no code was ported. Code imports from the upstream
|
||||||
because Chat 2 is undergoing a fundamental rework and selective patches are no longer cleanly portable. Status and
|
codebase are complete as of v1.4.x because Chat 2 is undergoing a fundamental rework and selective
|
||||||
rationale in [`UPSTREAM_SYNC.md`](UPSTREAM_SYNC.md).
|
patches are no longer cleanly portable. Status and rationale in
|
||||||
|
[`UPSTREAM_SYNC.md`](UPSTREAM_SYNC.md).
|
||||||
|
|||||||
+41
-33
@@ -4,8 +4,9 @@
|
|||||||
|
|
||||||
# Theme Authoring Guide
|
# Theme Authoring Guide
|
||||||
|
|
||||||
> Built by **Hellion Forge** — the plugin workshop arm of [Hellion Online Media](https://hellion-media.de). HellionChat
|
> Built by **Hellion Forge** — the plugin workshop arm of
|
||||||
> ships with nine built-in themes; this guide walks you through writing your own.
|
> [Hellion Online Media](https://hellion-media.de). HellionChat ships with nine built-in themes;
|
||||||
|
> this guide walks you through writing your own.
|
||||||
|
|
||||||
## TL;DR
|
## TL;DR
|
||||||
|
|
||||||
@@ -23,10 +24,11 @@ That's the whole loop. The rest of this document is reference.
|
|||||||
%APPDATA%\XIVLauncher\pluginConfigs\HellionChat\themes\
|
%APPDATA%\XIVLauncher\pluginConfigs\HellionChat\themes\
|
||||||
```
|
```
|
||||||
|
|
||||||
(or the equivalent path on Linux/macOS — Settings → Themes → "Open themes folder" opens it directly).
|
(or the equivalent path on Linux/macOS — Settings → Themes → "Open themes folder" opens it
|
||||||
|
directly).
|
||||||
|
|
||||||
Each `*.json` file in this folder is loaded as one theme. The `example-theme.json` that HellionChat seeds on first
|
Each `*.json` file in this folder is loaded as one theme. The `example-theme.json` that HellionChat
|
||||||
launch is your starting template.
|
seeds on first launch is your starting template.
|
||||||
|
|
||||||
## File format
|
## File format
|
||||||
|
|
||||||
@@ -60,7 +62,8 @@ Theme JSON has four blocks:
|
|||||||
|
|
||||||
### Color slots
|
### Color slots
|
||||||
|
|
||||||
All values are 6-digit `#RRGGBB` or 8-digit `#RRGGBBAA` hex strings. Six-digit values get an implicit `FF` alpha.
|
All values are 6-digit `#RRGGBB` or 8-digit `#RRGGBBAA` hex strings. Six-digit values get an
|
||||||
|
implicit `FF` alpha.
|
||||||
|
|
||||||
| Slot | Role |
|
| Slot | Role |
|
||||||
| ---------------------------- | ------------------------------------------------------------------------------- |
|
| ---------------------------- | ------------------------------------------------------------------------------- |
|
||||||
@@ -87,7 +90,8 @@ All values are 6-digit `#RRGGBB` or 8-digit `#RRGGBBAA` hex strings. Six-digit v
|
|||||||
|
|
||||||
### Layout slots
|
### Layout slots
|
||||||
|
|
||||||
All values are floats in pixels. `BorderSize` is 0 or 1 (no thicker borders look right with ImGui's edge anti-aliasing).
|
All values are floats in pixels. `BorderSize` is 0 or 1 (no thicker borders look right with ImGui's
|
||||||
|
edge anti-aliasing).
|
||||||
|
|
||||||
| Slot | Typical range | Notes |
|
| Slot | Typical range | Notes |
|
||||||
| ------------------- | ------------- | ------------------------------------------------- |
|
| ------------------- | ------------- | ------------------------------------------------- |
|
||||||
@@ -103,8 +107,8 @@ All values are floats in pixels. `BorderSize` is 0 or 1 (no thicker borders look
|
|||||||
|
|
||||||
### Optional `chatChannels`
|
### Optional `chatChannels`
|
||||||
|
|
||||||
If present, your theme proposes its own chat-channel colors. Property names are `ChatType` enum values
|
If present, your theme proposes its own chat-channel colors. Property names are `ChatType` enum
|
||||||
(case-insensitive). Unknown names are skipped silently — safe for forward-compat.
|
values (case-insensitive). Unknown names are skipped silently — safe for forward-compat.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"chatChannels": {
|
"chatChannels": {
|
||||||
@@ -120,8 +124,9 @@ If present, your theme proposes its own chat-channel colors. Property names are
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The user is asked **once per theme switch** whether to apply these colors — never auto-overwriting existing picks. The
|
The user is asked **once per theme switch** whether to apply these colors — never auto-overwriting
|
||||||
banner shows up only if your suggested colors differ from the user's current `Configuration.ChatColours`.
|
existing picks. The banner shows up only if your suggested colors differ from the user's current
|
||||||
|
`Configuration.ChatColours`.
|
||||||
|
|
||||||
#### Channel-identity rule
|
#### Channel-identity rule
|
||||||
|
|
||||||
@@ -137,25 +142,26 @@ banner shows up only if your suggested colors differ from the user's current `Co
|
|||||||
| FreeCompany | cyan-teal | Guild ops. |
|
| FreeCompany | cyan-teal | Guild ops. |
|
||||||
| NoviceNetwork | lime-green | Mentor channel. |
|
| NoviceNetwork | lime-green | Mentor channel. |
|
||||||
|
|
||||||
A theme can tint these toward its brand family (e.g., a purple theme can shift Tell from `#FF99CC` to `#E090FF`), but
|
A theme can tint these toward its brand family (e.g., a purple theme can shift Tell from `#FF99CC`
|
||||||
**don't** flip them (Tell suddenly green, Yell suddenly cyan). RP groups and combat-spec setups depend on the visual
|
to `#E090FF`), but **don't** flip them (Tell suddenly green, Yell suddenly cyan). RP groups and
|
||||||
hierarchy.
|
combat-spec setups depend on the visual hierarchy.
|
||||||
|
|
||||||
The eight colored built-in themes (Hellion Arctic, Hellion Spectrum, Event Horizon, Crystal Nocturne, Mint Grove, Night
|
The eight colored built-in themes (Hellion Arctic, Hellion Spectrum, Event Horizon, Crystal
|
||||||
Blue, Indigo Violet, Forge Merchantman) all follow this rule — read their source for reference. Chat 2 Klassik
|
Nocturne, Mint Grove, Night Blue, Indigo Violet, Forge Merchantman) all follow this rule — read
|
||||||
intentionally ships without `chatChannels` so the user keeps their existing picks.
|
their source for reference. Chat 2 Klassik intentionally ships without `chatChannels` so the user
|
||||||
|
keeps their existing picks.
|
||||||
|
|
||||||
## Theme families
|
## Theme families
|
||||||
|
|
||||||
Naming convention `<color>-<modifier>` is recommended for theme families. The first member of a family is the
|
Naming convention `<color>-<modifier>` is recommended for theme families. The first member of a
|
||||||
lightest/brightest:
|
family is the lightest/brightest:
|
||||||
|
|
||||||
- `mint-grove` (current built-in, light mint)
|
- `mint-grove` (current built-in, light mint)
|
||||||
- `forest-grove` (planned, dark emerald)
|
- `forest-grove` (planned, dark emerald)
|
||||||
- `moss-grove` (planned, mid muted)
|
- `moss-grove` (planned, mid muted)
|
||||||
|
|
||||||
Code-wise families have no special handling — only the slug naming hints at the relationship. The picker may group
|
Code-wise families have no special handling — only the slug naming hints at the relationship. The
|
||||||
families later, but that's not required.
|
picker may group families later, but that's not required.
|
||||||
|
|
||||||
## Validation and errors
|
## Validation and errors
|
||||||
|
|
||||||
@@ -164,8 +170,8 @@ When HellionChat loads your theme:
|
|||||||
- **Schema mismatch** (`schemaVersion != 1`): theme is skipped, warning written to `/xllog`.
|
- **Schema mismatch** (`schemaVersion != 1`): theme is skipped, warning written to `/xllog`.
|
||||||
- **Missing required field** (e.g., no `slug`): theme is skipped, warning written.
|
- **Missing required field** (e.g., no `slug`): theme is skipped, warning written.
|
||||||
- **Invalid hex** (e.g., `#GGHHII`): theme is skipped, warning written.
|
- **Invalid hex** (e.g., `#GGHHII`): theme is skipped, warning written.
|
||||||
- **Unknown channel name** in `chatChannels`: that one channel is skipped silently, the rest of the theme loads
|
- **Unknown channel name** in `chatChannels`: that one channel is skipped silently, the rest of the
|
||||||
normally.
|
theme loads normally.
|
||||||
|
|
||||||
Check `/xllog` after a plugin reload to see what loaded and what didn't.
|
Check `/xllog` after a plugin reload to see what loaded and what didn't.
|
||||||
|
|
||||||
@@ -177,23 +183,25 @@ Check `/xllog` after a plugin reload to see what loaded and what didn't.
|
|||||||
4. Watch every plugin window (chat, settings, pop-out) and pick something to fix.
|
4. Watch every plugin window (chat, settings, pop-out) and pick something to fix.
|
||||||
5. Tweak. Reload. Repeat.
|
5. Tweak. Reload. Repeat.
|
||||||
|
|
||||||
Tip: the **Settings → Themes** picker shows a mini-mockup per theme — your colors are visible before you switch.
|
Tip: the **Settings → Themes** picker shows a mini-mockup per theme — your colors are visible before
|
||||||
|
you switch.
|
||||||
|
|
||||||
## Sharing themes
|
## Sharing themes
|
||||||
|
|
||||||
Themes are JSON, so sharing is just a file. Drop it into someone's `pluginConfigs/HellionChat/themes/` folder and their
|
Themes are JSON, so sharing is just a file. Drop it into someone's
|
||||||
plugin picks it up on next reload.
|
`pluginConfigs/HellionChat/themes/` folder and their plugin picks it up on next reload.
|
||||||
|
|
||||||
A community theme repository is on the Hellion Forge roadmap. Until then: share via Discord or any pastebin.
|
A community theme repository is on the Hellion Forge roadmap. Until then: share via Discord or any
|
||||||
|
pastebin.
|
||||||
|
|
||||||
## Reference
|
## Reference
|
||||||
|
|
||||||
- `docs/example-theme.json` (seeded automatically on first launch into `pluginConfigs/HellionChat/themes/`) — minimal
|
- `docs/example-theme.json` (seeded automatically on first launch into
|
||||||
valid theme.
|
`pluginConfigs/HellionChat/themes/`) — minimal valid theme.
|
||||||
- The five built-in themes live in source under `HellionChat/Themes/Builtin/`. They are a good reference for Color
|
- The five built-in themes live in source under `HellionChat/Themes/Builtin/`. They are a good
|
||||||
choices that work.
|
reference for Color choices that work.
|
||||||
- [Hellion Online Media branding](https://hellion-media.de) — the Arctic Cyan + Ember Glow palette that drives the
|
- [Hellion Online Media branding](https://hellion-media.de) — the Arctic Cyan + Ember Glow palette
|
||||||
default Hellion Arctic theme.
|
that drives the default Hellion Arctic theme.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+22
-20
@@ -1,7 +1,7 @@
|
|||||||
# Third-party notices
|
# Third-party notices
|
||||||
|
|
||||||
HellionChat ships and depends on a number of third-party components. This document lists them, their licences and which
|
HellionChat ships and depends on a number of third-party components. This document lists them, their
|
||||||
of them touch the network. It is the inventory referenced by `PRIVACY.md`.
|
licences and which of them touch the network. It is the inventory referenced by `PRIVACY.md`.
|
||||||
|
|
||||||
Last reviewed: 2026-05-05 (HellionChat v1.1.0).
|
Last reviewed: 2026-05-05 (HellionChat v1.1.0).
|
||||||
|
|
||||||
@@ -20,11 +20,11 @@ Pinned in `HellionChat/HellionChat.csproj`. Versions reflect the v1.1.0 build.
|
|||||||
| [SixLabors.ImageSharp](https://github.com/SixLabors/ImageSharp) | 3.1.12 | [Six Labors Split License 1.0](https://github.com/SixLabors/ImageSharp/blob/main/LICENSE) (OSI-approved; free for open-source / non-commercial use, commercial licence required for closed-source commercial use) | no | Image decoding for cached emotes. |
|
| [SixLabors.ImageSharp](https://github.com/SixLabors/ImageSharp) | 3.1.12 | [Six Labors Split License 1.0](https://github.com/SixLabors/ImageSharp/blob/main/LICENSE) (OSI-approved; free for open-source / non-commercial use, commercial licence required for closed-source commercial use) | no | Image decoding for cached emotes. |
|
||||||
| [SQLitePCLRaw.lib.e_sqlite3](https://github.com/ericsink/SQLitePCL.raw) | 3.50.3 | MIT | no | Native SQLite binary, explicitly pinned to override the transitive default for CVE-2025-6965 (memory corruption from aggregate-term overflow) and CVE-2025-7709. |
|
| [SQLitePCLRaw.lib.e_sqlite3](https://github.com/ericsink/SQLitePCL.raw) | 3.50.3 | MIT | no | Native SQLite binary, explicitly pinned to override the transitive default for CVE-2025-6965 (memory corruption from aggregate-term overflow) and CVE-2025-7709. |
|
||||||
|
|
||||||
Six Labors note: HellionChat is an EUPL-1.2-licensed open-source project distributed at no cost. Use of ImageSharp 3.x
|
Six Labors note: HellionChat is an EUPL-1.2-licensed open-source project distributed at no cost. Use
|
||||||
under the Six Labors Split License 1.0 is permitted on that basis. Anyone forking HellionChat for closed-source or
|
of ImageSharp 3.x under the Six Labors Split License 1.0 is permitted on that basis. Anyone forking
|
||||||
commercial redistribution should review the
|
HellionChat for closed-source or commercial redistribution should review the
|
||||||
[Six Labors licence terms](https://github.com/SixLabors/ImageSharp/blob/main/LICENSE) and obtain a commercial licence if
|
[Six Labors licence terms](https://github.com/SixLabors/ImageSharp/blob/main/LICENSE) and obtain a
|
||||||
required.
|
commercial licence if required.
|
||||||
|
|
||||||
## SDK and tooling
|
## SDK and tooling
|
||||||
|
|
||||||
@@ -44,23 +44,24 @@ required.
|
|||||||
|
|
||||||
## Upstream code
|
## Upstream code
|
||||||
|
|
||||||
HellionChat is a fork of [Chat 2](https://github.com/Infiziert90/ChatTwo) by Infiziert90 (Infi) and Anna Clemens, also
|
HellionChat is a fork of [Chat 2](https://github.com/Infiziert90/ChatTwo) by Infiziert90 (Infi) and
|
||||||
licensed under EUPL-1.2. The bulk of the code, including the message store architecture, the channel logic, the hook
|
Anna Clemens, also licensed under EUPL-1.2. The bulk of the code, including the message store
|
||||||
system and the ImGui chat window, originates from upstream. See `../NOTICE.md` for the attribution; `UPSTREAM_SYNC.md`
|
architecture, the channel logic, the hook system and the ImGui chat window, originates from
|
||||||
documents the upstream-sync history, including the close of active cherry-picking in the v1.4.x cycle.
|
upstream. See `../NOTICE.md` for the attribution; `UPSTREAM_SYNC.md` documents the upstream-sync
|
||||||
|
history, including the close of active cherry-picking in the v1.4.x cycle.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Components that touch the network
|
## Components that touch the network
|
||||||
|
|
||||||
Of everything listed above, **none** of the bundled or NuGet components opens network connections on their own. All
|
Of everything listed above, **none** of the bundled or NuGet components opens network connections on
|
||||||
outbound traffic is initiated explicitly by HellionChat's own source files and is documented in `PRIVACY.md` under
|
their own. All outbound traffic is initiated explicitly by HellionChat's own source files and is
|
||||||
"Outbound network calls":
|
documented in `PRIVACY.md` under "Outbound network calls":
|
||||||
|
|
||||||
- `HellionChat/EmoteCache.cs` → BetterTTV API + CDN (opt-out via setting)
|
- `HellionChat/EmoteCache.cs` → BetterTTV API + CDN (opt-out via setting)
|
||||||
|
|
||||||
The earlier Square Enix Lodestone font download (`FontManager.cs`) was removed in v1.0.4 — it was a leftover from
|
The earlier Square Enix Lodestone font download (`FontManager.cs`) was removed in v1.0.4 — it was a
|
||||||
upstream's removed webinterface feature and was no longer consumed.
|
leftover from upstream's removed webinterface feature and was no longer consumed.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -72,8 +73,9 @@ To regenerate the dependency inventory after a version bump:
|
|||||||
dotnet list HellionChat.sln package --include-transitive
|
dotnet list HellionChat.sln package --include-transitive
|
||||||
```
|
```
|
||||||
|
|
||||||
The "direct NuGet dependencies" table above only lists direct references. Transitive dependencies pulled in by Dalamud
|
The "direct NuGet dependencies" table above only lists direct references. Transitive dependencies
|
||||||
SDK or by the listed packages are covered by the SDK / package licences and documented by their respective maintainers.
|
pulled in by Dalamud SDK or by the listed packages are covered by the SDK / package licences and
|
||||||
|
documented by their respective maintainers.
|
||||||
|
|
||||||
To re-audit the network-call inventory:
|
To re-audit the network-call inventory:
|
||||||
|
|
||||||
@@ -82,5 +84,5 @@ grep -rn -E "HttpClient|HttpRequest|new Uri\(|https?://" \
|
|||||||
--include="*.cs" HellionChat/
|
--include="*.cs" HellionChat/
|
||||||
```
|
```
|
||||||
|
|
||||||
Any new hit that is not a click-through (`Util.OpenLink`) or a payload-parsing call must be added to `PRIVACY.md` before
|
Any new hit that is not a click-through (`Util.OpenLink`) or a payload-parsing call must be added to
|
||||||
release.
|
`PRIVACY.md` before release.
|
||||||
|
|||||||
+66
-56
@@ -1,93 +1,103 @@
|
|||||||
# Upstream Sync
|
# Upstream Sync
|
||||||
|
|
||||||
HellionChat is a standalone EUPL-1.2 plugin that originated from [Chat 2](https://github.com/Infiziert90/ChatTwo). Since
|
HellionChat is a standalone EUPL-1.2 plugin that originated from
|
||||||
v1.0.0 it lives under its own namespace, IPC channels and source tree. The active cherry-pick pipeline from upstream
|
[Chat 2](https://github.com/Infiziert90/ChatTwo). Since v1.0.0 it lives under its own namespace, IPC
|
||||||
Chat 2 is closed since the v1.4.x cycle.
|
channels and source tree. The active cherry-pick pipeline from upstream Chat 2 is closed since the
|
||||||
|
v1.4.x cycle.
|
||||||
|
|
||||||
This document covers what that means, why I closed it, and what stays in place.
|
This document covers what that means, why I closed it, and what stays in place.
|
||||||
|
|
||||||
## A Word on Intent
|
## A Word on Intent
|
||||||
|
|
||||||
HellionChat is not trying to replace Chat 2. I build it for myself, and maybe for people who want the same things I do:
|
HellionChat is not trying to replace Chat 2. I build it for myself, and maybe for people who want
|
||||||
a privacy-first chat plugin with tighter defaults and no remote-access surface. If that is not you, Chat 2 is the better
|
the same things I do: a privacy-first chat plugin with tighter defaults and no remote-access
|
||||||
choice and a well-maintained project.
|
surface. If that is not you, Chat 2 is the better choice and a well-maintained project.
|
||||||
|
|
||||||
I am available to Infi if he ever has questions about HellionChat or how I have diverged from the upstream code. What I
|
I am available to Infi if he ever has questions about HellionChat or how I have diverged from the
|
||||||
will not do is interfere with Chat 2's direction or push unsolicited opinions into his project.
|
upstream code. What I will not do is interfere with Chat 2's direction or push unsolicited opinions
|
||||||
|
into his project.
|
||||||
|
|
||||||
Long-term compatibility between Chat 2 and HellionChat is not guaranteed and, frankly, not technically possible. I am
|
Long-term compatibility between Chat 2 and HellionChat is not guaranteed and, frankly, not
|
||||||
building a new UI from scratch and making deliberate architectural decisions that pull in a different direction. Some
|
technically possible. I am building a new UI from scratch and making deliberate architectural
|
||||||
upstream patches will simply stop applying cleanly and that is expected.
|
decisions that pull in a different direction. Some upstream patches will simply stop applying
|
||||||
|
cleanly and that is expected.
|
||||||
|
|
||||||
## Why Cherry-Picking Stopped in v1.4.x
|
## Why Cherry-Picking Stopped in v1.4.x
|
||||||
|
|
||||||
Two things converged:
|
Two things converged:
|
||||||
|
|
||||||
1. **Chat 2 is in a rework cycle.** Infi mentioned directly that parts of ChatTwo are being reworked and "stuff may not
|
1. **Chat 2 is in a rework cycle.** Infi mentioned directly that parts of ChatTwo are being reworked
|
||||||
be able to be cherry picked anymore." Once the upstream code paths I would pull from no longer exist in the same
|
and "stuff may not be able to be cherry picked anymore." Once the upstream code paths I would
|
||||||
shape, `git cherry-pick` stops being a meaningful tool — what would land would not be the change Infi wrote, it would
|
pull from no longer exist in the same shape, `git cherry-pick` stops being a meaningful tool —
|
||||||
be a hand-port of his concept.
|
what would land would not be the change Infi wrote, it would be a hand-port of his concept.
|
||||||
2. **HellionChat has drifted enough that selective patches require adaptation anyway.** The UI is being rebuilt, the
|
2. **HellionChat has drifted enough that selective patches require adaptation anyway.** The UI is
|
||||||
theme engine sits on top of HellionStyle which has no upstream equivalent, the privacy filter changes how messages
|
being rebuilt, the theme engine sits on top of HellionStyle which has no upstream equivalent, the
|
||||||
flow through MessageManager. Even before the rework was announced, more and more upstream patches needed adaptation
|
privacy filter changes how messages flow through MessageManager. Even before the rework was
|
||||||
rather than a clean apply.
|
announced, more and more upstream patches needed adaptation rather than a clean apply.
|
||||||
|
|
||||||
Together those two points mean continuing to call this an "active cherry-pick pipeline" was no longer honest. So I
|
Together those two points mean continuing to call this an "active cherry-pick pipeline" was no
|
||||||
closed it.
|
longer honest. So I closed it.
|
||||||
|
|
||||||
## What Closing the Pipeline Means in Practice
|
## What Closing the Pipeline Means in Practice
|
||||||
|
|
||||||
- The `upstream` git remote was removed locally on 2026-05-08. Anyone setting up a fresh clone does **not** add it back.
|
- The `upstream` git remote was removed locally on 2026-05-08. Anyone setting up a fresh clone does
|
||||||
- New commits will not carry `(cherry picked from commit ...)` trailers. Anything that originates from Chat 2 from this
|
**not** add it back.
|
||||||
point forward will be a hand-port at most, and it gets called out as such in its own commit message and in the
|
- New commits will not carry `(cherry picked from commit ...)` trailers. Anything that originates
|
||||||
relevant source comments.
|
from Chat 2 from this point forward will be a hand-port at most, and it gets called out as such in
|
||||||
- The existing cherry-pick trail stays in the git history exactly as it is. Every `(cherry picked from commit ...)` line
|
its own commit message and in the relevant source comments.
|
||||||
that was added with `-x` in earlier releases remains intact; that is the attribution paper trail and removing it would
|
- The existing cherry-pick trail stays in the git history exactly as it is. Every
|
||||||
be wrong.
|
`(cherry picked from commit ...)` line that was added with `-x` in earlier releases remains
|
||||||
|
intact; that is the attribution paper trail and removing it would be wrong.
|
||||||
|
|
||||||
## What Does Not Change
|
## What Does Not Change
|
||||||
|
|
||||||
- **EUPL-1.2 anchor lines in source files.** Files that originated from Chat 2 keep their licence headers and any "based
|
- **EUPL-1.2 anchor lines in source files.** Files that originated from Chat 2 keep their licence
|
||||||
on Infiziert90/ChatTwo" notice exactly as they are. The licence obligations under EUPL-1.2 do not lapse because
|
headers and any "based on Infiziert90/ChatTwo" notice exactly as they are. The licence obligations
|
||||||
cherry-picking stopped.
|
under EUPL-1.2 do not lapse because cherry-picking stopped.
|
||||||
- **NOTICE.md** stays canonical. Attribution to Infi and Anna for the message store, channel logic, hook system, ImGui
|
- **NOTICE.md** stays canonical. Attribution to Infi and Anna for the message store, channel logic,
|
||||||
chat window and the localisation infrastructure remains the foundation statement of this fork.
|
hook system, ImGui chat window and the localisation infrastructure remains the foundation
|
||||||
- **README acknowledgements.** The Acknowledgements section in `README.md`, the maintainer thanks in the About tab, and
|
statement of this fork.
|
||||||
the `Language.*.resx` Crowdin translator credit list all stay as they are.
|
- **README acknowledgements.** The Acknowledgements section in `README.md`, the maintainer thanks in
|
||||||
- **The original `Language.*.resx` files** remain in the source tree in their last upstream-sync state. They are the
|
the About tab, and the `Language.*.resx` Crowdin translator credit list all stay as they are.
|
||||||
work of the Chat 2 Crowdin community and the existing translations stay valuable. They will not receive automatic
|
- **The original `Language.*.resx` files** remain in the source tree in their last upstream-sync
|
||||||
upstream updates anymore — see CONTRIBUTING.md for what that means for translators.
|
state. They are the work of the Chat 2 Crowdin community and the existing translations stay
|
||||||
|
valuable. They will not receive automatic upstream updates anymore — see CONTRIBUTING.md for what
|
||||||
|
that means for translators.
|
||||||
|
|
||||||
## What Could Re-Open Later
|
## What Could Re-Open Later
|
||||||
|
|
||||||
If Chat 2's rework lands and stabilises, and there is a piece of upstream code that I genuinely want in HellionChat, the
|
If Chat 2's rework lands and stabilises, and there is a piece of upstream code that I genuinely want
|
||||||
path forward is **study and re-implement**, not cherry-pick. That means:
|
in HellionChat, the path forward is **study and re-implement**, not cherry-pick. That means:
|
||||||
|
|
||||||
- Read the upstream change, understand the design, port the concept to HellionChat's actual code paths.
|
- Read the upstream change, understand the design, port the concept to HellionChat's actual code
|
||||||
- Credit the upstream author in the commit message and, if the ported code is non-trivial, in a source-file comment.
|
paths.
|
||||||
|
- Credit the upstream author in the commit message and, if the ported code is non-trivial, in a
|
||||||
|
source-file comment.
|
||||||
- Pre-clear with Infi if the port is large enough to warrant a conversation.
|
- Pre-clear with Infi if the port is large enough to warrant a conversation.
|
||||||
|
|
||||||
This is heavier than `git cherry-pick -x` and that is the point. Cherry-picking was light because both codebases shared
|
This is heavier than `git cherry-pick -x` and that is the point. Cherry-picking was light because
|
||||||
structure; once they do not, the proper attribution costs a real conversation rather than a flag on a git command.
|
both codebases shared structure; once they do not, the proper attribution costs a real conversation
|
||||||
|
rather than a flag on a git command.
|
||||||
|
|
||||||
## Contributing Back
|
## Contributing Back
|
||||||
|
|
||||||
HellionChat benefits from Chat 2's work, so I try to give something back where I can. If I fix a bug or improve
|
HellionChat benefits from Chat 2's work, so I try to give something back where I can. If I fix a bug
|
||||||
something that would be useful to Chat 2 and is not HellionChat-specific, I submit a good-will PR to
|
or improve something that would be useful to Chat 2 and is not HellionChat-specific, I submit a
|
||||||
[Infiziert90/ChatTwo](https://github.com/Infiziert90/ChatTwo).
|
good-will PR to [Infiziert90/ChatTwo](https://github.com/Infiziert90/ChatTwo).
|
||||||
|
|
||||||
A few things to note about that process:
|
A few things to note about that process:
|
||||||
|
|
||||||
- Good-will PRs are validated in a separate fork first to make sure the fix stands on its own without HellionChat
|
- Good-will PRs are validated in a separate fork first to make sure the fix stands on its own
|
||||||
context.
|
without HellionChat context.
|
||||||
- They are written by hand. No AI-generated code goes to Infi's project. He did not ask for Pair-level AI involvement
|
- They are written by hand. No AI-generated code goes to Infi's project. He did not ask for
|
||||||
and I will not push that decision onto his codebase.
|
Pair-level AI involvement and I will not push that decision onto his codebase.
|
||||||
- This is not guaranteed for every change, only where it makes sense and where I am confident the fix is clean and
|
- This is not guaranteed for every change, only where it makes sense and where I am confident the
|
||||||
self-contained.
|
fix is clean and self-contained.
|
||||||
- Whether it gets accepted is Infi's call, and a "no" is fine.
|
- Whether it gets accepted is Infi's call, and a "no" is fine.
|
||||||
|
|
||||||
## When Upstream Takes a Direction I Cannot Follow
|
## When Upstream Takes a Direction I Cannot Follow
|
||||||
|
|
||||||
If a future Chat 2 release breaks compatibility with the HellionChat privacy philosophy in a way that cannot be resolved
|
If a future Chat 2 release breaks compatibility with the HellionChat privacy philosophy in a way
|
||||||
(mandatory cloud sync, removal of the local message store, an incompatible licence change), HellionChat continues from
|
that cannot be resolved (mandatory cloud sync, removal of the local message store, an incompatible
|
||||||
where it is. The inherited history stays under EUPL-1.2 and stays attributed.
|
licence change), HellionChat continues from where it is. The inherited history stays under EUPL-1.2
|
||||||
|
and stays attributed.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/dotnet-tools.json",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"isRoot": true,
|
"isRoot": true,
|
||||||
"tools": {
|
"tools": {
|
||||||
|
|||||||
@@ -27,6 +27,6 @@ dotnet csharpier check HellionChat/
|
|||||||
echo "==> preflight: Block F — markdownlint"
|
echo "==> preflight: Block F — markdownlint"
|
||||||
# npx --yes avoids a global install; first run caches into ~/.npm/_npx/.
|
# npx --yes avoids a global install; first run caches into ~/.npm/_npx/.
|
||||||
# Subsequent runs are sub-second.
|
# Subsequent runs are sub-second.
|
||||||
npx --yes markdownlint-cli2 "**/*.md" "#node_modules" "#bin" "#obj" "#.claude"
|
npx --yes markdownlint-cli2 "**/*.md" "#node_modules" "#bin" "#obj" "#.claude" "#CLAUDE.md"
|
||||||
|
|
||||||
echo "==> preflight: ALL GREEN"
|
echo "==> preflight: ALL GREEN"
|
||||||
|
|||||||
Reference in New Issue
Block a user