slight adjustments and fixes

This commit is contained in:
2026-01-03 10:20:07 +09:00
parent 4b13dfe8d4
commit a824d94ffe
5 changed files with 148 additions and 16 deletions

View File

@@ -51,6 +51,7 @@ public class LightlessConfig : ILightlessConfiguration
public bool PreferNotesOverNamesForVisible { get; set; } = false; public bool PreferNotesOverNamesForVisible { get; set; } = false;
public VisiblePairSortMode VisiblePairSortMode { get; set; } = VisiblePairSortMode.Alphabetical; public VisiblePairSortMode VisiblePairSortMode { get; set; } = VisiblePairSortMode.Alphabetical;
public OnlinePairSortMode OnlinePairSortMode { get; set; } = OnlinePairSortMode.Alphabetical; public OnlinePairSortMode OnlinePairSortMode { get; set; } = OnlinePairSortMode.Alphabetical;
public TextureFormatSortMode TextureFormatSortMode { get; set; } = TextureFormatSortMode.None;
public float ProfileDelay { get; set; } = 1.5f; public float ProfileDelay { get; set; } = 1.5f;
public bool ProfilePopoutRight { get; set; } = false; public bool ProfilePopoutRight { get; set; } = false;
public bool ProfilesAllowNsfw { get; set; } = false; public bool ProfilesAllowNsfw { get; set; } = false;

View File

