something something performance

This commit is contained in:
Stanley Dimant
2024-09-04 15:30:19 +02:00
parent 6b3d79869b
commit 92182ba0b1
13 changed files with 412 additions and 31 deletions

View File

@@ -0,0 +1,16 @@
namespace MareSynchronos.MareConfiguration.Configurations;
public class PlayerPerformanceConfig : IMareConfiguration
{
public int Version { get; set; } = 1;
public bool ShowPerformanceIndicator { get; set; } = true;
public bool WarnOnExceedingThresholds { get; set; } = true;
public bool WarnOnPreferredPermissionsExceedingThresholds { get; set; } = false;
public int VRAMSizeWarningThresholdMiB { get; set; } = 375;
public int TrisWarningThresholdThousands { get; set; } = 165;
public bool AutoPausePlayersExceedingThresholds { get; set; } = false;
public bool AutoPausePlayersWithPreferredPermissionsExceedingThresholds { get; set; } = false;
public int VRAMSizeAutoPauseThresholdMiB { get; set; } = 550;
public int TrisAutoPauseThresholdThousands { get; set; } = 250;
public List<string> UIDsToIgnore { get; set; } = new();
}

View File

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

View File

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

View File

@@ -25,6 +25,7 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
private readonly FileDownloadManager _downloadManager;
private readonly FileCacheManager _fileDbManager;
private readonly XivDataAnalyzer _xivDataAnalyzer;
private readonly PlayerPerformanceService _playerPerformanceService;
private readonly GameObjectHandlerFactory _gameObjectHandlerFactory;
private readonly IpcManager _ipcManager;
private readonly IHostApplicationLifetime _lifetime;
@@ -41,8 +42,9 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
private Dictionary<ObjectKind, Guid?> _customizeIds = [];
private bool _redrawOnNextApplication = false;
private CombatData? _dataReceivedInDowntime;
public long LastAppliedDataSize { get; private set; }
public long LastAppliedDataBytes { get; private set; }
public long LastAppliedDataTris { get; private set; }
public long LastAppliedApproximateVRAMBytes { get; private set; }
public PairHandler(ILogger<PairHandler> logger, OnlineUserIdentDto onlineUser,
GameObjectHandlerFactory gameObjectHandlerFactory,
@@ -50,7 +52,7 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
PluginWarningNotificationService pluginWarningNotificationManager,
DalamudUtilService dalamudUtil, IHostApplicationLifetime lifetime,
FileCacheManager fileDbManager, MareMediator mediator,
XivDataAnalyzer modelAnalyzer) : base(logger, mediator)
XivDataAnalyzer modelAnalyzer, PlayerPerformanceService playerPerformanceService) : base(logger, mediator)
{
OnlineUser = onlineUser;
_gameObjectHandlerFactory = gameObjectHandlerFactory;
@@ -61,6 +63,7 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
_lifetime = lifetime;
_fileDbManager = fileDbManager;
_xivDataAnalyzer = modelAnalyzer;
_playerPerformanceService = playerPerformanceService;
_penumbraCollection = _ipcManager.Penumbra.CreateTemporaryCollectionAsync(logger, OnlineUser.User.UID).ConfigureAwait(false).GetAwaiter().GetResult();
Mediator.Subscribe<FrameworkUpdateMessage>(this, (_) => FrameworkUpdate());
@@ -103,7 +106,7 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
_applicationCancellationTokenSource = _applicationCancellationTokenSource?.CancelRecreate();
});
LastAppliedDataSize = -1;
LastAppliedDataBytes = -1;
LastAppliedDataTris = -1;
}
@@ -384,17 +387,28 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
int attempts = 0;
List<FileReplacementData> toDownloadReplacements = TryCalculateModdedDictionary(applicationBase, charaData, out moddedPaths, downloadToken);
LastAppliedApproximateVRAMBytes = -1;
while (toDownloadReplacements.Count > 0 && attempts++ <= 10 && !downloadToken.IsCancellationRequested)
{
_downloadManager.CancelDownload();
Logger.LogDebug("[BASE-{appBase}] Downloading missing files for player {name}, {kind}", applicationBase, PlayerName, updatedData);
if (toDownloadReplacements.Any())
{
Mediator.Publish(new EventMessage(new Event(PlayerName, OnlineUser.User, nameof(PairHandler), EventSeverity.Informational,
$"Starting download for {toDownloadReplacements.Count} files")));
var toDownloadFiles = await _downloadManager.InitiateDownloadList(_charaHandler!, toDownloadReplacements, downloadToken).ConfigureAwait(false);
if (!_playerPerformanceService.TryCalculateVRAMUsage(this, charaData, toDownloadFiles, out long vramDuringDl))
{
LastAppliedApproximateVRAMBytes = vramDuringDl;
_downloadManager.CancelDownload();
return;
}
LastAppliedApproximateVRAMBytes = vramDuringDl;
await _downloadManager.DownloadFiles(_charaHandler!, toDownloadReplacements, downloadToken).ConfigureAwait(false);
_downloadManager.CancelDownload();
}
if (downloadToken.IsCancellationRequested)
{
@@ -412,6 +426,13 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
await Task.Delay(TimeSpan.FromSeconds(2)).ConfigureAwait(false);
}
if (LastAppliedApproximateVRAMBytes == -1
&& !_playerPerformanceService.TryCalculateVRAMUsage(this, charaData, [], out long vramUsage))
{
LastAppliedApproximateVRAMBytes = vramUsage;
return;
}
}
downloadToken.ThrowIfCancellationRequested();
@@ -446,12 +467,18 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
{
await _ipcManager.Penumbra.SetTemporaryModsAsync(Logger, _applicationId, _penumbraCollection,
moddedPaths.ToDictionary(k => k.Key.GamePath, k => k.Value, StringComparer.Ordinal)).ConfigureAwait(false);
LastAppliedDataSize = -1;
LastAppliedDataBytes = -1;
LastAppliedDataTris = -1;
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;
if (LastAppliedDataBytes == -1) LastAppliedDataBytes = 0;
if (LastAppliedApproximateVRAMBytes == -1) LastAppliedApproximateVRAMBytes = 0;
LastAppliedDataBytes += path.Length;
if (path.Name.EndsWith(".tex", StringComparison.OrdinalIgnoreCase))
{
LastAppliedApproximateVRAMBytes += path.Length;
}
}
foreach (var key in moddedPaths.Keys.Where(k => !string.IsNullOrEmpty(k.Hash)))
{

View File

@@ -44,8 +44,9 @@ public class Pair
public bool IsVisible => CachedPlayer?.IsVisible ?? false;
public CharacterData? LastReceivedCharacterData { get; set; }
public string? PlayerName => CachedPlayer?.PlayerName ?? string.Empty;
public long LastAppliedDataSize => CachedPlayer?.LastAppliedDataSize ?? -1;
public long LastAppliedDataBytes => CachedPlayer?.LastAppliedDataBytes ?? -1;
public long LastAppliedDataTris => CachedPlayer?.LastAppliedDataTris ?? -1;
public long LastAppliedApproximateVRAMBytes => CachedPlayer?.LastAppliedApproximateVRAMBytes ?? -1;
public UserData UserData => UserPair.User;

View File

@@ -110,6 +110,7 @@ public sealed class Plugin : IDalamudPlugin
collection.AddSingleton<FileCompactor>();
collection.AddSingleton<TagHandler>();
collection.AddSingleton<IdDisplayHandler>();
collection.AddSingleton<PlayerPerformanceService>();
collection.AddSingleton((s) => new IpcProvider(s.GetRequiredService<ILogger<IpcProvider>>(),
pluginInterface,
s.GetRequiredService<MareCharaFileManager>(), s.GetRequiredService<DalamudUtilService>(),
@@ -150,6 +151,7 @@ public sealed class Plugin : IDalamudPlugin
collection.AddSingleton((s) => new ServerTagConfigService(pluginInterface.ConfigDirectory.FullName));
collection.AddSingleton((s) => new TransientConfigService(pluginInterface.ConfigDirectory.FullName));
collection.AddSingleton((s) => new XivDataStorageService(pluginInterface.ConfigDirectory.FullName));
collection.AddSingleton((s) => new PlayerPerformanceConfigService(pluginInterface.ConfigDirectory.FullName));
collection.AddSingleton((s) => new ConfigurationMigrator(s.GetRequiredService<ILogger<ConfigurationMigrator>>(), pluginInterface));
collection.AddSingleton<HubFactory>();
@@ -197,6 +199,7 @@ public sealed class Plugin : IDalamudPlugin
collection.AddHostedService(p => p.GetRequiredService<DalamudUtilService>());
collection.AddHostedService(p => p.GetRequiredService<PerformanceCollectorService>());
collection.AddHostedService(p => p.GetRequiredService<DtrEntry>());
collection.AddHostedService(p => p.GetRequiredService<PlayerPerformanceService>());
collection.AddHostedService(p => p.GetRequiredService<EventAggregator>());
collection.AddHostedService(p => p.GetRequiredService<IpcProvider>());
collection.AddHostedService(p => p.GetRequiredService<MarePlugin>());

View File

@@ -0,0 +1,134 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Extensions;
using MareSynchronos.FileCache;
using MareSynchronos.MareConfiguration;
using MareSynchronos.PlayerData.Handlers;
using MareSynchronos.PlayerData.Pairs;
using MareSynchronos.Services.Mediator;
using MareSynchronos.UI;
using MareSynchronos.Utils;
using MareSynchronos.WebAPI;
using MareSynchronos.WebAPI.Files.Models;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace MareSynchronos.Services;
public class PlayerPerformanceService : IHostedService
{
private readonly ILogger<PlayerPerformanceService> _logger;
private readonly MareMediator _mediator;
private readonly PlayerPerformanceConfigService _playerPerformanceConfigService;
private readonly FileCacheManager _fileCacheManager;
private readonly PairManager _pairManager;
private readonly ApiController _apiController;
public PlayerPerformanceService(ILogger<PlayerPerformanceService> logger, MareMediator mediator,
PlayerPerformanceConfigService playerPerformanceConfigService, FileCacheManager fileCacheManager,
PairManager pairManager, ApiController apiController)
{
_logger = logger;
_mediator = mediator;
_playerPerformanceConfigService = playerPerformanceConfigService;
_fileCacheManager = fileCacheManager;
_pairManager = pairManager;
_apiController = apiController;
}
public Task StartAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public bool TryCalculateVRAMUsage(PairHandler pairHandler, CharacterData charaData, List<DownloadFileTransfer> toDownloadFiles, out long vramUsage)
{
var config = _playerPerformanceConfigService.Current;
var pair = _pairManager.GetOnlineUserPairs().First(p => string.Equals(p.UserData.UID, pairHandler.OnlineUser.User.UID, StringComparison.OrdinalIgnoreCase));
vramUsage = 0;
if (!charaData.FileReplacements.TryGetValue(API.Data.Enum.ObjectKind.Player, out List<FileReplacementData>? playerReplacements))
return true;
var moddedTextureHashes = playerReplacements.Where(p => string.IsNullOrEmpty(p.FileSwapPath) && p.GamePaths.Any(g => g.EndsWith("tex", StringComparison.OrdinalIgnoreCase)))
.Select(p => p.Hash)
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
foreach (var hash in moddedTextureHashes.ToList())
{
long fileSize = 0;
var download = toDownloadFiles.Find(f => string.Equals(hash, f.Hash, StringComparison.OrdinalIgnoreCase));
if (download != null)
{
fileSize = download.Total;
}
else
{
var fileEntry = _fileCacheManager.GetFileCacheByHash(hash);
if (fileEntry == null) continue;
if (fileEntry.Size == null)
{
fileEntry.Size = new FileInfo(fileEntry.ResolvedFilepath).Length;
_fileCacheManager.UpdateHashedFile(fileEntry, computeProperties: true);
}
fileSize = fileEntry.Size.Value;
}
vramUsage += fileSize;
}
_logger.LogDebug("Calculated VRAM usage for {p}", pairHandler);
// no warning of any kind on ignored pairs
if (config.UIDsToIgnore
.Exists(uid => string.Equals(uid, pair.UserData.Alias, StringComparison.Ordinal) || string.Equals(uid, pair.UserData.UID, StringComparison.Ordinal)))
return true;
bool isPrefPerm = pair.UserPair.OwnPermissions.HasFlag(API.Data.Enum.UserPermissions.Sticky);
// now check auto pause
if (CheckForThreshold(config.AutoPausePlayersExceedingThresholds, config.VRAMSizeAutoPauseThresholdMiB * 1024 * 1024,
vramUsage, config.AutoPausePlayersWithPreferredPermissionsExceedingThresholds, isPrefPerm))
{
_mediator.Publish(new NotificationMessage($"{pair.PlayerName} ({pair.UserData.AliasOrUID}) automatically paused",
$"Player {pair.PlayerName} exceeded your configured VRAM auto pause threshold (" +
$"{UiSharedService.ByteToString(vramUsage, addSuffix: true)}/{config.VRAMSizeAutoPauseThresholdMiB}MiB)" +
$" and has been automatically paused.",
MareConfiguration.Models.NotificationType.Warning));
// pause
var perm = pair.UserPair.OwnPermissions.DeepClone();
perm.SetPaused(paused: true);
_ = _apiController.SetBulkPermissions(new(
new(StringComparer.Ordinal) { { pair.UserData.UID, perm } },
new(StringComparer.Ordinal)));
return false;
}
// and fucking warnings
if (CheckForThreshold(config.WarnOnExceedingThresholds, config.VRAMSizeWarningThresholdMiB * 1024 * 1024,
vramUsage, config.WarnOnPreferredPermissionsExceedingThresholds, isPrefPerm))
{
_mediator.Publish(new NotificationMessage($"{pair.PlayerName} ({pair.UserData.AliasOrUID}) exceeds performance threshold",
$"Player {pair.PlayerName} exceeds your configured VRAM warning threshold (" +
$"{UiSharedService.ByteToString(vramUsage, true)}/{config.VRAMSizeWarningThresholdMiB}MiB).",
MareConfiguration.Models.NotificationType.Warning));
return true;
}
return true;
}
private static bool CheckForThreshold(bool thresholdEnabled, long threshold, long value, bool checkForPrefPerm, bool isPrefPerm) =>
thresholdEnabled && threshold > 0 && threshold < value && ((checkForPrefPerm && isPrefPerm) || !isPrefPerm);
}

View File

@@ -169,7 +169,7 @@ public class ServerConfigurationManager
Save();
}
internal void AddCurrentCharacterToServer(int serverSelectionIndex = -1, bool addLastSecretKey = false)
internal void AddCurrentCharacterToServer(int serverSelectionIndex = -1)
{
if (serverSelectionIndex == -1) serverSelectionIndex = CurrentServerIndex;
var server = GetServerByIndex(serverSelectionIndex);
@@ -181,7 +181,7 @@ public class ServerConfigurationManager
{
CharacterName = _dalamudUtil.GetPlayerNameAsync().GetAwaiter().GetResult(),
WorldId = _dalamudUtil.GetHomeWorldIdAsync().GetAwaiter().GetResult(),
SecretKeyIdx = addLastSecretKey ? server.SecretKeys.Last().Key : -1,
SecretKeyIdx = server.SecretKeys.Last().Key,
});
Save();
}
@@ -189,7 +189,10 @@ public class ServerConfigurationManager
internal void AddEmptyCharacterToServer(int serverSelectionIndex)
{
var server = GetServerByIndex(serverSelectionIndex);
server.Authentications.Add(new Authentication());
server.Authentications.Add(new Authentication()
{
SecretKeyIdx = server.SecretKeys.Any() ? server.SecretKeys.First().Key : -1,
});
Save();
}

View File

@@ -177,7 +177,7 @@ public sealed class XivDataAnalyzer
public Task<long> GetTrianglesByHash(string hash)
{
if (_configService.Current.TriangleDictionary.TryGetValue(hash, out var cachedTris))
if (_configService.Current.TriangleDictionary.TryGetValue(hash, out var cachedTris) && cachedTris > 0)
return Task.FromResult(cachedTris);
var path = _fileCacheManager.GetFileCacheByHash(hash);
@@ -192,13 +192,29 @@ public sealed class XivDataAnalyzer
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;
long tris = 0;
for (int i = 0; i < file.FileHeader.LodCount; i++)
{
try
{
var meshIdx = file.Lods[i].MeshIndex;
var meshCnt = file.Lods[i].MeshCount;
tris = file.Meshes.Skip(meshIdx).Take(meshCnt).Sum(p => p.IndexCount) / 3;
}
catch (Exception ex)
{
_logger.LogDebug(ex, "Could not load lod mesh {mesh} from {path}", i, filePath);
continue;
}
if (tris > 0)
{
_logger.LogDebug("{filePath} => {tris} triangles", filePath, tris);
_configService.Current.TriangleDictionary[hash] = tris;
_configService.Save();
break;
}
}
return Task.FromResult(tris);
}
catch (Exception e)

View File

@@ -228,11 +228,15 @@ public class DrawUserPair
userPairText += UiSharedService.TooltipSeparator + "You are directly Paired";
}
if (_pair.LastAppliedDataSize >= 0)
if (_pair.LastAppliedDataBytes >= 0)
{
userPairText += UiSharedService.TooltipSeparator;
userPairText += ((!_pair.IsPaired) ? "(Last) " : string.Empty) + "Mods Info" + Environment.NewLine;
userPairText += "Files Size: " + UiSharedService.ByteToString(_pair.LastAppliedDataSize, true);
userPairText += "Files Size: " + UiSharedService.ByteToString(_pair.LastAppliedDataBytes, true);
if (_pair.LastAppliedApproximateVRAMBytes >= 0)
{
userPairText += Environment.NewLine + "Approximate max. VRAM Usage: " + UiSharedService.ByteToString(_pair.LastAppliedApproximateVRAMBytes, true);
}
if (_pair.LastAppliedDataTris >= 0)
{
userPairText += Environment.NewLine + "Triangle Count (excl. Vanilla): "

View File

@@ -244,7 +244,7 @@ public partial class IntroUi : WindowMediatorSubscriberBase
FriendlyName = $"Secret Key added on Setup ({DateTime.Now:yyyy-MM-dd})",
Key = _secretKey,
});
_serverConfigurationManager.AddCurrentCharacterToServer(addLastSecretKey: true);
_serverConfigurationManager.AddCurrentCharacterToServer();
}
else
{

View File

@@ -44,6 +44,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
private readonly PairManager _pairManager;
private readonly PerformanceCollectorService _performanceCollector;
private readonly ServerConfigurationManager _serverConfigurationManager;
private readonly PlayerPerformanceConfigService _playerPerformanceConfigService;
private readonly UiSharedService _uiShared;
private bool _deleteAccountPopupModalShown = false;
private bool _deleteFilesPopupModalShown = false;
@@ -64,6 +65,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
UiSharedService uiShared, MareConfigService configService,
MareCharaFileManager mareCharaFileManager, PairManager pairManager,
ServerConfigurationManager serverConfigurationManager,
PlayerPerformanceConfigService playerPerformanceConfigService,
MareMediator mediator, PerformanceCollectorService performanceCollector,
FileUploadManager fileTransferManager,
FileTransferOrchestrator fileTransferOrchestrator,
@@ -76,6 +78,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
_mareCharaFileManager = mareCharaFileManager;
_pairManager = pairManager;
_serverConfigurationManager = serverConfigurationManager;
_playerPerformanceConfigService = playerPerformanceConfigService;
_performanceCollector = performanceCollector;
_fileTransferManager = fileTransferManager;
_fileTransferOrchestrator = fileTransferOrchestrator;
@@ -118,6 +121,8 @@ public class SettingsUi : WindowMediatorSubscriberBase
public override void OnClose()
{
_uiShared.EditTrackerPosition = false;
_uidToAddForIgnore = string.Empty;
base.OnClose();
}
@@ -1316,6 +1321,156 @@ public class SettingsUi : WindowMediatorSubscriberBase
}
}
private void DrawPerformance()
{
_uiShared.BigText("Performance Settings");
UiSharedService.TextWrapped("The configuration options here are to give you more informed warnings and automation when it comes to other performance-intensive synced players.");
ImGui.Dummy(new Vector2(10));
ImGui.Separator();
ImGui.Dummy(new Vector2(10));
bool showPerformanceIndicator = _playerPerformanceConfigService.Current.ShowPerformanceIndicator;
if (ImGui.Checkbox("Show performance indicator", ref showPerformanceIndicator))
{
_playerPerformanceConfigService.Current.ShowPerformanceIndicator = showPerformanceIndicator;
_playerPerformanceConfigService.Save();
}
_uiShared.DrawHelpText("Will show a performance indicator when players exceed defined thresholds in the main UI." + Environment.NewLine + "Will use warning thresholds.");
bool warnOnExceedingThresholds = _playerPerformanceConfigService.Current.WarnOnExceedingThresholds;
if (ImGui.Checkbox("Warn on loading in players exceeding performance thresholds", ref warnOnExceedingThresholds))
{
_playerPerformanceConfigService.Current.WarnOnExceedingThresholds = warnOnExceedingThresholds;
_playerPerformanceConfigService.Save();
}
_uiShared.DrawHelpText("Mare will print a warning in chat once per session of meeting those people. Will not warn on players with preferred permissions.");
using (ImRaii.Disabled(!warnOnExceedingThresholds))
{
using var indent = ImRaii.PushIndent();
var warnOnPref = _playerPerformanceConfigService.Current.WarnOnPreferredPermissionsExceedingThresholds;
if (ImGui.Checkbox("Warn also on players with preferred permissions", ref warnOnPref))
{
_playerPerformanceConfigService.Current.WarnOnPreferredPermissionsExceedingThresholds = warnOnPref;
_playerPerformanceConfigService.Save();
}
_uiShared.DrawHelpText("Mare will also print warnings for players where you enabled preferred permissions.");
}
using (ImRaii.Disabled(!showPerformanceIndicator && !warnOnExceedingThresholds))
{
var vram = _playerPerformanceConfigService.Current.VRAMSizeWarningThresholdMiB;
var tris = _playerPerformanceConfigService.Current.TrisWarningThresholdThousands;
ImGui.SetNextItemWidth(100);
if (ImGui.InputInt("Warning VRAM threshold", ref vram))
{
_playerPerformanceConfigService.Current.VRAMSizeWarningThresholdMiB = vram;
_playerPerformanceConfigService.Save();
}
ImGui.SameLine();
ImGui.Text("(MiB)");
_uiShared.DrawHelpText("Limit in MiB of approximate VRAM usage to trigger warning or performance indicator on UI." + UiSharedService.TooltipSeparator
+ "Default: 375 MiB");
ImGui.SetNextItemWidth(100);
if (ImGui.InputInt("Warning Triangle threshold", ref tris))
{
_playerPerformanceConfigService.Current.TrisWarningThresholdThousands = tris;
_playerPerformanceConfigService.Save();
}
ImGui.SameLine();
ImGui.Text("(thousand triangles)");
_uiShared.DrawHelpText("Limit in approximate used triangles from mods to trigger warning or performance indicator on UI." + UiSharedService.TooltipSeparator
+ "Default: 165 thousand");
}
ImGui.Dummy(new Vector2(10));
bool autoPause = _playerPerformanceConfigService.Current.AutoPausePlayersExceedingThresholds;
bool autoPauseEveryone = _playerPerformanceConfigService.Current.AutoPausePlayersWithPreferredPermissionsExceedingThresholds;
if (ImGui.Checkbox("Automatically pause players exceeding thresholds", ref autoPause))
{
_playerPerformanceConfigService.Current.AutoPausePlayersExceedingThresholds = autoPause;
_playerPerformanceConfigService.Save();
}
_uiShared.DrawHelpText("When enabled, it will automatically pause all players without preferred permissions that exceed the thresholds defined below." + Environment.NewLine
+ "Will print a warning in chat when a player got paused automatically."
+ UiSharedService.TooltipSeparator + "Warning: this will not automatically unpause those people again, you will have to do this manually.");
using (ImRaii.Disabled(!autoPause))
{
using var indent = ImRaii.PushIndent();
if (ImGui.Checkbox("Automatically pause also players with preferred permissions", ref autoPauseEveryone))
{
_playerPerformanceConfigService.Current.AutoPausePlayersWithPreferredPermissionsExceedingThresholds = autoPauseEveryone;
_playerPerformanceConfigService.Save();
}
_uiShared.DrawHelpText("When enabled, will automatically pause all players regardless of preferred permissions that exceed thresholds defined below." + UiSharedService.TooltipSeparator +
"Warning: this will not automatically unpause those people again, you will have to do this manually." + UiSharedService.TooltipSeparator
+ "Default: 550 MiB");
var vramAuto = _playerPerformanceConfigService.Current.VRAMSizeAutoPauseThresholdMiB;
var trisAuto = _playerPerformanceConfigService.Current.TrisAutoPauseThresholdThousands;
ImGui.SetNextItemWidth(100);
if (ImGui.InputInt("Auto Pause VRAM threshold", ref vramAuto))
{
_playerPerformanceConfigService.Current.VRAMSizeAutoPauseThresholdMiB = vramAuto;
_playerPerformanceConfigService.Save();
}
ImGui.SameLine();
ImGui.Text("(MiB)");
_uiShared.DrawHelpText("When a loading in player and their VRAM usage exceeds this amount, automatically pauses the synced player.");
ImGui.SetNextItemWidth(100);
if (ImGui.InputInt("Auto Pause Triangle threshold", ref trisAuto))
{
_playerPerformanceConfigService.Current.TrisAutoPauseThresholdThousands = trisAuto;
_playerPerformanceConfigService.Save();
}
ImGui.SameLine();
ImGui.Text("(thousand triangles)");
_uiShared.DrawHelpText("When a loading in player and their triangle count exceeds this amount, automatically pauses the synced player." + UiSharedService.TooltipSeparator
+ "Default: 250 thousand");
}
ImGui.Dummy(new Vector2(10));
_uiShared.BigText("Whitelisted UIDs");
UiSharedService.TextWrapped("The entries in the list below will be ignored for all warnings and auto pause operations.");
ImGui.Dummy(new Vector2(10));
ImGui.SetNextItemWidth(200);
ImGui.InputText("##ignoreuid", ref _uidToAddForIgnore, 20);
ImGui.SameLine();
using (ImRaii.Disabled(string.IsNullOrEmpty(_uidToAddForIgnore)))
{
if (_uiShared.IconTextButton(FontAwesomeIcon.Plus, "Add UID to whitelist"))
{
if (!_playerPerformanceConfigService.Current.UIDsToIgnore.Contains(_uidToAddForIgnore, StringComparer.Ordinal))
{
_playerPerformanceConfigService.Current.UIDsToIgnore.Add(_uidToAddForIgnore);
}
_uidToAddForIgnore = string.Empty;
}
}
_uiShared.DrawHelpText("Hint: UIDs are case sensitive.");
var playerList = _playerPerformanceConfigService.Current.UIDsToIgnore;
ImGui.SetNextItemWidth(200);
using (var lb = ImRaii.ListBox("UID whitelist"))
{
if (lb)
{
for (int i = 0; i < playerList.Count; i++)
{
bool shouldBeSelected = _selectedEntry == i;
if (ImGui.Selectable(playerList[i] + "##" + i, shouldBeSelected))
{
_selectedEntry = i;
}
}
}
}
using (ImRaii.Disabled(_selectedEntry == -1))
{
if (_uiShared.IconTextButton(FontAwesomeIcon.Trash, "Delete selected UID"))
{
_playerPerformanceConfigService.Current.UIDsToIgnore.RemoveAt(_selectedEntry);
_selectedEntry = -1;
_playerPerformanceConfigService.Save();
}
}
}
private string _uidToAddForIgnore = string.Empty;
private int _selectedEntry = -1;
private void DrawSettingsContent()
{
if (_apiController.ServerState is ServerState.Connected)
@@ -1349,6 +1504,12 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.EndTabItem();
}
if (ImGui.BeginTabItem("Performance"))
{
DrawPerformance();
ImGui.EndTabItem();
}
if (ImGui.BeginTabItem("Export & Storage"))
{
DrawFileStorageSettings();

View File

@@ -210,7 +210,7 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase
}
}
private async Task DownloadFilesInternal(GameObjectHandler gameObjectHandler, List<FileReplacementData> fileReplacement, CancellationToken ct)
public async Task<List<DownloadFileTransfer>> InitiateDownloadList(GameObjectHandler gameObjectHandler, List<FileReplacementData> fileReplacement, CancellationToken ct)
{
Logger.LogDebug("Download start: {id}", gameObjectHandler.Name);
@@ -221,9 +221,6 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase
Logger.LogDebug("Files with size 0 or less: {files}", string.Join(", ", downloadFileInfoFromService.Where(f => f.Size <= 0).Select(f => f.Hash)));
CurrentDownloads = downloadFileInfoFromService.Distinct().Select(d => new DownloadFileTransfer(d))
.Where(d => d.CanBeTransferred).ToList();
foreach (var dto in downloadFileInfoFromService.Where(c => c.IsForbidden))
{
if (!_orchestrator.ForbiddenTransfers.Exists(f => string.Equals(f.Hash, dto.Hash, StringComparison.Ordinal)))
@@ -232,7 +229,13 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase
}
}
var downloadGroups = CurrentDownloads.Where(f => f.CanBeTransferred).GroupBy(f => f.DownloadUri.Host + ":" + f.DownloadUri.Port, StringComparer.Ordinal);
return CurrentDownloads = downloadFileInfoFromService.Distinct().Select(d => new DownloadFileTransfer(d))
.Where(d => d.CanBeTransferred).ToList();
}
private async Task DownloadFilesInternal(GameObjectHandler gameObjectHandler, List<FileReplacementData> fileReplacement, CancellationToken ct)
{
var downloadGroups = CurrentDownloads.GroupBy(f => f.DownloadUri.Host + ":" + f.DownloadUri.Port, StringComparer.Ordinal);
foreach (var downloadGroup in downloadGroups)
{