From 4da2548e0323bb3b3e97a4b90a7b83e105671277 Mon Sep 17 00:00:00 2001 From: azyges Date: Mon, 5 Jan 2026 07:48:14 +0900 Subject: [PATCH] just misc --- .../Interop/BlockedCharacterHandler.cs | 24 ++++++-- .../Configurations/PlayerPerformanceConfig.cs | 2 +- LightlessSync/Plugin.cs | 4 +- LightlessSync/Services/DalamudUtilService.cs | 2 +- .../Services/ModelDecimation/MdlDecimator.cs | 27 ++++++++- LightlessSync/UI/SettingsUi.cs | 56 ++++++++++++++++--- LightlessSync/UI/ZoneChatUi.cs | 14 ++++- 7 files changed, 107 insertions(+), 22 deletions(-) diff --git a/LightlessSync/Interop/BlockedCharacterHandler.cs b/LightlessSync/Interop/BlockedCharacterHandler.cs index 0ad3c80..675bf3b 100644 --- a/LightlessSync/Interop/BlockedCharacterHandler.cs +++ b/LightlessSync/Interop/BlockedCharacterHandler.cs @@ -1,4 +1,5 @@ using Dalamud.Plugin.Services; +using Dalamud.Game.ClientState.Objects.SubKinds; using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.UI.Info; using Microsoft.Extensions.Logging; @@ -11,24 +12,35 @@ public unsafe class BlockedCharacterHandler private readonly Dictionary _blockedCharacterCache = new(); private readonly ILogger _logger; + private readonly IObjectTable _objectTable; - public BlockedCharacterHandler(ILogger logger, IGameInteropProvider gameInteropProvider) + public BlockedCharacterHandler(ILogger logger, IGameInteropProvider gameInteropProvider, IObjectTable objectTable) { gameInteropProvider.InitializeFromAttributes(this); _logger = logger; + _objectTable = objectTable; } - private static CharaData GetIdsFromPlayerPointer(nint ptr) + private CharaData? TryGetIdsFromPlayerPointer(nint ptr, ushort objectIndex) { - if (ptr == nint.Zero) return new(0, 0); - var castChar = ((BattleChara*)ptr); + if (ptr == nint.Zero || objectIndex >= 200) + return null; + + var obj = _objectTable[objectIndex]; + if (obj is not IPlayerCharacter player || player.Address != ptr) + return null; + + var castChar = (BattleChara*)player.Address; return new(castChar->Character.AccountId, castChar->Character.ContentId); } - public bool IsCharacterBlocked(nint ptr, out bool firstTime) + public bool IsCharacterBlocked(nint ptr, ushort objectIndex, out bool firstTime) { firstTime = false; - var combined = GetIdsFromPlayerPointer(ptr); + var combined = TryGetIdsFromPlayerPointer(ptr, objectIndex); + if (combined == null) + return false; + if (_blockedCharacterCache.TryGetValue(combined, out var isBlocked)) return isBlocked; diff --git a/LightlessSync/LightlessConfiguration/Configurations/PlayerPerformanceConfig.cs b/LightlessSync/LightlessConfiguration/Configurations/PlayerPerformanceConfig.cs index 5cdfd4e..462a63f 100644 --- a/LightlessSync/LightlessConfiguration/Configurations/PlayerPerformanceConfig.cs +++ b/LightlessSync/LightlessConfiguration/Configurations/PlayerPerformanceConfig.cs @@ -24,7 +24,7 @@ public class PlayerPerformanceConfig : ILightlessConfiguration public bool KeepOriginalTextureFiles { get; set; } = false; public bool SkipTextureDownscaleForPreferredPairs { get; set; } = true; public bool EnableModelDecimation { get; set; } = false; - public int ModelDecimationTriangleThreshold { get; set; } = 50_000; + public int ModelDecimationTriangleThreshold { get; set; } = 20_000; public double ModelDecimationTargetRatio { get; set; } = 0.8; public bool KeepOriginalModelFiles { get; set; } = true; public bool SkipModelDecimationForPreferredPairs { get; set; } = true; diff --git a/LightlessSync/Plugin.cs b/LightlessSync/Plugin.cs index fafd1c7..b760070 100644 --- a/LightlessSync/Plugin.cs +++ b/LightlessSync/Plugin.cs @@ -123,6 +123,7 @@ public sealed class Plugin : IDalamudPlugin services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); @@ -180,7 +181,8 @@ public sealed class Plugin : IDalamudPlugin services.AddSingleton(sp => new BlockedCharacterHandler( sp.GetRequiredService>(), - gameInteropProvider)); + gameInteropProvider, + objectTable)); services.AddSingleton(sp => new IpcProvider( sp.GetRequiredService>(), diff --git a/LightlessSync/Services/DalamudUtilService.cs b/LightlessSync/Services/DalamudUtilService.cs index b278667..28345d2 100644 --- a/LightlessSync/Services/DalamudUtilService.cs +++ b/LightlessSync/Services/DalamudUtilService.cs @@ -1010,7 +1010,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber if (actor.ObjectIndex >= 200) continue; - if (_blockedCharacterHandler.IsCharacterBlocked(playerAddress, out bool firstTime) && firstTime) + if (_blockedCharacterHandler.IsCharacterBlocked(playerAddress, actor.ObjectIndex, out bool firstTime) && firstTime) { _logger.LogTrace("Skipping character {addr}, blocked/muted", playerAddress.ToString("X")); continue; diff --git a/LightlessSync/Services/ModelDecimation/MdlDecimator.cs b/LightlessSync/Services/ModelDecimation/MdlDecimator.cs index 36feb4a..a7af13f 100644 --- a/LightlessSync/Services/ModelDecimation/MdlDecimator.cs +++ b/LightlessSync/Services/ModelDecimation/MdlDecimator.cs @@ -1,6 +1,7 @@ using Lumina.Data.Parsing; using Lumina.Extensions; using MeshDecimator; +using MeshDecimator.Algorithms; using MeshDecimator.Math; using Microsoft.Extensions.Logging; using Penumbra.GameData.Files.ModelStructs; @@ -94,6 +95,8 @@ internal static class MdlDecimator var newVertexBuffer = new List(mdl.VertexBufferSize[lodIndex] > 0 ? (int)mdl.VertexBufferSize[lodIndex] : 0); var newIndexBuffer = new List(mdl.IndexBufferSize[lodIndex] > 0 ? (int)(mdl.IndexBufferSize[lodIndex] / sizeof(ushort)) : 0); var subMeshCursor = 0; + DecimationAlgorithm? decimationAlgorithm = null; + int? decimationUvChannelCount = null; for (var meshIndex = 0; meshIndex < meshes.Length; meshIndex++) { @@ -119,6 +122,8 @@ internal static class MdlDecimator out vertexStreams, out indices, out decimated, + ref decimationAlgorithm, + ref decimationUvChannelCount, logger)) { updatedSubMeshes = OffsetSubMeshes(updatedSubMeshes, meshIndexBase); @@ -309,6 +314,8 @@ internal static class MdlDecimator out byte[][] vertexStreams, out int[] indices, out bool decimated, + ref DecimationAlgorithm? decimationAlgorithm, + ref int? decimationUvChannelCount, MsLogger logger) { updatedMesh = mesh; @@ -352,8 +359,7 @@ internal static class MdlDecimator } var meshDecimatorMesh = BuildMesh(decoded, subMeshIndices); - var algorithm = MeshDecimation.CreateAlgorithm(Algorithm.Default); - algorithm.Logger = logger; + var algorithm = GetOrCreateAlgorithm(format, ref decimationAlgorithm, ref decimationUvChannelCount, logger); algorithm.Initialize(meshDecimatorMesh); algorithm.DecimateMesh(targetTriangles); var decimatedMesh = algorithm.ToMesh(); @@ -374,6 +380,23 @@ internal static class MdlDecimator return true; } + private static DecimationAlgorithm GetOrCreateAlgorithm( + VertexFormat format, + ref DecimationAlgorithm? decimationAlgorithm, + ref int? decimationUvChannelCount, + MsLogger logger) + { + var uvChannelCount = format.UvChannelCount; + if (decimationAlgorithm == null || decimationUvChannelCount != uvChannelCount) + { + decimationAlgorithm = MeshDecimation.CreateAlgorithm(Algorithm.Default); + decimationAlgorithm.Logger = logger; + decimationUvChannelCount = uvChannelCount; + } + + return decimationAlgorithm; + } + private static Mesh BuildMesh(DecodedMeshData decoded, int[][] subMeshIndices) { var mesh = new Mesh(decoded.Positions, subMeshIndices); diff --git a/LightlessSync/UI/SettingsUi.cs b/LightlessSync/UI/SettingsUi.cs index ea0d0e1..aa5db82 100644 --- a/LightlessSync/UI/SettingsUi.cs +++ b/LightlessSync/UI/SettingsUi.cs @@ -3635,8 +3635,31 @@ public class SettingsUi : WindowMediatorSubscriberBase new SeStringUtils.RichTextEntry("destructive", UIColors.Get("DimRed"), true), new SeStringUtils.RichTextEntry(" process and may cause broken or incorrect character appearances.")); + _uiShared.DrawNoteLine("! ", UIColors.Get("DimRed"), - new SeStringUtils.RichTextEntry("this shit is placeholder still owo")); + new SeStringUtils.RichTextEntry("This feature is encouraged to help "), + new SeStringUtils.RichTextEntry("lower-end systems with limited VRAM", UIColors.Get("LightlessYellow"), true), + new SeStringUtils.RichTextEntry(" and for use in "), + new SeStringUtils.RichTextEntry("performance-critical scenarios", UIColors.Get("LightlessYellow"), true), + new SeStringUtils.RichTextEntry(".")); + + _uiShared.DrawNoteLine("! ", UIColors.Get("DimRed"), + new SeStringUtils.RichTextEntry("Runtime decimation "), + new SeStringUtils.RichTextEntry("MAY", UIColors.Get("DimRed"), true), + new SeStringUtils.RichTextEntry(" cause higher load on the system when processing downloads.")); + + _uiShared.DrawNoteLine("!!! ", UIColors.Get("DimRed"), + new SeStringUtils.RichTextEntry("When enabled, we cannot provide support for appearance issues caused by this setting!", UIColors.Get("DimRed"), true)); + + ImGui.Dummy(new Vector2(15)); + + _uiShared.DrawNoteLine("! ", UIColors.Get("LightlessGreen"), + new SeStringUtils.RichTextEntry("If a mesh exceeds the "), + new SeStringUtils.RichTextEntry("triangle threshold", UIColors.Get("LightlessGreen"), true), + new SeStringUtils.RichTextEntry(", it will be decimated automatically to the set "), + new SeStringUtils.RichTextEntry("target triangle ratio", UIColors.Get("LightlessGreen"), true), + new SeStringUtils.RichTextEntry(". This will reduce quality of the mesh or may break it's intended structure.")); + var performanceConfig = _playerPerformanceConfigService.Current; var enableDecimation = performanceConfig.EnableModelDecimation; @@ -3667,9 +3690,9 @@ public class SettingsUi : WindowMediatorSubscriberBase var triangleThreshold = performanceConfig.ModelDecimationTriangleThreshold; ImGui.SetNextItemWidth(300 * ImGuiHelpers.GlobalScale); - if (ImGui.SliderInt("Decimate models above", ref triangleThreshold, 10_000, 100_000)) + if (ImGui.SliderInt("Decimate models above", ref triangleThreshold, 8_000, 100_000)) { - performanceConfig.ModelDecimationTriangleThreshold = Math.Clamp(triangleThreshold, 10_000, 100_000); + performanceConfig.ModelDecimationTriangleThreshold = Math.Clamp(triangleThreshold, 8_000, 100_000); _playerPerformanceConfigService.Save(); } ImGui.SameLine(); @@ -3677,7 +3700,7 @@ public class SettingsUi : WindowMediatorSubscriberBase _uiShared.DrawHelpText($"Models below this triangle count are left untouched.{UiSharedService.TooltipSeparator}Default: 50,000"); var targetPercent = (float)(performanceConfig.ModelDecimationTargetRatio * 100.0); - var clampedPercent = Math.Clamp(targetPercent, 70f, 99f); + var clampedPercent = Math.Clamp(targetPercent, 60f, 99f); if (Math.Abs(clampedPercent - targetPercent) > float.Epsilon) { performanceConfig.ModelDecimationTargetRatio = clampedPercent / 100.0; @@ -3685,17 +3708,30 @@ public class SettingsUi : WindowMediatorSubscriberBase targetPercent = clampedPercent; } ImGui.SetNextItemWidth(300 * ImGuiHelpers.GlobalScale); - if (ImGui.SliderFloat("Target triangle ratio", ref targetPercent, 70f, 99f, "%.0f%%")) + if (ImGui.SliderFloat("Target triangle ratio", ref targetPercent, 60f, 99f, "%.0f%%")) { - performanceConfig.ModelDecimationTargetRatio = Math.Clamp(targetPercent / 100f, 0.7f, 0.99f); + performanceConfig.ModelDecimationTargetRatio = Math.Clamp(targetPercent / 100f, 0.6f, 0.99f); _playerPerformanceConfigService.Save(); } - _uiShared.DrawHelpText($"Target ratio relative to original triangle count (70% keeps 70% of triangles).{UiSharedService.TooltipSeparator}Default: 70%"); + _uiShared.DrawHelpText($"Target ratio relative to original triangle count (80% keeps 80% of triangles).{UiSharedService.TooltipSeparator}Default: 80%"); - ImGui.Dummy(new Vector2(5)); + ImGui.Dummy(new Vector2(15)); ImGui.TextUnformatted("Decimation targets"); _uiShared.DrawHelpText("Hair mods are always excluded from decimation."); + _uiShared.DrawNoteLine("! ", UIColors.Get("LightlessGreen"), + new SeStringUtils.RichTextEntry("Automatic decimation will only target the selected "), + new SeStringUtils.RichTextEntry("decimation targets", UIColors.Get("LightlessGreen"), true), + new SeStringUtils.RichTextEntry(".")); + + _uiShared.DrawNoteLine("! ", UIColors.Get("LightlessYellow"), + new SeStringUtils.RichTextEntry("It is advised to not decimate any body related meshes which includes: "), + new SeStringUtils.RichTextEntry("facial mods + sculpts, chest, legs, hands and feet", UIColors.Get("LightlessYellow"), true), + new SeStringUtils.RichTextEntry(".")); + + _uiShared.DrawNoteLine("!!! ", UIColors.Get("DimRed"), + new SeStringUtils.RichTextEntry("Remember, automatic decimation is not perfect and can cause meshes to be ruined, especially hair mods.", UIColors.Get("DimRed"), true)); + var allowBody = performanceConfig.ModelDecimationAllowBody; if (ImGui.Checkbox("Body", ref allowBody)) { @@ -3731,6 +3767,10 @@ public class SettingsUi : WindowMediatorSubscriberBase _playerPerformanceConfigService.Save(); } + ImGui.Dummy(new Vector2(5)); + + UiSharedService.ColoredSeparator(UIColors.Get("LightlessGrey"), 3f); + ImGui.Dummy(new Vector2(5)); DrawTriangleDecimationCounters(); ImGui.Dummy(new Vector2(5)); diff --git a/LightlessSync/UI/ZoneChatUi.cs b/LightlessSync/UI/ZoneChatUi.cs index cb6dae8..a03ceab 100644 --- a/LightlessSync/UI/ZoneChatUi.cs +++ b/LightlessSync/UI/ZoneChatUi.cs @@ -205,10 +205,8 @@ public sealed class ZoneChatUi : WindowMediatorSubscriberBase private void ApplyUiVisibilitySettings() { - var config = _chatConfigService.Current; _uiBuilder.DisableUserUiHide = true; - _uiBuilder.DisableCutsceneUiHide = config.ShowInCutscenes; - _uiBuilder.DisableGposeUiHide = config.ShowInGpose; + _uiBuilder.DisableCutsceneUiHide = true; } private bool ShouldHide() @@ -220,6 +218,16 @@ public sealed class ZoneChatUi : WindowMediatorSubscriberBase return true; } + if (!config.ShowInGpose && _dalamudUtilService.IsInGpose) + { + return true; + } + + if (!config.ShowInCutscenes && _dalamudUtilService.IsInCutscene) + { + return true; + } + if (config.HideInCombat && _dalamudUtilService.IsInCombat) { return true;