fix some shit, add triangle count

This commit is contained in:
rootdarkarchon
2024-03-20 15:12:19 +01:00
parent f62e8675e7
commit 1d99102c73
22 changed files with 196 additions and 46 deletions

View File

@@ -100,3 +100,12 @@ dotnet_diagnostic.MA0075.severity = silent
# S3358: Ternary operators should not be nested # S3358: Ternary operators should not be nested
dotnet_diagnostic.S3358.severity = suggestion dotnet_diagnostic.S3358.severity = suggestion
# S6678: Use PascalCase for named placeholders
dotnet_diagnostic.S6678.severity = suggestion
# S6605: Collection-specific "Exists" method should be used instead of the "Any" extension
dotnet_diagnostic.S6605.severity = suggestion
# S6667: Logging in a catch clause should pass the caught exception as a parameter.
dotnet_diagnostic.S6667.severity = suggestion

View File

@@ -5,6 +5,7 @@ using MareSynchronos.Services.Mediator;
using MareSynchronos.Utils; using MareSynchronos.Utils;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Diagnostics;
namespace MareSynchronos.FileCache; namespace MareSynchronos.FileCache;
@@ -25,6 +26,7 @@ public sealed class CacheMonitor : DisposableMediatorSubscriberBase
FileCacheManager fileDbManager, MareMediator mediator, PerformanceCollectorService performanceCollector, DalamudUtilService dalamudUtil, FileCacheManager fileDbManager, MareMediator mediator, PerformanceCollectorService performanceCollector, DalamudUtilService dalamudUtil,
FileCompactor fileCompactor) : base(logger, mediator) FileCompactor fileCompactor) : base(logger, mediator)
{ {
Logger.LogInformation("Creating CacheMonitor from {trace}", Environment.StackTrace);
_ipcManager = ipcManager; _ipcManager = ipcManager;
_configService = configService; _configService = configService;
_fileDbManager = fileDbManager; _fileDbManager = fileDbManager;

View File

@@ -0,0 +1,9 @@
using System.Collections.Concurrent;
namespace MareSynchronos.MareConfiguration.Configurations;
public class TriangleCalculationConfig : IMareConfiguration
{
public ConcurrentDictionary<string, long> TriangleDictionary { get; set; } = new(StringComparer.OrdinalIgnoreCase);
public int Version { get; set; } = 0;
}

View File

@@ -0,0 +1,12 @@
using MareSynchronos.MareConfiguration.Configurations;
namespace MareSynchronos.MareConfiguration;
public class TriangleCalculationConfigService : ConfigurationServiceBase<TriangleCalculationConfig>
{
public const string ConfigName = "trianglecache.json";
public TriangleCalculationConfigService(string configDir) : base(configDir) { }
protected override string ConfigurationName => ConfigName;
}

View File

@@ -73,6 +73,7 @@ public class MarePlugin : MediatorSubscriberBase, IHostedService
private readonly ServerConfigurationManager _serverConfigurationManager; private readonly ServerConfigurationManager _serverConfigurationManager;
private readonly IServiceScopeFactory _serviceScopeFactory; private readonly IServiceScopeFactory _serviceScopeFactory;
private IServiceScope? _runtimeServiceScope; private IServiceScope? _runtimeServiceScope;
private Task? _launchTask = null;
public MarePlugin(ILogger<MarePlugin> logger, MareConfigService mareConfigService, public MarePlugin(ILogger<MarePlugin> logger, MareConfigService mareConfigService,
ServerConfigurationManager serverConfigurationManager, ServerConfigurationManager serverConfigurationManager,
@@ -92,7 +93,7 @@ public class MarePlugin : MediatorSubscriberBase, IHostedService
Mediator.Publish(new EventMessage(new Services.Events.Event(nameof(MarePlugin), Services.Events.EventSeverity.Informational, Mediator.Publish(new EventMessage(new Services.Events.Event(nameof(MarePlugin), Services.Events.EventSeverity.Informational,
$"Starting Mare Synchronos {version.Major}.{version.Minor}.{version.Build}"))); $"Starting Mare Synchronos {version.Major}.{version.Minor}.{version.Build}")));
Mediator.Subscribe<SwitchToMainUiMessage>(this, (msg) => _ = Task.Run(WaitForPlayerAndLaunchCharacterManager)); Mediator.Subscribe<SwitchToMainUiMessage>(this, (msg) => { if (_launchTask == null || _launchTask.IsCompleted) _launchTask = Task.Run(WaitForPlayerAndLaunchCharacterManager); });
Mediator.Subscribe<DalamudLoginMessage>(this, (_) => DalamudUtilOnLogIn()); Mediator.Subscribe<DalamudLoginMessage>(this, (_) => DalamudUtilOnLogIn());
Mediator.Subscribe<DalamudLogoutMessage>(this, (_) => DalamudUtilOnLogOut()); Mediator.Subscribe<DalamudLogoutMessage>(this, (_) => DalamudUtilOnLogOut());
@@ -115,8 +116,7 @@ public class MarePlugin : MediatorSubscriberBase, IHostedService
private void DalamudUtilOnLogIn() private void DalamudUtilOnLogIn()
{ {
Logger?.LogDebug("Client login"); Logger?.LogDebug("Client login");
if (_launchTask == null || _launchTask.IsCompleted) _launchTask = Task.Run(WaitForPlayerAndLaunchCharacterManager);
_ = Task.Run(WaitForPlayerAndLaunchCharacterManager);
} }
private void DalamudUtilOnLogOut() private void DalamudUtilOnLogOut()

View File

@@ -20,12 +20,13 @@ public class PairHandlerFactory
private readonly IpcManager _ipcManager; private readonly IpcManager _ipcManager;
private readonly ILoggerFactory _loggerFactory; private readonly ILoggerFactory _loggerFactory;
private readonly MareMediator _mareMediator; private readonly MareMediator _mareMediator;
private readonly ModelAnalyzer _modelAnalyzer;
private readonly PluginWarningNotificationService _pluginWarningNotificationManager; private readonly PluginWarningNotificationService _pluginWarningNotificationManager;
public PairHandlerFactory(ILoggerFactory loggerFactory, GameObjectHandlerFactory gameObjectHandlerFactory, IpcManager ipcManager, public PairHandlerFactory(ILoggerFactory loggerFactory, GameObjectHandlerFactory gameObjectHandlerFactory, IpcManager ipcManager,
FileDownloadManagerFactory fileDownloadManagerFactory, DalamudUtilService dalamudUtilService, FileDownloadManagerFactory fileDownloadManagerFactory, DalamudUtilService dalamudUtilService,
PluginWarningNotificationService pluginWarningNotificationManager, IHostApplicationLifetime hostApplicationLifetime, PluginWarningNotificationService pluginWarningNotificationManager, IHostApplicationLifetime hostApplicationLifetime,
FileCacheManager fileCacheManager, MareMediator mareMediator) FileCacheManager fileCacheManager, MareMediator mareMediator, ModelAnalyzer modelAnalyzer)
{ {
_loggerFactory = loggerFactory; _loggerFactory = loggerFactory;
_gameObjectHandlerFactory = gameObjectHandlerFactory; _gameObjectHandlerFactory = gameObjectHandlerFactory;
@@ -36,12 +37,13 @@ public class PairHandlerFactory
_hostApplicationLifetime = hostApplicationLifetime; _hostApplicationLifetime = hostApplicationLifetime;
_fileCacheManager = fileCacheManager; _fileCacheManager = fileCacheManager;
_mareMediator = mareMediator; _mareMediator = mareMediator;
_modelAnalyzer = modelAnalyzer;
} }
public PairHandler Create(OnlineUserIdentDto onlineUserIdentDto) public PairHandler Create(OnlineUserIdentDto onlineUserIdentDto)
{ {
return new PairHandler(_loggerFactory.CreateLogger<PairHandler>(), onlineUserIdentDto, _gameObjectHandlerFactory, return new PairHandler(_loggerFactory.CreateLogger<PairHandler>(), onlineUserIdentDto, _gameObjectHandlerFactory,
_ipcManager, _fileDownloadManagerFactory.Create(), _pluginWarningNotificationManager, _dalamudUtilService, _hostApplicationLifetime, _ipcManager, _fileDownloadManagerFactory.Create(), _pluginWarningNotificationManager, _dalamudUtilService, _hostApplicationLifetime,
_fileCacheManager, _mareMediator); _fileCacheManager, _mareMediator, _modelAnalyzer);
} }
} }

View File

@@ -30,7 +30,7 @@ public class PlayerDataFactory
_transientResourceManager = transientResourceManager; _transientResourceManager = transientResourceManager;
_fileCacheManager = fileReplacementFactory; _fileCacheManager = fileReplacementFactory;
_performanceCollector = performanceCollector; _performanceCollector = performanceCollector;
_logger.LogTrace("Creating " + nameof(PlayerDataFactory)); _logger.LogTrace("Creating {this}", nameof(PlayerDataFactory));
} }
public async Task BuildCharacterData(CharacterData previousData, GameObjectHandler playerRelatedObject, CancellationToken token) public async Task BuildCharacterData(CharacterData previousData, GameObjectHandler playerRelatedObject, CancellationToken token)
@@ -140,7 +140,7 @@ public class PlayerDataFactory
// penumbra call, it's currently broken // penumbra call, it's currently broken
IReadOnlyDictionary<string, string[]>? resolvedPaths; IReadOnlyDictionary<string, string[]>? resolvedPaths;
resolvedPaths = (await _ipcManager.Penumbra.GetCharacterData(_logger, playerRelatedObject).ConfigureAwait(false))![0]; resolvedPaths = (await _ipcManager.Penumbra.GetCharacterData(_logger, playerRelatedObject).ConfigureAwait(false))?[0];
if (resolvedPaths == null) throw new InvalidOperationException("Penumbra returned null data"); if (resolvedPaths == null) throw new InvalidOperationException("Penumbra returned null data");
previousData.FileReplacements[objectKind] = previousData.FileReplacements[objectKind] =

