feat(branding): replace ASCII fox banner with embedded image
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
using Dalamud.Interface.Textures;
|
||||
|
||||
namespace HellionChat.Branding;
|
||||
|
||||
// UI sibling of HellionForgeAscii.FoxMini: the embedded Hellion Forge fox
|
||||
// banner PNG. Uses ITextureProvider.GetFromManifestResource, a "Get" shared
|
||||
// texture, so Dalamud owns the cache and lifetime. No manual dispose, no async
|
||||
// handling in the plugin. Static to mirror HellionForgeAscii (zero injectable
|
||||
// deps; Plugin.TextureProvider is a static [PluginService]).
|
||||
internal static class FoxBannerTexture
|
||||
{
|
||||
private const string ResourceName = "HellionChat.Branding.fox-banner.png";
|
||||
|
||||
// Resolved fresh on every access. Dalamud keeps the shared texture cached
|
||||
// internally and decodes it asynchronously, so GetWrapOrDefault() returns
|
||||
// null for the first few frames until the decode finishes.
|
||||
public static ISharedImmediateTexture Shared =>
|
||||
Plugin.TextureProvider.GetFromManifestResource(
|
||||
typeof(FoxBannerTexture).Assembly,
|
||||
ResourceName
|
||||
);
|
||||
}
|
||||
@@ -1,25 +1,18 @@
|
||||
namespace HellionChat.Branding;
|
||||
|
||||
// Lazy-loaded provenance art that ships embedded with the DLL. Two
|
||||
// variants:
|
||||
// Lazy-loaded ASCII art that ships embedded with the DLL.
|
||||
//
|
||||
// - FoxBanner: the full-size silhouette with "Hellion Forge" inside
|
||||
// the body — rendered in the first-run wizard and the Information
|
||||
// tab as a small "about the makers" anchor.
|
||||
// - FoxMini: the four-line fox-head + curly-tail that gets stitched
|
||||
// into the DI-logger bootstrap line so an xllog reader sees the
|
||||
// same signature on every plugin load.
|
||||
//
|
||||
// Both files live as embedded resources under HellionChat.Branding.* so
|
||||
// the plugin DLL is self-contained — no on-disk asset lookup that could
|
||||
// The file lives as an embedded resource under HellionChat.Branding.* so
|
||||
// the plugin DLL is self-contained; no on-disk asset lookup that could
|
||||
// silently miss after a partial deploy.
|
||||
internal static class HellionForgeAscii
|
||||
{
|
||||
private static string? _foxBanner;
|
||||
private static string? _foxMini;
|
||||
|
||||
public static string FoxBanner => _foxBanner ??= Load("HellionChat.Branding.fox-banner.txt");
|
||||
|
||||
public static string FoxMini => _foxMini ??= Load("HellionChat.Branding.fox-mini.txt");
|
||||
|
||||
private static string Load(string resourceName)
|
||||
|
||||
@@ -58,8 +58,8 @@
|
||||
<EmbeddedResource Include="Resources\Inter-OFL.txt">
|
||||
<LogicalName>Inter-OFL.txt</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Resources\Branding\fox-banner.txt">
|
||||
<LogicalName>HellionChat.Branding.fox-banner.txt</LogicalName>
|
||||
<EmbeddedResource Include="Resources\Branding\fox-banner.png">
|
||||
<LogicalName>HellionChat.Branding.fox-banner.png</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Resources\Branding\fox-mini.txt">
|
||||
<LogicalName>HellionChat.Branding.fox-mini.txt</LogicalName>
|
||||
|
||||
@@ -337,6 +337,7 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
new SelfTests.FontPushSmokeStep(this),
|
||||
new SelfTests.WizardStateSmokeStep(this),
|
||||
new SelfTests.QuickPickerSelfTestStep(this),
|
||||
new SelfTests.FoxBannerTextureSmokeStep(this),
|
||||
]);
|
||||
|
||||
// Re-surface the wizard for existing users when a major UX
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 419 KiB |
@@ -1,68 +0,0 @@
|
||||
.:;+xXXX$$$$$$$$XXx+;:
|
||||
.X$+ .;+X$$$$$$$$$$$$$$$$$$$$$$$$$$$x:
|
||||
;$xx$$X+:... .....::+X$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$;.
|
||||
X$; .:+xXXX$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$X:
|
||||
$$; :++xX$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$X;
|
||||
$$x. .+$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.
|
||||
x$$; ;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$X+;::::::;x$$$$$:
|
||||
:$$$; .+$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$X+:. .+$$$$$$$$$X+;;:
|
||||
;$$$+. :X$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$X;: :$$$$$$$$$$$$$$$$X;.
|
||||
.+$$$X: ..;X$$$$$$$$$$$$$$$$$$$$$$$$$$X;.. :$$$$$$$$$$$$$$$$$$$$X:
|
||||
;$$$$$X+::::+X$$$$$$$$$$$$$$$$$$$$$X;. .$$$$$$$$$$$$$$$$$$$$$$$X;
|
||||
+$$$$$$$$$$$$$$$$$$$$$$$$$$$$X+: Hellion Forge x$$$$$$$$$$$$$$$$$$$$$$$$$X:
|
||||
.;x$$$$$$$$$$$$$$$$$$$$$x;: .X$$$$$$$$$$$$$$$$$$$$$$$$$$$+
|
||||
.;+$$$$$$$$$$X+;:.. .X$$$$$$$$$$$$$$$$$$$$$$$$$$$$+
|
||||
.X$$$$$$$$$$$$$$$$$$$$$$$$$$$$$;
|
||||
.X$$$$$$$$$$$$$$$$$$$$$$$$$$$$$X
|
||||
x$$$$$$$$$$$$$$$$$$$$$$$$$$$$$X
|
||||
;$$$$$$xx$$$$$$$$$$$$$$$$$$$$$x
|
||||
.$$$$$$x+$$$$$$$$$$$$$$$$$$$$$x
|
||||
:+X$$$$$$X;$$$$$$$$$$$$$$$$$$$$$$:
|
||||
;$$$$$$$$$$;$$$$$$$$$$$$$$$$$$$$$$X.
|
||||
+$$$$$$$$$$;x$$$$$$$$$$$$$$$$$$$$$$+
|
||||
x$$$$$$$$$$:$$$$$$$$$$$$$$$$$$$$$$X:
|
||||
.X$$$$$$$$$.:$$$$$$$$$$$$$$$$$$$$$$;
|
||||
:X$$X;;;;: .$$$$$$$$$$$$$$$$$$$$$$X.
|
||||
.$$$$X .$$$$$$$$$$$$$$$$$$$$$$$:
|
||||
.$$$$+ .X$$$$$$$$$$$$$$$$$$$$$$;
|
||||
;$$$$: .X$$$$$$$$$$$$$$$$$$$$$$x
|
||||
:X$$$+ .$$$$$$$$$$$$$$$$$$$$$$$X
|
||||
+$$$x :$$$$$$$$$$$$$$$$$$$$$$$X
|
||||
;$$X: $$$$$$$$$$$$$$$$$$$$$$$$X
|
||||
x$$$$$$$$$$$$$$$$$$$$$$$$X
|
||||
+$$$$$$$$$$$$$$$$$$$$$$$$$+
|
||||
.+$$$$$$$$$$$$$$$$$$$$$$$$$$;
|
||||
. ;$$$$$$$$$$$$$$$$$$$$$$$$$$$$:
|
||||
:X$x$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
|
||||
.XX$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$+
|
||||
;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$+$;
|
||||
.. ++X$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$:+$:
|
||||
:$$+. ;$$$$$$$$$$$$$$X$$$$$$$$$$$$$$$$$$$$$;:$$+
|
||||
.x+X$X: X$$$$$$$$$$x::;:;$$$$$$$$$$$$$$$$$$X: ;$X.
|
||||
:X.x$$$:.::::::;x+:X$$$$;$$$$$$$$$$$$$$$$$$: :X;
|
||||
:x.x$$$$$$$$$$$$$$$$$;;$:$$$$$$$$$$$$$$$$$: :$+
|
||||
:Xx$$$$$$$$$$$$$$$$$: ;X;$$$$$$$$$$$$$$$$: .+$$;
|
||||
;$$$$$$$$$$$$$$$$$$; .X+X$$$$$$$$$$$$$$$+ .+$+.
|
||||
+$$$$$$$$$$$$$$$$$$$$$$$;+$$$$$$$$$$$$$$X: .+X:
|
||||
+$$$$$$$$$$$$$$$$$$$$$$$$$+:$$$$$$$$$$$$$+.+$+.
|
||||
;$$$$$$$$$$$$$$$$$$$$$$$$$$$X;$$$$$$$$$$$$$$X:
|
||||
+X: .:X$$$$$$$$x+++x$$$$$$$$;:X$$$$$$$$$$$X:
|
||||
:x.;$;+$$$$$:. :X$$$$X :$$$$$$$$$$X:
|
||||
;x :X$$$; .x$$x X$$; .:+.$$$$$$$$$$x
|
||||
xx.X$$X: X$;.:$X:.X$$$$$$$$$:
|
||||
+$$$$X. ;$;::: .$$$$$$$$$:
|
||||
;$$$; :+X$$$$XX$; X$$$$$$$$:
|
||||
;$$X: .:x$x$$$$$X. x$$$$$$$$:
|
||||
:X$X: :+x; :$$$$$: +$$$$$$$X:
|
||||
:++$X+xXX;. +$$$$. +$$$$$$$+.
|
||||
... .X$$$X. +$$$$$$$:
|
||||
;$$$$; .X$$$$$$x.
|
||||
;$$X; :X$$$$$$;
|
||||
;$$$$$$x.
|
||||
.X$$$$$$;
|
||||
;$$$$$$+
|
||||
+$$$$$;
|
||||
:X$$$$;.
|
||||
;$$$$+.
|
||||
.x$$$X:
|
||||
.+$$X;
|
||||
@@ -0,0 +1,47 @@
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Plugin.SelfTest;
|
||||
using HellionChat.Branding;
|
||||
|
||||
namespace HellionChat.SelfTests;
|
||||
|
||||
// Verifies the embedded fox-banner PNG decodes into a usable texture. The load
|
||||
// is async, so the step returns Waiting until Dalamud finishes the decode and
|
||||
// the self-test runner re-polls. A decode or resource error is a build defect
|
||||
// and fails the step hard. The resource lives in the DLL, it cannot be a
|
||||
// runtime miss.
|
||||
internal sealed class FoxBannerTextureSmokeStep : ISelfTestStep
|
||||
{
|
||||
private readonly Plugin plugin;
|
||||
|
||||
public FoxBannerTextureSmokeStep(Plugin plugin)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public string Name => "Hellion Chat - Fox banner texture smoke";
|
||||
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
if (!FoxBannerTexture.Shared.TryGetWrap(out var wrap, out var ex))
|
||||
{
|
||||
if (ex is not null)
|
||||
{
|
||||
ImGui.Text($"Fox banner load failed: {ex.Message}");
|
||||
return SelfTestStepResult.Fail;
|
||||
}
|
||||
|
||||
ImGui.Text("Fox banner still loading...");
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
if (wrap.Size.X <= 0 || wrap.Size.Y <= 0)
|
||||
{
|
||||
ImGui.Text($"Fox banner has degenerate size {wrap.Size}");
|
||||
return SelfTestStepResult.Fail;
|
||||
}
|
||||
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
public void CleanUp() { }
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using Dalamud.Interface.Windowing;
|
||||
using HellionChat.Branding;
|
||||
@@ -171,24 +172,20 @@ public sealed class FirstRunWizard : Window
|
||||
ImGui.TextUnformatted(HellionStrings.Wizard_Step1_Title);
|
||||
ImGui.Spacing();
|
||||
|
||||
// Banner is opt-in: the full silhouette dominates the wizard window
|
||||
// at the default size, so the TreeNode is folded by default and the
|
||||
// onboarding copy stays the primary focus. Mirrors the pre-rewrite
|
||||
// collapsible anchor from v1.5.1.
|
||||
using (var tree = ImRaii.TreeNode("Hellion Forge"))
|
||||
// Fox-banner image: the embedded Hellion Forge fox artwork, replacing
|
||||
// the ASCII FoxBanner. Async load renders nothing until the texture is
|
||||
// ready (a few frames). No theme tinting, the fox keeps its identity.
|
||||
var banner = FoxBannerTexture.Shared.GetWrapOrDefault();
|
||||
if (banner is not null)
|
||||
{
|
||||
if (tree.Success)
|
||||
{
|
||||
using (Plugin.Interface.UiBuilder.MonoFontHandle.Push())
|
||||
{
|
||||
// CalcTextSize must run inside the MonoFont push so the
|
||||
// measurement matches the glyph width actually used for
|
||||
// rendering.
|
||||
var bannerSize = ImGui.CalcTextSize(HellionForgeAscii.FoxBanner);
|
||||
ImGui.SetCursorPosX((ImGui.GetContentRegionAvail().X - bannerSize.X) * 0.5f);
|
||||
ImGui.TextUnformatted(HellionForgeAscii.FoxBanner);
|
||||
}
|
||||
}
|
||||
var height = 120f * ImGuiHelpers.GlobalScale;
|
||||
var width = height * banner.Size.X / banner.Size.Y;
|
||||
// Anchor the centering offset to the current cursor X. Avoids a
|
||||
// negative position if the banner is ever wider than the region.
|
||||
var offsetX = (ImGui.GetContentRegionAvail().X - width) * 0.5f;
|
||||
if (offsetX > 0f)
|
||||
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + offsetX);
|
||||
ImGui.Image(banner.Handle, new Vector2(width, height));
|
||||
}
|
||||
|
||||
ImGui.Spacing();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Numerics;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Colors;
|
||||
@@ -68,18 +69,15 @@ internal sealed class Information : ISettingsTab
|
||||
DrawChangelogSection();
|
||||
}
|
||||
|
||||
// Provenance anchor — folded by default so the tab opens to the
|
||||
// version-info section as before. Expands to show the full Hellion
|
||||
// Forge silhouette in monospace.
|
||||
private void DrawHellionForgeSection()
|
||||
{
|
||||
using var tree = ImRaii.TreeNode("Hellion Forge");
|
||||
if (!tree.Success)
|
||||
var banner = FoxBannerTexture.Shared.GetWrapOrDefault();
|
||||
if (banner is null)
|
||||
return;
|
||||
|
||||
using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false))
|
||||
using (Plugin.Interface.UiBuilder.MonoFontHandle.Push())
|
||||
ImGui.TextUnformatted(HellionForgeAscii.FoxBanner);
|
||||
var height = 120f * ImGuiHelpers.GlobalScale;
|
||||
var width = height * banner.Size.X / banner.Size.Y;
|
||||
ImGui.Image(banner.Handle, new Vector2(width, height));
|
||||
}
|
||||
|
||||
private void DrawVersionInfoSection()
|
||||
|
||||
Reference in New Issue
Block a user