@@ -644,9 +644,8 @@ internal sealed class PairHandlerAdapter : DisposableMediatorSubscriberBase, IPa
var dataApplied = !string.IsNullOrEmpty(dataHash) var dataApplied = !string.IsNullOrEmpty(dataHash)
&& string.Equals(dataHash, _lastSuccessfulDataHash ?? string.Empty, StringComparison.Ordinal); && string.Equals(dataHash, _lastSuccessfulDataHash ?? string.Empty, StringComparison.Ordinal);
var needsApply = !dataApplied; var needsApply = !dataApplied;
var hasModReplacements = sanitized.FileReplacements.Values.Any(list => list.Count > 0); var modFilesChanged = PlayerModFilesChanged(sanitized, _cachedData);
var needsModReapply = needsApply && hasModReplacements; var shouldForceMods = shouldForce || modFilesChanged;
var shouldForceMods = shouldForce || needsModReapply;
forceApplyCustomization = forced || needsApply; forceApplyCustomization = forced || needsApply;
var suppressForcedModRedraw = !forced && hasMissingCachedFiles && dataApplied; var suppressForcedModRedraw = !forced && hasMissingCachedFiles && dataApplied;
@@ -2192,7 +2191,7 @@ internal sealed class PairHandlerAdapter : DisposableMediatorSubscriberBase, IPa
if (ex is AggregateException aggr && aggr.InnerExceptions.Any(e => e is ArgumentNullException)) if (ex is AggregateException aggr && aggr.InnerExceptions.Any(e => e is ArgumentNullException))
{ {
IsVisible = false; IsVisible = false;
_forceApplyMods = true; _forceApplyMods = true;
_cachedData = charaData; _cachedData = charaData;
_pairStateCache.Store(Ident, charaData); _pairStateCache.Store(Ident, charaData);
_forceFullReapply = true; _forceFullReapply = true;

View File

@@ -11,6 +11,7 @@ using LightlessSync.LightlessConfiguration;
using LightlessSync.Services; using LightlessSync.Services;
using LightlessSync.Services.Mediator; using LightlessSync.Services.Mediator;
using LightlessSync.Services.TextureCompression; using LightlessSync.Services.TextureCompression;
using LightlessSync.UI.Models;
using LightlessSync.Utils; using LightlessSync.Utils;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using OtterTex; using OtterTex;
@@ -42,6 +43,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
private readonly Progress<TextureConversionProgress> _conversionProgress = new(); private readonly Progress<TextureConversionProgress> _conversionProgress = new();
private readonly IpcManager _ipcManager; private readonly IpcManager _ipcManager;
private readonly UiSharedService _uiSharedService; private readonly UiSharedService _uiSharedService;
private readonly LightlessConfigService _configService;
private readonly PlayerPerformanceConfigService _playerPerformanceConfig; private readonly PlayerPerformanceConfigService _playerPerformanceConfig;
private readonly TransientResourceManager _transientResourceManager; private readonly TransientResourceManager _transientResourceManager;
private readonly TransientConfigService _transientConfigService; private readonly TransientConfigService _transientConfigService;
@@ -106,10 +108,12 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
private TextureUsageCategory? _textureCategoryFilter = null; private TextureUsageCategory? _textureCategoryFilter = null;
private TextureMapKind? _textureMapFilter = null; private TextureMapKind? _textureMapFilter = null;
private TextureCompressionTarget? _textureTargetFilter = null; private TextureCompressionTarget? _textureTargetFilter = null;
private TextureFormatSortMode _textureFormatSortMode = TextureFormatSortMode.None;
public DataAnalysisUi(ILogger<DataAnalysisUi> logger, LightlessMediator mediator, public DataAnalysisUi(ILogger<DataAnalysisUi> logger, LightlessMediator mediator,
CharacterAnalyzer characterAnalyzer, IpcManager ipcManager, CharacterAnalyzer characterAnalyzer, IpcManager ipcManager,
PerformanceCollectorService performanceCollectorService, UiSharedService uiSharedService, PerformanceCollectorService performanceCollectorService, UiSharedService uiSharedService,
LightlessConfigService configService,
PlayerPerformanceConfigService playerPerformanceConfig, TransientResourceManager transientResourceManager, PlayerPerformanceConfigService playerPerformanceConfig, TransientResourceManager transientResourceManager,
TransientConfigService transientConfigService, TextureCompressionService textureCompressionService, TransientConfigService transientConfigService, TextureCompressionService textureCompressionService,
TextureMetadataHelper textureMetadataHelper) TextureMetadataHelper textureMetadataHelper)
@@ -118,6 +122,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
_characterAnalyzer = characterAnalyzer; _characterAnalyzer = characterAnalyzer;
_ipcManager = ipcManager; _ipcManager = ipcManager;
_uiSharedService = uiSharedService; _uiSharedService = uiSharedService;
_configService = configService;
_playerPerformanceConfig = playerPerformanceConfig; _playerPerformanceConfig = playerPerformanceConfig;
_transientResourceManager = transientResourceManager; _transientResourceManager = transientResourceManager;
_transientConfigService = transientConfigService; _transientConfigService = transientConfigService;
@@ -971,6 +976,13 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
#if DEBUG #if DEBUG
ResetDebugCompressionModalState(); ResetDebugCompressionModalState();
#endif #endif
var savedFormatSort = _configService.Current.TextureFormatSortMode;
if (!Enum.IsDefined(typeof(TextureFormatSortMode), savedFormatSort))
{
savedFormatSort = TextureFormatSortMode.None;
}
SetTextureFormatSortMode(savedFormatSort, persist: false);
} }
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
@@ -2198,26 +2210,56 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
ImGui.TableSetupColumn("Original", ImGuiTableColumnFlags.PreferSortDescending); ImGui.TableSetupColumn("Original", ImGuiTableColumnFlags.PreferSortDescending);
ImGui.TableSetupColumn("Compressed", ImGuiTableColumnFlags.PreferSortDescending); ImGui.TableSetupColumn("Compressed", ImGuiTableColumnFlags.PreferSortDescending);
ImGui.TableSetupScrollFreeze(0, 1); ImGui.TableSetupScrollFreeze(0, 1);
ImGui.TableHeadersRow(); DrawTextureTableHeaderRow();
var targets = _textureCompressionService.SelectableTargets; var targets = _textureCompressionService.SelectableTargets;
IEnumerable<TextureRow> orderedRows = rows; IEnumerable<TextureRow> orderedRows = rows;
var sortSpecs = ImGui.TableGetSortSpecs(); var sortSpecs = ImGui.TableGetSortSpecs();
var sizeSortColumn = -1;
var sizeSortDirection = ImGuiSortDirection.Ascending;
if (sortSpecs.SpecsCount > 0) if (sortSpecs.SpecsCount > 0)
{ {
var spec = sortSpecs.Specs[0]; var spec = sortSpecs.Specs[0];
orderedRows = spec.ColumnIndex switch if (spec.ColumnIndex is 7 or 8)
{ {
7 => spec.SortDirection == ImGuiSortDirection.Ascending sizeSortColumn = spec.ColumnIndex;
? rows.OrderBy(r => r.OriginalSize) sizeSortDirection = spec.SortDirection;
: rows.OrderByDescending(r => r.OriginalSize), }
8 => spec.SortDirection == ImGuiSortDirection.Ascending }
? rows.OrderBy(r => r.CompressedSize)
: rows.OrderByDescending(r => r.CompressedSize),
_ => rows
};
var hasSizeSort = sizeSortColumn != -1;
var indexedRows = rows.Select((row, idx) => (row, idx));
if (_textureFormatSortMode != TextureFormatSortMode.None)
{
bool compressedFirst = _textureFormatSortMode == TextureFormatSortMode.CompressedFirst;
int GroupKey(TextureRow row) => row.IsAlreadyCompressed == compressedFirst ? 0 : 1;
long SizeKey(TextureRow row) => sizeSortColumn == 7 ? row.OriginalSize : row.CompressedSize;
var ordered = indexedRows.OrderBy(pair => GroupKey(pair.row));
if (hasSizeSort)
{
ordered = sizeSortDirection == ImGuiSortDirection.Ascending
? ordered.ThenBy(pair => SizeKey(pair.row))
: ordered.ThenByDescending(pair => SizeKey(pair.row));
}
orderedRows = ordered
.ThenBy(pair => pair.idx)
.Select(pair => pair.row);
}
else if (hasSizeSort)
{
long SizeKey(TextureRow row) => sizeSortColumn == 7 ? row.OriginalSize : row.CompressedSize;
orderedRows = sizeSortDirection == ImGuiSortDirection.Ascending
? indexedRows.OrderBy(pair => SizeKey(pair.row)).ThenBy(pair => pair.idx).Select(pair => pair.row)
: indexedRows.OrderByDescending(pair => SizeKey(pair.row)).ThenBy(pair => pair.idx).Select(pair => pair.row);
}
if (sortSpecs.SpecsCount > 0)
{
sortSpecs.SpecsDirty = false; sortSpecs.SpecsDirty = false;
} }
@@ -2259,6 +2301,79 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
} }
} }
} }
private void DrawTextureTableHeaderRow()
{
ImGui.TableNextRow(ImGuiTableRowFlags.Headers);
DrawHeaderCell(0, "##select");
DrawHeaderCell(1, "Texture");
DrawHeaderCell(2, "Slot");
DrawHeaderCell(3, "Map");
DrawFormatHeaderCell();
DrawHeaderCell(5, "Recommended");
DrawHeaderCell(6, "Target");
DrawHeaderCell(7, "Original");
DrawHeaderCell(8, "Compressed");
}
private static void DrawHeaderCell(int columnIndex, string label)
{
ImGui.TableSetColumnIndex(columnIndex);
ImGui.TableHeader(label);
}
private void DrawFormatHeaderCell()
{
ImGui.TableSetColumnIndex(4);
ImGui.TableHeader(GetFormatHeaderLabel());
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
{
CycleTextureFormatSortMode();
}
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip("Click to cycle sort: normal, compressed first, uncompressed first.");
}
}
private string GetFormatHeaderLabel()
=> _textureFormatSortMode switch
{
TextureFormatSortMode.CompressedFirst => "Format (C)##formatHeader",
TextureFormatSortMode.UncompressedFirst => "Format (U)##formatHeader",
_ => "Format##formatHeader"
};
private void SetTextureFormatSortMode(TextureFormatSortMode mode, bool persist = true)
{
if (_textureFormatSortMode == mode)
{
return;
}
_textureFormatSortMode = mode;
if (persist)
{
_configService.Current.TextureFormatSortMode = mode;
_configService.Save();
}
}
private void CycleTextureFormatSortMode()
{
var nextMode = _textureFormatSortMode switch
{
TextureFormatSortMode.None => TextureFormatSortMode.CompressedFirst,
TextureFormatSortMode.CompressedFirst => TextureFormatSortMode.UncompressedFirst,
_ => TextureFormatSortMode.None
};
SetTextureFormatSortMode(nextMode);
}
private void StartTextureConversion() private void StartTextureConversion()
{ {
if (_conversionTask != null && !_conversionTask.IsCompleted) if (_conversionTask != null && !_conversionTask.IsCompleted)

View File

@@ -103,10 +103,19 @@ public sealed class DtrEntry : IDisposable, IHostedService
public async Task StopAsync(CancellationToken cancellationToken) public async Task StopAsync(CancellationToken cancellationToken)
{ {
await _cancellationTokenSource.CancelAsync().ConfigureAwait(false); _cancellationTokenSource.Cancel();
if (_dalamudUtilService.IsOnFrameworkThread)
{
_logger.LogDebug("Skipping Lightfinder DTR wait on framework thread during shutdown.");
_cancellationTokenSource.Dispose();
return;
}
try try
{ {
await _runTask!.ConfigureAwait(false); if (_runTask != null)
await _runTask.ConfigureAwait(false);
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {

View File

@@ -0,0 +1,8 @@
namespace LightlessSync.UI.Models;
public enum TextureFormatSortMode
{
None = 0,
CompressedFirst = 1,
UncompressedFirst = 2
}