View File

@@ -24,6 +24,7 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
private readonly DalamudUtilService _dalamudUtil; private readonly DalamudUtilService _dalamudUtil;
private readonly FileDownloadManager _downloadManager; private readonly FileDownloadManager _downloadManager;
private readonly FileCacheManager _fileDbManager; private readonly FileCacheManager _fileDbManager;
private readonly ModelAnalyzer _modelAnalyzer;
private readonly GameObjectHandlerFactory _gameObjectHandlerFactory; private readonly GameObjectHandlerFactory _gameObjectHandlerFactory;
private readonly IpcManager _ipcManager; private readonly IpcManager _ipcManager;
private readonly IHostApplicationLifetime _lifetime; private readonly IHostApplicationLifetime _lifetime;
@@ -40,13 +41,15 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
private bool _redrawOnNextApplication = false; private bool _redrawOnNextApplication = false;
private CombatData? _dataReceivedInDowntime; private CombatData? _dataReceivedInDowntime;
public long LastAppliedDataSize { get; private set; } public long LastAppliedDataSize { get; private set; }
public long LastAppliedDataTris { get; private set; }
public PairHandler(ILogger<PairHandler> logger, OnlineUserIdentDto onlineUser, public PairHandler(ILogger<PairHandler> logger, OnlineUserIdentDto onlineUser,
GameObjectHandlerFactory gameObjectHandlerFactory, GameObjectHandlerFactory gameObjectHandlerFactory,
IpcManager ipcManager, FileDownloadManager transferManager, IpcManager ipcManager, FileDownloadManager transferManager,
PluginWarningNotificationService pluginWarningNotificationManager, PluginWarningNotificationService pluginWarningNotificationManager,
DalamudUtilService dalamudUtil, IHostApplicationLifetime lifetime, DalamudUtilService dalamudUtil, IHostApplicationLifetime lifetime,
FileCacheManager fileDbManager, MareMediator mediator) : base(logger, mediator) FileCacheManager fileDbManager, MareMediator mediator,
ModelAnalyzer modelAnalyzer) : base(logger, mediator)
{ {
OnlineUser = onlineUser; OnlineUser = onlineUser;
_gameObjectHandlerFactory = gameObjectHandlerFactory; _gameObjectHandlerFactory = gameObjectHandlerFactory;
@@ -56,6 +59,7 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
_dalamudUtil = dalamudUtil; _dalamudUtil = dalamudUtil;
_lifetime = lifetime; _lifetime = lifetime;
_fileDbManager = fileDbManager; _fileDbManager = fileDbManager;
_modelAnalyzer = modelAnalyzer;
_penumbraCollection = _ipcManager.Penumbra.CreateTemporaryCollectionAsync(logger, OnlineUser.User.UID).ConfigureAwait(false).GetAwaiter().GetResult(); _penumbraCollection = _ipcManager.Penumbra.CreateTemporaryCollectionAsync(logger, OnlineUser.User.UID).ConfigureAwait(false).GetAwaiter().GetResult();
Mediator.Subscribe<FrameworkUpdateMessage>(this, (_) => FrameworkUpdate()); Mediator.Subscribe<FrameworkUpdateMessage>(this, (_) => FrameworkUpdate());
@@ -99,6 +103,7 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
}); });
LastAppliedDataSize = -1; LastAppliedDataSize = -1;
LastAppliedDataTris = -1;
} }
public bool IsVisible public bool IsVisible
@@ -370,7 +375,7 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
_ = Task.Run(async () => _ = Task.Run(async () =>
{ {
Dictionary<string, string> moddedPaths = new(StringComparer.Ordinal); Dictionary<(string GamePath, string? Hash), string> moddedPaths = new();
if (updateModdedPaths) if (updateModdedPaths)
{ {
@@ -437,12 +442,20 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
if (updateModdedPaths) if (updateModdedPaths)
{ {
await _ipcManager.Penumbra.SetTemporaryModsAsync(Logger, _applicationId, _penumbraCollection, moddedPaths).ConfigureAwait(false); await _ipcManager.Penumbra.SetTemporaryModsAsync(Logger, _applicationId, _penumbraCollection,
moddedPaths.ToDictionary(k => k.Key.GamePath, k => k.Value, StringComparer.Ordinal)).ConfigureAwait(false);
LastAppliedDataSize = -1; LastAppliedDataSize = -1;
LastAppliedDataTris = -1;
foreach (var path in moddedPaths.Values.Distinct(StringComparer.OrdinalIgnoreCase).Select(v => new FileInfo(v)).Where(p => p.Exists)) foreach (var path in moddedPaths.Values.Distinct(StringComparer.OrdinalIgnoreCase).Select(v => new FileInfo(v)).Where(p => p.Exists))
{ {
if (LastAppliedDataSize == -1) LastAppliedDataSize = 0;
LastAppliedDataSize += path.Length; LastAppliedDataSize += path.Length;
} }
foreach (var key in moddedPaths.Keys.Where(k => !string.IsNullOrEmpty(k.Hash)))
{
if (LastAppliedDataTris == -1) LastAppliedDataTris = 0;
LastAppliedDataTris += await _modelAnalyzer.GetTrianglesByHash(key.Hash!).ConfigureAwait(false);
}
} }
if (updateManip) if (updateManip)
@@ -597,12 +610,12 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
} }
} }
private List<FileReplacementData> TryCalculateModdedDictionary(Guid applicationBase, CharacterData charaData, out Dictionary<string, string> moddedDictionary, CancellationToken token) private List<FileReplacementData> TryCalculateModdedDictionary(Guid applicationBase, CharacterData charaData, out Dictionary<(string GamePath, string? Hash), string> moddedDictionary, CancellationToken token)
{ {
Stopwatch st = Stopwatch.StartNew(); Stopwatch st = Stopwatch.StartNew();
ConcurrentBag<FileReplacementData> missingFiles = []; ConcurrentBag<FileReplacementData> missingFiles = [];
moddedDictionary = new Dictionary<string, string>(StringComparer.Ordinal); moddedDictionary = new Dictionary<(string GamePath, string? Hash), string>();
ConcurrentDictionary<string, string> outputDict = new(StringComparer.Ordinal); ConcurrentDictionary<(string GamePath, string? Hash), string> outputDict = new();
bool hasMigrationChanges = false; bool hasMigrationChanges = false;
try try
@@ -627,7 +640,7 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
foreach (var gamePath in item.GamePaths) foreach (var gamePath in item.GamePaths)
{ {
outputDict[gamePath] = fileCache.ResolvedFilepath; outputDict[(gamePath, item.Hash)] = fileCache.ResolvedFilepath;
} }
} }
else else
@@ -637,14 +650,14 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
} }
}); });
moddedDictionary = outputDict.ToDictionary(k => k.Key, k => k.Value, StringComparer.Ordinal); moddedDictionary = outputDict.ToDictionary(k => k.Key, k => k.Value);
foreach (var item in charaData.FileReplacements.SelectMany(k => k.Value.Where(v => !string.IsNullOrEmpty(v.FileSwapPath))).ToList()) foreach (var item in charaData.FileReplacements.SelectMany(k => k.Value.Where(v => !string.IsNullOrEmpty(v.FileSwapPath))).ToList())
{ {
foreach (var gamePath in item.GamePaths) foreach (var gamePath in item.GamePaths)
{ {
Logger.LogTrace("[BASE-{appBase}] Adding file swap for {path}: {fileSwap}", applicationBase, gamePath, item.FileSwapPath); Logger.LogTrace("[BASE-{appBase}] Adding file swap for {path}: {fileSwap}", applicationBase, gamePath, item.FileSwapPath);
moddedDictionary[gamePath] = item.FileSwapPath; moddedDictionary[(gamePath, null)] = item.FileSwapPath;
} }
} }
} }

