chore: housekeeping — linter & formatter setup
Add .prettierrc.json, .markdownlint.json, .yamllint.yaml, .gitattributes Run CSharpier, Prettier and markdownlint across the entire codebase. No logic changes — formatting, using order and line endings only.
This commit is contained in:
+212
-102
@@ -3,17 +3,17 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using HellionChat.Ipc;
|
||||
using HellionChat.Resources;
|
||||
using HellionChat.Ui;
|
||||
using HellionChat.Util;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Interface.ImGuiFileDialog;
|
||||
using Dalamud.Interface.Windowing;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Interface.ImGuiFileDialog;
|
||||
using HellionChat.Ipc;
|
||||
using HellionChat.Resources;
|
||||
using HellionChat.Ui;
|
||||
using HellionChat.Util;
|
||||
|
||||
namespace HellionChat;
|
||||
|
||||
@@ -22,27 +22,68 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
{
|
||||
public const string PluginName = "Hellion Chat";
|
||||
|
||||
[PluginService] public static IPluginLog Log { get; private set; } = null!;
|
||||
[PluginService] public static IDalamudPluginInterface Interface { get; private set; } = null!;
|
||||
[PluginService] public static IChatGui ChatGui { get; private set; } = null!;
|
||||
[PluginService] public static IClientState ClientState { get; private set; } = null!;
|
||||
[PluginService] public static ICommandManager CommandManager { get; private set; } = null!;
|
||||
[PluginService] public static ICondition Condition { get; private set; } = null!;
|
||||
[PluginService] public static IDataManager DataManager { get; private set; } = null!;
|
||||
[PluginService] public static IFramework Framework { get; private set; } = null!;
|
||||
[PluginService] public static IGameGui GameGui { get; private set; } = null!;
|
||||
[PluginService] public static IKeyState KeyState { get; private set; } = null!;
|
||||
[PluginService] public static IObjectTable ObjectTable { get; private set; } = null!;
|
||||
[PluginService] public static IPartyList PartyList { get; private set; } = null!;
|
||||
[PluginService] public static ITargetManager TargetManager { get; private set; } = null!;
|
||||
[PluginService] public static ITextureProvider TextureProvider { get; private set; } = null!;
|
||||
[PluginService] public static IGameInteropProvider GameInteropProvider { get; private set; } = null!;
|
||||
[PluginService] public static IGameConfig GameConfig { get; private set; } = null!;
|
||||
[PluginService] public static INotificationManager Notification { get; private set; } = null!;
|
||||
[PluginService] public static IAddonLifecycle AddonLifecycle { get; private set; } = null!;
|
||||
[PluginService] public static IPlayerState PlayerState { get; private set; } = null!;
|
||||
[PluginService] public static ISeStringEvaluator Evaluator { get; private set; } = null!;
|
||||
[PluginService] public static ISelfTestRegistry SelfTestRegistry { get; private set; } = null!;
|
||||
[PluginService]
|
||||
public static IPluginLog Log { get; private set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
public static IDalamudPluginInterface Interface { get; private set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
public static IChatGui ChatGui { get; private set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
public static IClientState ClientState { get; private set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
public static ICommandManager CommandManager { get; private set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
public static ICondition Condition { get; private set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
public static IDataManager DataManager { get; private set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
public static IFramework Framework { get; private set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
public static IGameGui GameGui { get; private set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
public static IKeyState KeyState { get; private set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
public static IObjectTable ObjectTable { get; private set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
public static IPartyList PartyList { get; private set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
public static ITargetManager TargetManager { get; private set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
public static ITextureProvider TextureProvider { get; private set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
public static IGameInteropProvider GameInteropProvider { get; private set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
public static IGameConfig GameConfig { get; private set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
public static INotificationManager Notification { get; private set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
public static IAddonLifecycle AddonLifecycle { get; private set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
public static IPlayerState PlayerState { get; private set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
public static ISeStringEvaluator Evaluator { get; private set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
public static ISelfTestRegistry SelfTestRegistry { get; private set; } = null!;
|
||||
|
||||
public static Configuration Config = null!;
|
||||
public static FileDialogManager FileDialogManager { get; private set; } = null!;
|
||||
@@ -136,8 +177,9 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
if (Config.Version < 16)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"HellionChat v1.4.3 requires config schema v16, got v{Config.Version}. " +
|
||||
"Please install v1.4.2 first to migrate the configuration, then upgrade to v1.4.3.");
|
||||
$"HellionChat v1.4.3 requires config schema v16, got v{Config.Version}. "
|
||||
+ "Please install v1.4.2 first to migrate the configuration, then upgrade to v1.4.3."
|
||||
);
|
||||
}
|
||||
|
||||
// Hellion Chat — Auto-Tell-Tabs Defense-in-Depth. SaveConfig
|
||||
@@ -219,13 +261,15 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
// Auto-Tell-Tabs subscribes to MessageManager.MessageProcessed for
|
||||
// live tells and to ClientState.Logout for cleanup; needs the live
|
||||
// store handed in at construction.
|
||||
AutoTellTabsService = new AutoTellTabsService(this, MessageManager, MessageManager.Store);
|
||||
AutoTellTabsService = new AutoTellTabsService(
|
||||
this,
|
||||
MessageManager,
|
||||
MessageManager.Store
|
||||
);
|
||||
AutoTellTabsService.Initialize();
|
||||
|
||||
// SelfTest steps poll Active per frame and need the registry wired.
|
||||
SelfTestRegistry.RegisterTestSteps([
|
||||
new SelfTests.ThemeSwitchSelfTestStep(this),
|
||||
]);
|
||||
SelfTestRegistry.RegisterTestSteps([new SelfTests.ThemeSwitchSelfTestStep(this)]);
|
||||
|
||||
ChatLogWindow = new ChatLogWindow(this);
|
||||
SettingsWindow = new SettingsWindow(this);
|
||||
@@ -268,14 +312,14 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
Interface.UiBuilder.DisableCutsceneUiHide = true;
|
||||
Interface.UiBuilder.DisableGposeUiHide = true;
|
||||
|
||||
#if !DEBUG
|
||||
#if !DEBUG
|
||||
// Fire-and-forget on a worker thread. The first auto-translate use of
|
||||
// a session may have a sub-second hitch if the cache hasn't filled yet,
|
||||
// but that's preferable to making every user wait ~300 ms during
|
||||
// plugin load for a cache they may never touch. ChatTwo (upstream)
|
||||
// does this sync; we trade load-time for first-use latency.
|
||||
_ = Task.Run(AutoTranslate.PreloadCache, cancellationToken);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
@@ -296,8 +340,13 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
// Mirror the v1.4.0 load-failure recovery: hand off to DisposeAsync
|
||||
// so partially-built services are torn down. Swallow the cleanup
|
||||
// exception so the original load failure stays the visible cause.
|
||||
try { await DisposeAsync().ConfigureAwait(false); }
|
||||
catch { /* keep original failure */ }
|
||||
try
|
||||
{
|
||||
await DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{ /* keep original failure */
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@@ -324,14 +373,17 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
|
||||
// v1.4.0 F5.3 — flush a pending DeferredSave before service teardown,
|
||||
// since FrameworkUpdate just got unsubscribed and won't fire it.
|
||||
failure = CaptureFailure(failure, () =>
|
||||
{
|
||||
if (DeferredSaveFrames >= 0)
|
||||
failure = CaptureFailure(
|
||||
failure,
|
||||
() =>
|
||||
{
|
||||
SaveConfig();
|
||||
DeferredSaveFrames = -1;
|
||||
if (DeferredSaveFrames >= 0)
|
||||
{
|
||||
SaveConfig();
|
||||
DeferredSaveFrames = -1;
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
// Auto-Tell-Tabs unsubscribes from MessageProcessed before MessageManager
|
||||
// goes away. Pure-memory cleanup, no framework-thread requirement.
|
||||
@@ -342,7 +394,10 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
// framework-block so the worker threads are quiesced first.
|
||||
if (MessageManager is not null)
|
||||
{
|
||||
failure = await CaptureFailureAsync(failure, () => MessageManager.DisposeAsync().AsTask())
|
||||
failure = await CaptureFailureAsync(
|
||||
failure,
|
||||
() => MessageManager.DisposeAsync().AsTask()
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@@ -354,32 +409,37 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
// behind it; mirrors Lightless DisposeFrameworkBoundServicesAsync.
|
||||
try
|
||||
{
|
||||
await Framework.RunOnFrameworkThread(() =>
|
||||
{
|
||||
// Game-Functions first — other services may still query
|
||||
// chat-interactable state during their Dispose.
|
||||
failure = CaptureFailure(failure, () => GameFunctions.GameFunctions.SetChatInteractable(true));
|
||||
await Framework
|
||||
.RunOnFrameworkThread(() =>
|
||||
{
|
||||
// Game-Functions first — other services may still query
|
||||
// chat-interactable state during their Dispose.
|
||||
failure = CaptureFailure(
|
||||
failure,
|
||||
() => GameFunctions.GameFunctions.SetChatInteractable(true)
|
||||
);
|
||||
|
||||
// IPC subscribers — dispose before windows so any final
|
||||
// event firing from the IPC source can't reach a half-torn
|
||||
// ChatLogWindow.
|
||||
failure = CaptureFailure(failure, () => HonorificService?.Dispose());
|
||||
failure = CaptureFailure(failure, () => TypingIpc?.Dispose());
|
||||
failure = CaptureFailure(failure, () => ExtraChat?.Dispose());
|
||||
failure = CaptureFailure(failure, () => Ipc?.Dispose());
|
||||
// IPC subscribers — dispose before windows so any final
|
||||
// event firing from the IPC source can't reach a half-torn
|
||||
// ChatLogWindow.
|
||||
failure = CaptureFailure(failure, () => HonorificService?.Dispose());
|
||||
failure = CaptureFailure(failure, () => TypingIpc?.Dispose());
|
||||
failure = CaptureFailure(failure, () => ExtraChat?.Dispose());
|
||||
failure = CaptureFailure(failure, () => Ipc?.Dispose());
|
||||
|
||||
// Windows — RemoveAllWindows first, then per-window Dispose.
|
||||
// Order matches the pre-v1.4.3 Dispose body byte-for-byte.
|
||||
// CommandHelpWindow and FirstRunWizard don't implement
|
||||
// IDisposable; their resources are reclaimed via WindowSystem.
|
||||
failure = CaptureFailure(failure, () => WindowSystem?.RemoveAllWindows());
|
||||
failure = CaptureFailure(failure, () => ChatLogWindow?.Dispose());
|
||||
failure = CaptureFailure(failure, () => DbViewer?.Dispose());
|
||||
failure = CaptureFailure(failure, () => InputPreview?.Dispose());
|
||||
failure = CaptureFailure(failure, () => SettingsWindow?.Dispose());
|
||||
failure = CaptureFailure(failure, () => DebuggerWindow?.Dispose());
|
||||
failure = CaptureFailure(failure, () => SeStringDebugger?.Dispose());
|
||||
}).ConfigureAwait(false);
|
||||
// Windows — RemoveAllWindows first, then per-window Dispose.
|
||||
// Order matches the pre-v1.4.3 Dispose body byte-for-byte.
|
||||
// CommandHelpWindow and FirstRunWizard don't implement
|
||||
// IDisposable; their resources are reclaimed via WindowSystem.
|
||||
failure = CaptureFailure(failure, () => WindowSystem?.RemoveAllWindows());
|
||||
failure = CaptureFailure(failure, () => ChatLogWindow?.Dispose());
|
||||
failure = CaptureFailure(failure, () => DbViewer?.Dispose());
|
||||
failure = CaptureFailure(failure, () => InputPreview?.Dispose());
|
||||
failure = CaptureFailure(failure, () => SettingsWindow?.Dispose());
|
||||
failure = CaptureFailure(failure, () => DebuggerWindow?.Dispose());
|
||||
failure = CaptureFailure(failure, () => SeStringDebugger?.Dispose());
|
||||
})
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -401,15 +461,30 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
// skip every cleanup behind it and leave services half-torn.
|
||||
private static Exception? CaptureFailure(Exception? failure, Action action)
|
||||
{
|
||||
try { action(); }
|
||||
catch (Exception ex) { failure ??= ex; }
|
||||
try
|
||||
{
|
||||
action();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
failure ??= ex;
|
||||
}
|
||||
return failure;
|
||||
}
|
||||
|
||||
private static async ValueTask<Exception?> CaptureFailureAsync(Exception? failure, Func<Task> action)
|
||||
private static async ValueTask<Exception?> CaptureFailureAsync(
|
||||
Exception? failure,
|
||||
Func<Task> action
|
||||
)
|
||||
{
|
||||
try { await action().ConfigureAwait(false); }
|
||||
catch (Exception ex) { failure ??= ex; }
|
||||
try
|
||||
{
|
||||
await action().ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
failure ??= ex;
|
||||
}
|
||||
return failure;
|
||||
}
|
||||
|
||||
@@ -434,12 +509,17 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
if (!File.Exists(ourConfigFile) && File.Exists(legacyConfigFile))
|
||||
{
|
||||
File.Move(legacyConfigFile, ourConfigFile);
|
||||
Log.Information($"HellionChat: migrated config file {legacyConfigFile} → {ourConfigFile}");
|
||||
Log.Information(
|
||||
$"HellionChat: migrated config file {legacyConfigFile} → {ourConfigFile}"
|
||||
);
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Log.Warning(e, $"HellionChat: config file move blocked, leaving {legacyConfigFile} in place");
|
||||
Log.Warning(
|
||||
e,
|
||||
$"HellionChat: config file move blocked, leaving {legacyConfigFile} in place"
|
||||
);
|
||||
lockedBlocker = true;
|
||||
}
|
||||
|
||||
@@ -469,7 +549,10 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Log.Warning(e, $"HellionChat: file move blocked for {file}, will retry on next load");
|
||||
Log.Warning(
|
||||
e,
|
||||
$"HellionChat: file move blocked for {file}, will retry on next load"
|
||||
);
|
||||
lockedBlocker = true;
|
||||
}
|
||||
}
|
||||
@@ -486,7 +569,10 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Log.Warning(e, $"HellionChat: subdir move blocked for {dir}, will retry on next load");
|
||||
Log.Warning(
|
||||
e,
|
||||
$"HellionChat: subdir move blocked for {dir}, will retry on next load"
|
||||
);
|
||||
lockedBlocker = true;
|
||||
}
|
||||
}
|
||||
@@ -507,15 +593,18 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
// Surface the most common cause to the user as a notification
|
||||
// so they don't think Hellion Chat lost their history when in
|
||||
// fact upstream Chat 2 was still holding the database file.
|
||||
Notification.AddNotification(new Dalamud.Interface.ImGuiNotification.Notification
|
||||
{
|
||||
Title = "Hellion Chat",
|
||||
Content = "Could not migrate the Chat 2 database — the file appears to be in use. " +
|
||||
"Disable Chat 2, fully close the game, then start it again. " +
|
||||
"See the README troubleshooting section if the issue persists.",
|
||||
Type = Dalamud.Interface.ImGuiNotification.NotificationType.Warning,
|
||||
InitialDuration = TimeSpan.FromSeconds(30),
|
||||
});
|
||||
Notification.AddNotification(
|
||||
new Dalamud.Interface.ImGuiNotification.Notification
|
||||
{
|
||||
Title = "Hellion Chat",
|
||||
Content =
|
||||
"Could not migrate the Chat 2 database — the file appears to be in use. "
|
||||
+ "Disable Chat 2, fully close the game, then start it again. "
|
||||
+ "See the README troubleshooting section if the issue persists.",
|
||||
Type = Dalamud.Interface.ImGuiNotification.NotificationType.Warning,
|
||||
InitialDuration = TimeSpan.FromSeconds(30),
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,11 +664,13 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
// — the .Wait() here would return as soon as the inner Task.Run was
|
||||
// dispatched, racing the next sweep cycle against the still-running
|
||||
// filter pass. See AUDIT-2026-05-05 [QUAL-02].
|
||||
Framework.Run(() =>
|
||||
{
|
||||
MessageManager.ClearAllTabs();
|
||||
MessageManager.FilterAllTabs();
|
||||
}).Wait();
|
||||
Framework
|
||||
.Run(() =>
|
||||
{
|
||||
MessageManager.ClearAllTabs();
|
||||
MessageManager.FilterAllTabs();
|
||||
})
|
||||
.Wait();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -595,7 +686,10 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
lock (RetentionSweepLock)
|
||||
RetentionSweepRunning = false;
|
||||
}
|
||||
}) { IsBackground = true }.Start();
|
||||
})
|
||||
{
|
||||
IsBackground = true,
|
||||
}.Start();
|
||||
}
|
||||
|
||||
private void Draw()
|
||||
@@ -603,7 +697,10 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
// Theme-Engine ist ab v14 immer aktiv; Klassik ist jetzt ein eigenes
|
||||
// Theme statt einem deaktivierten Hellion-Theme. Active wird einmal
|
||||
// pro Frame aus der Registry gelesen.
|
||||
using IDisposable _style = HellionStyle.PushGlobal(ThemeRegistry.Active, Config.WindowOpacity);
|
||||
using IDisposable _style = HellionStyle.PushGlobal(
|
||||
ThemeRegistry.Active,
|
||||
Config.WindowOpacity
|
||||
);
|
||||
|
||||
ChatLogWindow.BeginFrame();
|
||||
|
||||
@@ -617,7 +714,12 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
// v1.0.2 — global skip while the New Game+ menu (QuestRedo addon) is
|
||||
// open. Hides every plugin window in one shot (chat log, pop-outs,
|
||||
// settings, db viewer, etc.), matching the LoadingScreens pattern.
|
||||
if (Config.HideInNewGamePlusMenu && GameFunctions.GameFunctions.IsAddonInteractable(GameFunctions.GameFunctions.NewGamePlusAddonName))
|
||||
if (
|
||||
Config.HideInNewGamePlusMenu
|
||||
&& GameFunctions.GameFunctions.IsAddonInteractable(
|
||||
GameFunctions.GameFunctions.NewGamePlusAddonName
|
||||
)
|
||||
)
|
||||
{
|
||||
ChatLogWindow.FinalizeFrame();
|
||||
TypingIpc.Update();
|
||||
@@ -627,7 +729,7 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
ChatLogWindow.HideStateCheck();
|
||||
|
||||
Interface.UiBuilder.DisableUserUiHide = !Config.HideWhenUiHidden;
|
||||
ChatLogWindow.DefaultText = ImGui.GetStyle().Colors[(int) ImGuiCol.Text];
|
||||
ChatLogWindow.DefaultText = ImGui.GetStyle().Colors[(int)ImGuiCol.Text];
|
||||
|
||||
using ((Config.FontsEnabled ? FontManager.RegularFont : FontManager.Axis).Push())
|
||||
WindowSystem.Draw();
|
||||
@@ -655,9 +757,10 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
|
||||
internal void LanguageChanged(string langCode)
|
||||
{
|
||||
var info = Config.LanguageOverride is LanguageOverride.None
|
||||
? new CultureInfo(langCode)
|
||||
: new CultureInfo(Config.LanguageOverride.Code());
|
||||
var info =
|
||||
Config.LanguageOverride is LanguageOverride.None
|
||||
? new CultureInfo(langCode)
|
||||
: new CultureInfo(Config.LanguageOverride.Code());
|
||||
|
||||
Language.Culture = info;
|
||||
HellionStrings.Culture = info;
|
||||
@@ -669,7 +772,7 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
"ChatLogPanel_0",
|
||||
"ChatLogPanel_1",
|
||||
"ChatLogPanel_2",
|
||||
"ChatLogPanel_3"
|
||||
"ChatLogPanel_3",
|
||||
];
|
||||
|
||||
private void FrameworkUpdate(IFramework framework)
|
||||
@@ -687,7 +790,9 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
|
||||
public static bool InBattle => Condition[ConditionFlag.InCombat];
|
||||
public static bool GposeActive => Condition[ConditionFlag.WatchingCutscene];
|
||||
public static bool CutsceneActive => Condition[ConditionFlag.OccupiedInCutSceneEvent] || Condition[ConditionFlag.WatchingCutscene78];
|
||||
public static bool CutsceneActive =>
|
||||
Condition[ConditionFlag.OccupiedInCutSceneEvent]
|
||||
|| Condition[ConditionFlag.WatchingCutscene78];
|
||||
|
||||
// v1.1.0 — wenn der themes/-Ordner leer ist, schreiben wir die embedded
|
||||
// example-theme.json als Vorlage rein. Bestehende User-Customs werden
|
||||
@@ -698,7 +803,9 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
return;
|
||||
|
||||
var examplePath = Path.Combine(dir, "example-theme.json");
|
||||
var resourceStream = typeof(Plugin).Assembly.GetManifestResourceStream("HellionChat.Themes.Builtin.example-theme.json");
|
||||
var resourceStream = typeof(Plugin).Assembly.GetManifestResourceStream(
|
||||
"HellionChat.Themes.Builtin.example-theme.json"
|
||||
);
|
||||
if (resourceStream is null)
|
||||
{
|
||||
Log.Warning("Themes example template not found in assembly resources; skipping seed.");
|
||||
@@ -713,7 +820,10 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
Log.Warning(ex, "Failed to seed example-theme.json; user can create custom themes manually.");
|
||||
Log.Warning(
|
||||
ex,
|
||||
"Failed to seed example-theme.json; user can create custom themes manually."
|
||||
);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user