View File

@@ -45,6 +45,7 @@ public class Pair
public CharacterData? LastReceivedCharacterData { get; set; } public CharacterData? LastReceivedCharacterData { get; set; }
public string? PlayerName => CachedPlayer?.PlayerName ?? string.Empty; public string? PlayerName => CachedPlayer?.PlayerName ?? string.Empty;
public long LastAppliedDataSize => CachedPlayer?.LastAppliedDataSize ?? -1; public long LastAppliedDataSize => CachedPlayer?.LastAppliedDataSize ?? -1;
public long LastAppliedDataTris => CachedPlayer?.LastAppliedDataTris ?? -1;
public UserData UserData => UserPair.User; public UserData UserData => UserPair.User;

View File

@@ -69,13 +69,14 @@ public sealed class Plugin : IDalamudPlugin
collection.AddSingleton<FileDownloadManagerFactory>(); collection.AddSingleton<FileDownloadManagerFactory>();
collection.AddSingleton<PairHandlerFactory>(); collection.AddSingleton<PairHandlerFactory>();
collection.AddSingleton<PairFactory>(); collection.AddSingleton<PairFactory>();
collection.AddSingleton<ModelAnalyzer>(s => new(s.GetRequiredService<ILogger<ModelAnalyzer>>(), s.GetRequiredService<FileCacheManager>(),
s.GetRequiredService<TriangleCalculationConfigService>(), gameData));
collection.AddSingleton<CharacterAnalyzer>(); collection.AddSingleton<CharacterAnalyzer>();
collection.AddSingleton<TokenProvider>(); collection.AddSingleton<TokenProvider>();
collection.AddSingleton<PluginWarningNotificationService>(); collection.AddSingleton<PluginWarningNotificationService>();
collection.AddSingleton<FileCompactor>(); collection.AddSingleton<FileCompactor>();
collection.AddSingleton<TagHandler>(); collection.AddSingleton<TagHandler>();
collection.AddSingleton<IdDisplayHandler>(); collection.AddSingleton<IdDisplayHandler>();
collection.AddSingleton<DrawEntityFactory>();
collection.AddSingleton((s) => new IpcProvider(s.GetRequiredService<ILogger<IpcProvider>>(), collection.AddSingleton((s) => new IpcProvider(s.GetRequiredService<ILogger<IpcProvider>>(),
pluginInterface, pluginInterface,
s.GetRequiredService<MareCharaFileManager>(), s.GetRequiredService<DalamudUtilService>(), s.GetRequiredService<MareCharaFileManager>(), s.GetRequiredService<DalamudUtilService>(),
@@ -83,7 +84,6 @@ public sealed class Plugin : IDalamudPlugin
collection.AddSingleton<SelectPairForTagUi>(); collection.AddSingleton<SelectPairForTagUi>();
collection.AddSingleton((s) => new EventAggregator(pluginInterface.ConfigDirectory.FullName, collection.AddSingleton((s) => new EventAggregator(pluginInterface.ConfigDirectory.FullName,
s.GetRequiredService<ILogger<EventAggregator>>(), s.GetRequiredService<MareMediator>())); s.GetRequiredService<ILogger<EventAggregator>>(), s.GetRequiredService<MareMediator>()));
collection.AddSingleton<SelectTagForPairUi>();
collection.AddSingleton((s) => new DalamudContextMenu(pluginInterface)); collection.AddSingleton((s) => new DalamudContextMenu(pluginInterface));
collection.AddSingleton((s) => new DalamudUtilService(s.GetRequiredService<ILogger<DalamudUtilService>>(), collection.AddSingleton((s) => new DalamudUtilService(s.GetRequiredService<ILogger<DalamudUtilService>>(),
clientState, objectTable, framework, gameGui, condition, gameData, targetManager, clientState, objectTable, framework, gameGui, condition, gameData, targetManager,
@@ -114,12 +114,15 @@ public sealed class Plugin : IDalamudPlugin
collection.AddSingleton((s) => new NotesConfigService(pluginInterface.ConfigDirectory.FullName)); collection.AddSingleton((s) => new NotesConfigService(pluginInterface.ConfigDirectory.FullName));
collection.AddSingleton((s) => new ServerTagConfigService(pluginInterface.ConfigDirectory.FullName)); collection.AddSingleton((s) => new ServerTagConfigService(pluginInterface.ConfigDirectory.FullName));
collection.AddSingleton((s) => new TransientConfigService(pluginInterface.ConfigDirectory.FullName)); collection.AddSingleton((s) => new TransientConfigService(pluginInterface.ConfigDirectory.FullName));
collection.AddSingleton((s) => new TriangleCalculationConfigService(pluginInterface.ConfigDirectory.FullName));
collection.AddSingleton((s) => new ConfigurationMigrator(s.GetRequiredService<ILogger<ConfigurationMigrator>>(), pluginInterface)); collection.AddSingleton((s) => new ConfigurationMigrator(s.GetRequiredService<ILogger<ConfigurationMigrator>>(), pluginInterface));
collection.AddSingleton<HubFactory>(); collection.AddSingleton<HubFactory>();
// add scoped services // add scoped services
collection.AddScoped<DrawEntityFactory>();
collection.AddScoped<CacheMonitor>(); collection.AddScoped<CacheMonitor>();
collection.AddScoped<UiFactory>(); collection.AddScoped<UiFactory>();
collection.AddScoped<SelectTagForPairUi>();
collection.AddScoped<WindowMediatorSubscriberBase, SettingsUi>(); collection.AddScoped<WindowMediatorSubscriberBase, SettingsUi>();
collection.AddScoped<WindowMediatorSubscriberBase, CompactUi>(); collection.AddScoped<WindowMediatorSubscriberBase, CompactUi>();
collection.AddScoped<WindowMediatorSubscriberBase, GposeUi>(); collection.AddScoped<WindowMediatorSubscriberBase, GposeUi>();

View File

@@ -12,16 +12,22 @@ namespace MareSynchronos.Services;
public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable
{ {
private readonly FileCacheManager _fileCacheManager; private readonly FileCacheManager _fileCacheManager;
private readonly ModelAnalyzer _modelAnalyzer;
private CancellationTokenSource? _analysisCts; private CancellationTokenSource? _analysisCts;
private CancellationTokenSource _baseAnalysisCts = new();
private string _lastDataHash = string.Empty; private string _lastDataHash = string.Empty;
public CharacterAnalyzer(ILogger<CharacterAnalyzer> logger, MareMediator mediator, FileCacheManager fileCacheManager) : base(logger, mediator) public CharacterAnalyzer(ILogger<CharacterAnalyzer> logger, MareMediator mediator, FileCacheManager fileCacheManager, ModelAnalyzer modelAnalyzer)
: base(logger, mediator)
{ {
Mediator.Subscribe<CharacterDataCreatedMessage>(this, (msg) => Mediator.Subscribe<CharacterDataCreatedMessage>(this, (msg) =>
{ {
_ = Task.Run(() => BaseAnalysis(msg.CharacterData.DeepClone())); _baseAnalysisCts = _baseAnalysisCts.CancelRecreate();
var token = _baseAnalysisCts.Token;
_ = BaseAnalysis(msg.CharacterData, token);
}); });
_fileCacheManager = fileCacheManager; _fileCacheManager = fileCacheManager;
_modelAnalyzer = modelAnalyzer;
} }
public int CurrentFile { get; internal set; } public int CurrentFile { get; internal set; }
@@ -87,7 +93,7 @@ public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable
_analysisCts.CancelDispose(); _analysisCts.CancelDispose();
} }
private void BaseAnalysis(CharacterData charaData) private async Task BaseAnalysis(CharacterData charaData, CancellationToken token)
{ {
if (string.Equals(charaData.DataHash.Value, _lastDataHash, StringComparison.Ordinal)) return; if (string.Equals(charaData.DataHash.Value, _lastDataHash, StringComparison.Ordinal)) return;
@@ -98,6 +104,8 @@ public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable
Dictionary<string, FileDataEntry> data = new(StringComparer.OrdinalIgnoreCase); Dictionary<string, FileDataEntry> data = new(StringComparer.OrdinalIgnoreCase);
foreach (var fileEntry in obj.Value) foreach (var fileEntry in obj.Value)
{ {
token.ThrowIfCancellationRequested();
var fileCacheEntries = _fileCacheManager.GetAllFileCachesByHash(fileEntry.Hash, ignoreCacheEntries: true, validate: false).ToList(); var fileCacheEntries = _fileCacheManager.GetAllFileCachesByHash(fileEntry.Hash, ignoreCacheEntries: true, validate: false).ToList();
if (fileCacheEntries.Count == 0) continue; if (fileCacheEntries.Count == 0) continue;
@@ -113,12 +121,16 @@ public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable
Logger.LogWarning(ex, "Could not identify extension for {path}", filePath); Logger.LogWarning(ex, "Could not identify extension for {path}", filePath);
} }
var tris = await _modelAnalyzer.GetTrianglesByHash(fileEntry.Hash).ConfigureAwait(false);
foreach (var entry in fileCacheEntries) foreach (var entry in fileCacheEntries)
{ {
data[fileEntry.Hash] = new FileDataEntry(fileEntry.Hash, ext, data[fileEntry.Hash] = new FileDataEntry(fileEntry.Hash, ext,
[.. fileEntry.GamePaths], [.. fileEntry.GamePaths],
fileCacheEntries.Select(c => c.ResolvedFilepath).Distinct().ToList(), fileCacheEntries.Select(c => c.ResolvedFilepath).Distinct().ToList(),
entry.Size > 0 ? entry.Size.Value : 0, entry.CompressedSize > 0 ? entry.CompressedSize.Value : 0); entry.Size > 0 ? entry.Size.Value : 0,
entry.CompressedSize > 0 ? entry.CompressedSize.Value : 0,
tris);
} }
} }
@@ -176,7 +188,7 @@ public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable
Logger.LogInformation("IMPORTANT NOTES:\n\r- For Mare up- and downloads only the compressed size is relevant.\n\r- An unusually high total files count beyond 200 and up will also increase your download time to others significantly."); Logger.LogInformation("IMPORTANT NOTES:\n\r- For Mare up- and downloads only the compressed size is relevant.\n\r- An unusually high total files count beyond 200 and up will also increase your download time to others significantly.");
} }
internal sealed record FileDataEntry(string Hash, string FileType, List<string> GamePaths, List<string> FilePaths, long OriginalSize, long CompressedSize) internal sealed record FileDataEntry(string Hash, string FileType, List<string> GamePaths, List<string> FilePaths, long OriginalSize, long CompressedSize, long Triangles)
{ {
public bool IsComputed => OriginalSize > 0 && CompressedSize > 0; public bool IsComputed => OriginalSize > 0 && CompressedSize > 0;
public async Task ComputeSizes(FileCacheManager fileCacheManager, CancellationToken token) public async Task ComputeSizes(FileCacheManager fileCacheManager, CancellationToken token)
@@ -194,6 +206,7 @@ public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable
} }
public long OriginalSize { get; private set; } = OriginalSize; public long OriginalSize { get; private set; } = OriginalSize;
public long CompressedSize { get; private set; } = CompressedSize; public long CompressedSize { get; private set; } = CompressedSize;
public long Triangles { get; private set; } = Triangles;
public Lazy<string> Format = new(() => public Lazy<string> Format = new(() =>
{ {

View File

@@ -48,7 +48,7 @@ public sealed class CommandManagerService : IDisposable
{ {
var splitArgs = args.ToLowerInvariant().Trim().Split(" ", StringSplitOptions.RemoveEmptyEntries); var splitArgs = args.ToLowerInvariant().Trim().Split(" ", StringSplitOptions.RemoveEmptyEntries);
if (splitArgs == null || splitArgs.Length == 0) if (splitArgs.Length == 0)
{ {
// Interpret this as toggling the UI // Interpret this as toggling the UI
if (_mareConfigService.Current.HasValidSetup()) if (_mareConfigService.Current.HasValidSetup())

View File

@@ -0,0 +1,72 @@
using Dalamud.Plugin.Services;
using Lumina;
using Lumina.Data.Files;
using MareSynchronos.FileCache;
using MareSynchronos.MareConfiguration;
using Microsoft.Extensions.Logging;
namespace MareSynchronos.Services;
public sealed class ModelAnalyzer
{
private readonly ILogger<ModelAnalyzer> _logger;
private readonly FileCacheManager _fileCacheManager;
private readonly TriangleCalculationConfigService _configService;
private readonly GameData _luminaGameData;
public ModelAnalyzer(ILogger<ModelAnalyzer> logger, FileCacheManager fileCacheManager,
TriangleCalculationConfigService configService, IDataManager gameData)
{
_logger = logger;
_fileCacheManager = fileCacheManager;
_configService = configService;
_luminaGameData = new GameData(gameData.GameData.DataPath.FullName);
}
public Task<long> GetTrianglesFromGamePath(string gamePath)
{
if (_configService.Current.TriangleDictionary.TryGetValue(gamePath, out var cachedTris))
return Task.FromResult(cachedTris);
_logger.LogInformation("Detected Model File {path}, calculating Tris", gamePath);
var file = _luminaGameData.GetFile<MdlFile>(gamePath);
if (file == null)
return Task.FromResult((long)0);
if (file.FileHeader.LodCount <= 0)
return Task.FromResult((long)0);
var meshIdx = file.Lods[0].MeshIndex;
var meshCnt = file.Lods[0].MeshCount;
var tris = file.Meshes.Skip(meshIdx).Take(meshCnt).Sum(p => p.IndexCount) / 3;
_logger.LogInformation("{filePath} => {tris} triangles", gamePath, tris);
_configService.Current.TriangleDictionary[gamePath] = tris;
_configService.Save();
return Task.FromResult(tris);
}
public Task<long> GetTrianglesByHash(string hash)
{
if (_configService.Current.TriangleDictionary.TryGetValue(hash, out var cachedTris))
return Task.FromResult(cachedTris);
var path = _fileCacheManager.GetFileCacheByHash(hash);
if (path == null || !path.ResolvedFilepath.EndsWith(".mdl", StringComparison.OrdinalIgnoreCase))
return Task.FromResult((long)0);
var filePath = path.ResolvedFilepath;
_logger.LogInformation("Detected Model File {path}, calculating Tris", filePath);
var file = _luminaGameData.GetFileFromDisk<MdlFile>(filePath);
if (file.FileHeader.LodCount <= 0)
return Task.FromResult((long)0);
var meshIdx = file.Lods[0].MeshIndex;
var meshCnt = file.Lods[0].MeshCount;
var tris = file.Meshes.Skip(meshIdx).Take(meshCnt).Sum(p => p.IndexCount) / 3;
_logger.LogInformation("{filePath} => {tris} triangles", filePath, tris);
_configService.Current.TriangleDictionary[hash] = tris;
_configService.Save();
return Task.FromResult(tris);
}
}

View File

@@ -242,8 +242,14 @@ public class DrawUserPair
if (_pair.LastAppliedDataSize >= 0) if (_pair.LastAppliedDataSize >= 0)
{ {
userPairText += UiSharedService.TooltipSeparator + (!_pair.IsVisible ? "(Last) " : string.Empty) + userPairText += UiSharedService.TooltipSeparator;
"Loaded Mods Size: " + UiSharedService.ByteToString(_pair.LastAppliedDataSize, true); userPairText += ((!_pair.IsPaired) ? "(Last) " : string.Empty) + "Mods Info" + Environment.NewLine;
userPairText += "Files Size: " + UiSharedService.ByteToString(_pair.LastAppliedDataSize, true);
if (_pair.LastAppliedDataTris >= 0)
{
userPairText += Environment.NewLine + "Triangle Count (excl. Vanilla): "
+ (_pair.LastAppliedDataTris > 1000 ? (_pair.LastAppliedDataTris / 1000d).ToString("0.0'k'") : _pair.LastAppliedDataTris);
}
} }
if (_syncedGroups.Any()) if (_syncedGroups.Any())

View File

@@ -11,15 +11,13 @@ namespace MareSynchronos.UI.Components.Popup;
public class BanUserPopupHandler : IPopupHandler public class BanUserPopupHandler : IPopupHandler
{ {
private readonly ApiController _apiController; private readonly ApiController _apiController;
private readonly UiSharedService _uiSharedService;
private string _banReason = string.Empty; private string _banReason = string.Empty;
private GroupFullInfoDto _group = null!; private GroupFullInfoDto _group = null!;
private Pair _reportedPair = null!; private Pair _reportedPair = null!;
public BanUserPopupHandler(ApiController apiController, UiSharedService uiSharedService) public BanUserPopupHandler(ApiController apiController)
{ {
_apiController = apiController; _apiController = apiController;
_uiSharedService = uiSharedService;
} }
public Vector2 PopupSize => new(500, 250); public Vector2 PopupSize => new(500, 250);

View File

@@ -13,11 +13,10 @@ public class PopupHandler : WindowMediatorSubscriberBase
{ {
protected bool _openPopup = false; protected bool _openPopup = false;
private readonly HashSet<IPopupHandler> _handlers; private readonly HashSet<IPopupHandler> _handlers;
private readonly UiSharedService _uiSharedService;
private IPopupHandler? _currentHandler = null; private IPopupHandler? _currentHandler = null;
public PopupHandler(ILogger<PopupHandler> logger, MareMediator mediator, IEnumerable<IPopupHandler> popupHandlers, PerformanceCollectorService performanceCollectorService, public PopupHandler(ILogger<PopupHandler> logger, MareMediator mediator, IEnumerable<IPopupHandler> popupHandlers,
UiSharedService uiSharedService) PerformanceCollectorService performanceCollectorService)
: base(logger, mediator, "MarePopupHandler", performanceCollectorService) : base(logger, mediator, "MarePopupHandler", performanceCollectorService)
{ {
Flags = ImGuiWindowFlags.NoBringToFrontOnFocus Flags = ImGuiWindowFlags.NoBringToFrontOnFocus
@@ -54,7 +53,6 @@ public class PopupHandler : WindowMediatorSubscriberBase
_currentHandler = _handlers.OfType<CensusPopupHandler>().Single(); _currentHandler = _handlers.OfType<CensusPopupHandler>().Single();
IsOpen = true; IsOpen = true;
}); });
_uiSharedService = uiSharedService;
} }
protected override void DrawInternal() protected override void DrawInternal()

View File

@@ -14,7 +14,6 @@ public class SelectTagForPairUi
{ {
private readonly TagHandler _tagHandler; private readonly TagHandler _tagHandler;
private readonly IdDisplayHandler _uidDisplayHandler; private readonly IdDisplayHandler _uidDisplayHandler;
private readonly UiSharedService _uiSharedService;
/// <summary> /// <summary>
/// The group UI is always open for a specific pair. This defines which pair the UI is open for. /// The group UI is always open for a specific pair. This defines which pair the UI is open for.
@@ -32,13 +31,12 @@ public class SelectTagForPairUi
/// </summary> /// </summary>
private string _tagNameToAdd = ""; private string _tagNameToAdd = "";
public SelectTagForPairUi(TagHandler tagHandler, IdDisplayHandler uidDisplayHandler, UiSharedService uiSharedService) public SelectTagForPairUi(TagHandler tagHandler, IdDisplayHandler uidDisplayHandler)
{ {
_show = false; _show = false;
_pair = null; _pair = null;
_tagHandler = tagHandler; _tagHandler = tagHandler;
_uidDisplayHandler = uidDisplayHandler; _uidDisplayHandler = uidDisplayHandler;
_uiSharedService = uiSharedService;
} }
public void Draw() public void Draw()

View File

@@ -161,7 +161,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
ImGui.TextUnformatted("Total size (compressed):"); ImGui.TextUnformatted("Total size (compressed):");
ImGui.SameLine(); ImGui.SameLine();
ImGui.TextUnformatted(UiSharedService.ByteToString(_cachedAnalysis!.Sum(c => c.Value.Sum(c => c.Value.CompressedSize)))); ImGui.TextUnformatted(UiSharedService.ByteToString(_cachedAnalysis!.Sum(c => c.Value.Sum(c => c.Value.CompressedSize))));
ImGui.TextUnformatted($"Total modded model triangles: {_cachedAnalysis.Sum(c => c.Value.Sum(f => f.Value.Triangles))}");
ImGui.Separator(); ImGui.Separator();
using var tabbar = ImRaii.TabBar("objectSelection"); using var tabbar = ImRaii.TabBar("objectSelection");
@@ -198,6 +198,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
ImGui.TextUnformatted($"{kvp.Key} size (compressed):"); ImGui.TextUnformatted($"{kvp.Key} size (compressed):");
ImGui.SameLine(); ImGui.SameLine();
ImGui.TextUnformatted(UiSharedService.ByteToString(kvp.Value.Sum(c => c.Value.CompressedSize))); ImGui.TextUnformatted(UiSharedService.ByteToString(kvp.Value.Sum(c => c.Value.CompressedSize)));
ImGui.TextUnformatted($"{kvp.Key} modded model triangles: {kvp.Value.Sum(f => f.Value.Triangles)}");
ImGui.Separator(); ImGui.Separator();
if (_selectedObjectTab != kvp.Key) if (_selectedObjectTab != kvp.Key)
@@ -337,8 +338,10 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
private void DrawTable(IGrouping<string, CharacterAnalyzer.FileDataEntry> fileGroup) private void DrawTable(IGrouping<string, CharacterAnalyzer.FileDataEntry> fileGroup)
{ {
using var table = ImRaii.Table("Analysis", string.Equals(fileGroup.Key, "tex", StringComparison.Ordinal) ? var tableColumns = string.Equals(fileGroup.Key, "tex", StringComparison.Ordinal)
(_enableBc7ConversionMode ? 7 : 6) : 5, ImGuiTableFlags.Sortable | ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.SizingFixedFit, ? (_enableBc7ConversionMode ? 7 : 6)
: (string.Equals(fileGroup.Key, "mdl", StringComparison.Ordinal) ? 6 : 5);
using var table = ImRaii.Table("Analysis", tableColumns, ImGuiTableFlags.Sortable | ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.SizingFixedFit,
new Vector2(0, 300)); new Vector2(0, 300));
if (!table.Success) return; if (!table.Success) return;
ImGui.TableSetupColumn("Hash"); ImGui.TableSetupColumn("Hash");
@@ -351,6 +354,10 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
ImGui.TableSetupColumn("Format"); ImGui.TableSetupColumn("Format");
if (_enableBc7ConversionMode) ImGui.TableSetupColumn("Convert to BC7"); if (_enableBc7ConversionMode) ImGui.TableSetupColumn("Convert to BC7");
} }
if (string.Equals(fileGroup.Key, "mdl", StringComparison.Ordinal))
{
ImGui.TableSetupColumn("Triangles");
}
ImGui.TableSetupScrollFreeze(0, 1); ImGui.TableSetupScrollFreeze(0, 1);
ImGui.TableHeadersRow(); ImGui.TableHeadersRow();
@@ -444,6 +451,12 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
} }
} }
} }
if (string.Equals(fileGroup.Key, "mdl", StringComparison.Ordinal))
{
ImGui.TableNextColumn();
ImGui.TextUnformatted(item.Triangles.ToString());
if (ImGui.IsItemClicked()) _selectedHash = item.Hash;
}
} }
} }
} }

View File

@@ -12,7 +12,6 @@ namespace MareSynchronos.UI;
public class GposeUi : WindowMediatorSubscriberBase public class GposeUi : WindowMediatorSubscriberBase
{ {
private readonly MareConfigService _configService; private readonly MareConfigService _configService;
private readonly UiSharedService _uiSharedService;
private readonly DalamudUtilService _dalamudUtil; private readonly DalamudUtilService _dalamudUtil;
private readonly FileDialogManager _fileDialogManager; private readonly FileDialogManager _fileDialogManager;
private readonly MareCharaFileManager _mareCharaFileManager; private readonly MareCharaFileManager _mareCharaFileManager;
@@ -21,15 +20,13 @@ public class GposeUi : WindowMediatorSubscriberBase
public GposeUi(ILogger<GposeUi> logger, MareCharaFileManager mareCharaFileManager, public GposeUi(ILogger<GposeUi> logger, MareCharaFileManager mareCharaFileManager,
DalamudUtilService dalamudUtil, FileDialogManager fileDialogManager, MareConfigService configService, DalamudUtilService dalamudUtil, FileDialogManager fileDialogManager, MareConfigService configService,
MareMediator mediator, PerformanceCollectorService performanceCollectorService, MareMediator mediator, PerformanceCollectorService performanceCollectorService)
UiSharedService uiSharedService)
: base(logger, mediator, "Mare Synchronos Gpose Import UI###MareSynchronosGposeUI", performanceCollectorService) : base(logger, mediator, "Mare Synchronos Gpose Import UI###MareSynchronosGposeUI", performanceCollectorService)
{ {
_mareCharaFileManager = mareCharaFileManager; _mareCharaFileManager = mareCharaFileManager;
_dalamudUtil = dalamudUtil; _dalamudUtil = dalamudUtil;
_fileDialogManager = fileDialogManager; _fileDialogManager = fileDialogManager;
_configService = configService; _configService = configService;
_uiSharedService = uiSharedService;
Mediator.Subscribe<GposeStartMessage>(this, (_) => StartGpose()); Mediator.Subscribe<GposeStartMessage>(this, (_) => StartGpose());
Mediator.Subscribe<GposeEndMessage>(this, (_) => EndGpose()); Mediator.Subscribe<GposeEndMessage>(this, (_) => EndGpose());
IsOpen = _dalamudUtil.IsInGpose; IsOpen = _dalamudUtil.IsInGpose;

View File

@@ -90,7 +90,11 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase
{ {
stream.Dispose(); stream.Dispose();
} }
catch { } catch
{
// do nothing
//
}
} }
base.Dispose(disposing); base.Dispose(disposing);
} }