Compare commits
6 Commits
1.42.0.73-
...
animatedhe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
812fbaec78 | ||
|
|
e11135bb23 | ||
|
|
be068ed6d1 | ||
|
|
3c3c8fd90b | ||
| 835a0a637d | |||
| ad0254a812 |
@@ -6,6 +6,7 @@ using LightlessSync.Utils;
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace LightlessSync.FileCache;
|
namespace LightlessSync.FileCache;
|
||||||
|
|
||||||
@@ -21,6 +22,7 @@ public sealed class CacheMonitor : DisposableMediatorSubscriberBase
|
|||||||
private CancellationTokenSource _scanCancellationTokenSource = new();
|
private CancellationTokenSource _scanCancellationTokenSource = new();
|
||||||
private readonly CancellationTokenSource _periodicCalculationTokenSource = new();
|
private readonly CancellationTokenSource _periodicCalculationTokenSource = new();
|
||||||
public static readonly IImmutableList<string> AllowedFileExtensions = [".mdl", ".tex", ".mtrl", ".tmb", ".pap", ".avfx", ".atex", ".sklb", ".eid", ".phyb", ".pbd", ".scd", ".skp", ".shpk", ".kdb"];
|
public static readonly IImmutableList<string> AllowedFileExtensions = [".mdl", ".tex", ".mtrl", ".tmb", ".pap", ".avfx", ".atex", ".sklb", ".eid", ".phyb", ".pbd", ".scd", ".skp", ".shpk", ".kdb"];
|
||||||
|
private static readonly HashSet<string> AllowedFileExtensionSet = new(AllowedFileExtensions, StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
public CacheMonitor(ILogger<CacheMonitor> logger, IpcManager ipcManager, LightlessConfigService configService,
|
public CacheMonitor(ILogger<CacheMonitor> logger, IpcManager ipcManager, LightlessConfigService configService,
|
||||||
FileCacheManager fileDbManager, LightlessMediator mediator, PerformanceCollectorService performanceCollector, DalamudUtilService dalamudUtil,
|
FileCacheManager fileDbManager, LightlessMediator mediator, PerformanceCollectorService performanceCollector, DalamudUtilService dalamudUtil,
|
||||||
@@ -163,7 +165,7 @@ public sealed class CacheMonitor : DisposableMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
Logger.LogTrace("Lightless FSW: FileChanged: {change} => {path}", e.ChangeType, e.FullPath);
|
Logger.LogTrace("Lightless FSW: FileChanged: {change} => {path}", e.ChangeType, e.FullPath);
|
||||||
|
|
||||||
if (!AllowedFileExtensions.Any(ext => e.FullPath.EndsWith(ext, StringComparison.OrdinalIgnoreCase))) return;
|
if (!HasAllowedExtension(e.FullPath)) return;
|
||||||
|
|
||||||
lock (_watcherChanges)
|
lock (_watcherChanges)
|
||||||
{
|
{
|
||||||
@@ -207,7 +209,7 @@ public sealed class CacheMonitor : DisposableMediatorSubscriberBase
|
|||||||
private void Fs_Changed(object sender, FileSystemEventArgs e)
|
private void Fs_Changed(object sender, FileSystemEventArgs e)
|
||||||
{
|
{
|
||||||
if (Directory.Exists(e.FullPath)) return;
|
if (Directory.Exists(e.FullPath)) return;
|
||||||
if (!AllowedFileExtensions.Any(ext => e.FullPath.EndsWith(ext, StringComparison.OrdinalIgnoreCase))) return;
|
if (!HasAllowedExtension(e.FullPath)) return;
|
||||||
|
|
||||||
if (e.ChangeType is not (WatcherChangeTypes.Changed or WatcherChangeTypes.Deleted or WatcherChangeTypes.Created))
|
if (e.ChangeType is not (WatcherChangeTypes.Changed or WatcherChangeTypes.Deleted or WatcherChangeTypes.Created))
|
||||||
return;
|
return;
|
||||||
@@ -231,7 +233,7 @@ public sealed class CacheMonitor : DisposableMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
foreach (var file in directoryFiles)
|
foreach (var file in directoryFiles)
|
||||||
{
|
{
|
||||||
if (!AllowedFileExtensions.Any(ext => file.EndsWith(ext, StringComparison.OrdinalIgnoreCase))) continue;
|
if (!HasAllowedExtension(file)) continue;
|
||||||
var oldPath = file.Replace(e.FullPath, e.OldFullPath, StringComparison.OrdinalIgnoreCase);
|
var oldPath = file.Replace(e.FullPath, e.OldFullPath, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
_watcherChanges.Remove(oldPath);
|
_watcherChanges.Remove(oldPath);
|
||||||
@@ -243,7 +245,7 @@ public sealed class CacheMonitor : DisposableMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!AllowedFileExtensions.Any(ext => e.FullPath.EndsWith(ext, StringComparison.OrdinalIgnoreCase))) return;
|
if (!HasAllowedExtension(e.FullPath)) return;
|
||||||
|
|
||||||
lock (_watcherChanges)
|
lock (_watcherChanges)
|
||||||
{
|
{
|
||||||
@@ -263,6 +265,17 @@ public sealed class CacheMonitor : DisposableMediatorSubscriberBase
|
|||||||
public FileSystemWatcher? PenumbraWatcher { get; private set; }
|
public FileSystemWatcher? PenumbraWatcher { get; private set; }
|
||||||
public FileSystemWatcher? LightlessWatcher { get; private set; }
|
public FileSystemWatcher? LightlessWatcher { get; private set; }
|
||||||
|
|
||||||
|
private static bool HasAllowedExtension(string path)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(path))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var extension = Path.GetExtension(path);
|
||||||
|
return !string.IsNullOrEmpty(extension) && AllowedFileExtensionSet.Contains(extension);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task LightlessWatcherExecution()
|
private async Task LightlessWatcherExecution()
|
||||||
{
|
{
|
||||||
_lightlessFswCts = _lightlessFswCts.CancelRecreate();
|
_lightlessFswCts = _lightlessFswCts.CancelRecreate();
|
||||||
@@ -606,7 +619,7 @@ public sealed class CacheMonitor : DisposableMediatorSubscriberBase
|
|||||||
[
|
[
|
||||||
.. Directory.GetFiles(folder, "*.*", SearchOption.AllDirectories)
|
.. Directory.GetFiles(folder, "*.*", SearchOption.AllDirectories)
|
||||||
.AsParallel()
|
.AsParallel()
|
||||||
.Where(f => AllowedFileExtensions.Any(e => f.EndsWith(e, StringComparison.OrdinalIgnoreCase))
|
.Where(f => HasAllowedExtension(f)
|
||||||
&& !f.Contains(@"\bg\", StringComparison.OrdinalIgnoreCase)
|
&& !f.Contains(@"\bg\", StringComparison.OrdinalIgnoreCase)
|
||||||
&& !f.Contains(@"\bgcommon\", StringComparison.OrdinalIgnoreCase)
|
&& !f.Contains(@"\bgcommon\", StringComparison.OrdinalIgnoreCase)
|
||||||
&& !f.Contains(@"\ui\", StringComparison.OrdinalIgnoreCase)),
|
&& !f.Contains(@"\ui\", StringComparison.OrdinalIgnoreCase)),
|
||||||
|
|||||||
@@ -372,6 +372,9 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase
|
|||||||
|
|
||||||
private void HandleActorTracked(ActorObjectService.ActorDescriptor descriptor)
|
private void HandleActorTracked(ActorObjectService.ActorDescriptor descriptor)
|
||||||
{
|
{
|
||||||
|
if (descriptor.IsInGpose)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!TryResolveObjectKind(descriptor, out var resolvedKind))
|
if (!TryResolveObjectKind(descriptor, out var resolvedKind))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
using Dalamud.Plugin;
|
||||||
using Dalamud.Plugin;
|
|
||||||
using Dalamud.Plugin.Ipc;
|
using Dalamud.Plugin.Ipc;
|
||||||
using LightlessSync.Interop.Ipc.Framework;
|
using LightlessSync.Interop.Ipc.Framework;
|
||||||
using LightlessSync.Services;
|
using LightlessSync.Services;
|
||||||
@@ -13,7 +12,7 @@ public sealed class IpcCallerMoodles : IpcServiceBase
|
|||||||
private static readonly IpcServiceDescriptor MoodlesDescriptor = new("Moodles", "Moodles", new Version(0, 0, 0, 0));
|
private static readonly IpcServiceDescriptor MoodlesDescriptor = new("Moodles", "Moodles", new Version(0, 0, 0, 0));
|
||||||
|
|
||||||
private readonly ICallGateSubscriber<int> _moodlesApiVersion;
|
private readonly ICallGateSubscriber<int> _moodlesApiVersion;
|
||||||
private readonly ICallGateSubscriber<IPlayerCharacter, object> _moodlesOnChange;
|
private readonly ICallGateSubscriber<nint, object> _moodlesOnChange;
|
||||||
private readonly ICallGateSubscriber<nint, string> _moodlesGetStatus;
|
private readonly ICallGateSubscriber<nint, string> _moodlesGetStatus;
|
||||||
private readonly ICallGateSubscriber<nint, string, object> _moodlesSetStatus;
|
private readonly ICallGateSubscriber<nint, string, object> _moodlesSetStatus;
|
||||||
private readonly ICallGateSubscriber<nint, object> _moodlesRevertStatus;
|
private readonly ICallGateSubscriber<nint, object> _moodlesRevertStatus;
|
||||||
@@ -29,7 +28,7 @@ public sealed class IpcCallerMoodles : IpcServiceBase
|
|||||||
_lightlessMediator = lightlessMediator;
|
_lightlessMediator = lightlessMediator;
|
||||||
|
|
||||||
_moodlesApiVersion = pi.GetIpcSubscriber<int>("Moodles.Version");
|
_moodlesApiVersion = pi.GetIpcSubscriber<int>("Moodles.Version");
|
||||||
_moodlesOnChange = pi.GetIpcSubscriber<IPlayerCharacter, object>("Moodles.StatusManagerModified");
|
_moodlesOnChange = pi.GetIpcSubscriber<nint, object>("Moodles.StatusManagerModified");
|
||||||
_moodlesGetStatus = pi.GetIpcSubscriber<nint, string>("Moodles.GetStatusManagerByPtrV2");
|
_moodlesGetStatus = pi.GetIpcSubscriber<nint, string>("Moodles.GetStatusManagerByPtrV2");
|
||||||
_moodlesSetStatus = pi.GetIpcSubscriber<nint, string, object>("Moodles.SetStatusManagerByPtrV2");
|
_moodlesSetStatus = pi.GetIpcSubscriber<nint, string, object>("Moodles.SetStatusManagerByPtrV2");
|
||||||
_moodlesRevertStatus = pi.GetIpcSubscriber<nint, object>("Moodles.ClearStatusManagerByPtrV2");
|
_moodlesRevertStatus = pi.GetIpcSubscriber<nint, object>("Moodles.ClearStatusManagerByPtrV2");
|
||||||
@@ -39,9 +38,9 @@ public sealed class IpcCallerMoodles : IpcServiceBase
|
|||||||
CheckAPI();
|
CheckAPI();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMoodlesChange(IPlayerCharacter character)
|
private void OnMoodlesChange(nint address)
|
||||||
{
|
{
|
||||||
_lightlessMediator.Publish(new MoodlesMessage(character.Address));
|
_lightlessMediator.Publish(new MoodlesMessage(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
@@ -107,7 +106,7 @@ public sealed class IpcCallerMoodles : IpcServiceBase
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return _moodlesApiVersion.InvokeFunc() == 3
|
return _moodlesApiVersion.InvokeFunc() >= 4
|
||||||
? IpcConnectionState.Available
|
? IpcConnectionState.Available
|
||||||
: IpcConnectionState.VersionMismatch;
|
: IpcConnectionState.VersionMismatch;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors></Authors>
|
<Authors></Authors>
|
||||||
<Company></Company>
|
<Company></Company>
|
||||||
<Version>2.0.0</Version>
|
<Version>2.0.1</Version>
|
||||||
<Description></Description>
|
<Description></Description>
|
||||||
<Copyright></Copyright>
|
<Copyright></Copyright>
|
||||||
<PackageProjectUrl>https://github.com/Light-Public-Syncshells/LightlessClient</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/Light-Public-Syncshells/LightlessClient</PackageProjectUrl>
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ public class PlayerDataFactory
|
|||||||
CharacterDataFragment fragment = objectKind == ObjectKind.Player ? new CharacterDataFragmentPlayer() : new();
|
CharacterDataFragment fragment = objectKind == ObjectKind.Player ? new CharacterDataFragmentPlayer() : new();
|
||||||
|
|
||||||
_logger.LogDebug("Building character data for {obj}", playerRelatedObject);
|
_logger.LogDebug("Building character data for {obj}", playerRelatedObject);
|
||||||
|
var logDebug = _logger.IsEnabled(LogLevel.Debug);
|
||||||
|
|
||||||
// wait until chara is not drawing and present so nothing spontaneously explodes
|
// wait until chara is not drawing and present so nothing spontaneously explodes
|
||||||
await _dalamudUtil.WaitWhileCharacterIsDrawing(_logger, playerRelatedObject, Guid.NewGuid(), 30000, ct: ct).ConfigureAwait(false);
|
await _dalamudUtil.WaitWhileCharacterIsDrawing(_logger, playerRelatedObject, Guid.NewGuid(), 30000, ct: ct).ConfigureAwait(false);
|
||||||
@@ -132,11 +133,6 @@ public class PlayerDataFactory
|
|||||||
|
|
||||||
ct.ThrowIfCancellationRequested();
|
ct.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
Dictionary<string, List<ushort>>? boneIndices =
|
|
||||||
objectKind != ObjectKind.Player
|
|
||||||
? null
|
|
||||||
: await _dalamudUtil.RunOnFrameworkThread(() => _modelAnalyzer.GetSkeletonBoneIndices(playerRelatedObject)).ConfigureAwait(false);
|
|
||||||
|
|
||||||
DateTime start = DateTime.UtcNow;
|
DateTime start = DateTime.UtcNow;
|
||||||
|
|
||||||
// penumbra call, it's currently broken
|
// penumbra call, it's currently broken
|
||||||
@@ -154,11 +150,21 @@ public class PlayerDataFactory
|
|||||||
|
|
||||||
ct.ThrowIfCancellationRequested();
|
ct.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
_logger.LogDebug("== Static Replacements ==");
|
if (logDebug)
|
||||||
foreach (var replacement in fragment.FileReplacements.Where(i => i.HasFileReplacement).OrderBy(i => i.GamePaths.First(), StringComparer.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
_logger.LogDebug("=> {repl}", replacement);
|
_logger.LogDebug("== Static Replacements ==");
|
||||||
ct.ThrowIfCancellationRequested();
|
foreach (var replacement in fragment.FileReplacements.Where(i => i.HasFileReplacement).OrderBy(i => i.GamePaths.First(), StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
_logger.LogDebug("=> {repl}", replacement);
|
||||||
|
ct.ThrowIfCancellationRequested();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var replacement in fragment.FileReplacements.Where(i => i.HasFileReplacement))
|
||||||
|
{
|
||||||
|
ct.ThrowIfCancellationRequested();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await _transientResourceManager.WaitForRecording(ct).ConfigureAwait(false);
|
await _transientResourceManager.WaitForRecording(ct).ConfigureAwait(false);
|
||||||
@@ -190,11 +196,21 @@ public class PlayerDataFactory
|
|||||||
var transientPaths = ManageSemiTransientData(objectKind);
|
var transientPaths = ManageSemiTransientData(objectKind);
|
||||||
var resolvedTransientPaths = await GetFileReplacementsFromPaths(transientPaths, new HashSet<string>(StringComparer.Ordinal)).ConfigureAwait(false);
|
var resolvedTransientPaths = await GetFileReplacementsFromPaths(transientPaths, new HashSet<string>(StringComparer.Ordinal)).ConfigureAwait(false);
|
||||||
|
|
||||||
_logger.LogDebug("== Transient Replacements ==");
|
if (logDebug)
|
||||||
foreach (var replacement in resolvedTransientPaths.Select(c => new FileReplacement([.. c.Value], c.Key)).OrderBy(f => f.ResolvedPath, StringComparer.Ordinal))
|
|
||||||
{
|
{
|
||||||
_logger.LogDebug("=> {repl}", replacement);
|
_logger.LogDebug("== Transient Replacements ==");
|
||||||
fragment.FileReplacements.Add(replacement);
|
foreach (var replacement in resolvedTransientPaths.Select(c => new FileReplacement([.. c.Value], c.Key)).OrderBy(f => f.ResolvedPath, StringComparer.Ordinal))
|
||||||
|
{
|
||||||
|
_logger.LogDebug("=> {repl}", replacement);
|
||||||
|
fragment.FileReplacements.Add(replacement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var replacement in resolvedTransientPaths.Select(c => new FileReplacement([.. c.Value], c.Key)))
|
||||||
|
{
|
||||||
|
fragment.FileReplacements.Add(replacement);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// clean up all semi transient resources that don't have any file replacement (aka null resolve)
|
// clean up all semi transient resources that don't have any file replacement (aka null resolve)
|
||||||
@@ -252,11 +268,26 @@ public class PlayerDataFactory
|
|||||||
|
|
||||||
ct.ThrowIfCancellationRequested();
|
ct.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
Dictionary<string, List<ushort>>? boneIndices = null;
|
||||||
|
var hasPapFiles = false;
|
||||||
|
if (objectKind == ObjectKind.Player)
|
||||||
|
{
|
||||||
|
hasPapFiles = fragment.FileReplacements.Any(f =>
|
||||||
|
!f.IsFileSwap && f.GamePaths.First().EndsWith("pap", StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (hasPapFiles)
|
||||||
|
{
|
||||||
|
boneIndices = await _dalamudUtil.RunOnFrameworkThread(() => _modelAnalyzer.GetSkeletonBoneIndices(playerRelatedObject)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (objectKind == ObjectKind.Player)
|
if (objectKind == ObjectKind.Player)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await VerifyPlayerAnimationBones(boneIndices, (fragment as CharacterDataFragmentPlayer)!, ct).ConfigureAwait(false);
|
if (hasPapFiles)
|
||||||
|
{
|
||||||
|
await VerifyPlayerAnimationBones(boneIndices, (fragment as CharacterDataFragmentPlayer)!, ct).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException e)
|
catch (OperationCanceledException e)
|
||||||
{
|
{
|
||||||
@@ -278,12 +309,16 @@ public class PlayerDataFactory
|
|||||||
{
|
{
|
||||||
if (boneIndices == null) return;
|
if (boneIndices == null) return;
|
||||||
|
|
||||||
foreach (var kvp in boneIndices)
|
if (_logger.IsEnabled(LogLevel.Debug))
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Found {skellyname} ({idx} bone indices) on player: {bones}", kvp.Key, kvp.Value.Any() ? kvp.Value.Max() : 0, string.Join(',', kvp.Value));
|
foreach (var kvp in boneIndices)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Found {skellyname} ({idx} bone indices) on player: {bones}", kvp.Key, kvp.Value.Any() ? kvp.Value.Max() : 0, string.Join(',', kvp.Value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (boneIndices.All(u => u.Value.Count == 0)) return;
|
var maxPlayerBoneIndex = boneIndices.SelectMany(kvp => kvp.Value).DefaultIfEmpty().Max();
|
||||||
|
if (maxPlayerBoneIndex <= 0) return;
|
||||||
|
|
||||||
int noValidationFailed = 0;
|
int noValidationFailed = 0;
|
||||||
foreach (var file in fragment.FileReplacements.Where(f => !f.IsFileSwap && f.GamePaths.First().EndsWith("pap", StringComparison.OrdinalIgnoreCase)).ToList())
|
foreach (var file in fragment.FileReplacements.Where(f => !f.IsFileSwap && f.GamePaths.First().EndsWith("pap", StringComparison.OrdinalIgnoreCase)).ToList())
|
||||||
@@ -303,12 +338,13 @@ public class PlayerDataFactory
|
|||||||
|
|
||||||
_logger.LogDebug("Verifying bone indices for {path}, found {x} skeletons", file.ResolvedPath, skeletonIndices.Count);
|
_logger.LogDebug("Verifying bone indices for {path}, found {x} skeletons", file.ResolvedPath, skeletonIndices.Count);
|
||||||
|
|
||||||
foreach (var boneCount in skeletonIndices.Select(k => k).ToList())
|
foreach (var boneCount in skeletonIndices)
|
||||||
{
|
{
|
||||||
if (boneCount.Value.Max() > boneIndices.SelectMany(b => b.Value).Max())
|
var maxAnimationIndex = boneCount.Value.DefaultIfEmpty().Max();
|
||||||
|
if (maxAnimationIndex > maxPlayerBoneIndex)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Found more bone indices on the animation {path} skeleton {skl} (max indice {idx}) than on any player related skeleton (max indice {idx2})",
|
_logger.LogWarning("Found more bone indices on the animation {path} skeleton {skl} (max indice {idx}) than on any player related skeleton (max indice {idx2})",
|
||||||
file.ResolvedPath, boneCount.Key, boneCount.Value.Max(), boneIndices.SelectMany(b => b.Value).Max());
|
file.ResolvedPath, boneCount.Key, maxAnimationIndex, maxPlayerBoneIndex);
|
||||||
validationFailed = true;
|
validationFailed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -222,7 +222,9 @@ public class AnimatedHeader
|
|||||||
|
|
||||||
if (ImGui.IsItemHovered() && !string.IsNullOrEmpty(button.Tooltip))
|
if (ImGui.IsItemHovered() && !string.IsNullOrEmpty(button.Tooltip))
|
||||||
{
|
{
|
||||||
|
ImGui.PushFont(UiBuilder.DefaultFont);
|
||||||
ImGui.SetTooltip(button.Tooltip);
|
ImGui.SetTooltip(button.Tooltip);
|
||||||
|
ImGui.PopFont();
|
||||||
}
|
}
|
||||||
|
|
||||||
currentX -= buttonSize.X + spacing;
|
currentX -= buttonSize.X + spacing;
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ public sealed class ZoneChatUi : WindowMediatorSubscriberBase
|
|||||||
private string? _dragHoverKey;
|
private string? _dragHoverKey;
|
||||||
private bool _HideStateActive;
|
private bool _HideStateActive;
|
||||||
private bool _HideStateWasOpen;
|
private bool _HideStateWasOpen;
|
||||||
|
private bool _pushedStyle;
|
||||||
|
|
||||||
public ZoneChatUi(
|
public ZoneChatUi(
|
||||||
ILogger<ZoneChatUi> logger,
|
ILogger<ZoneChatUi> logger,
|
||||||
@@ -139,6 +140,8 @@ public sealed class ZoneChatUi : WindowMediatorSubscriberBase
|
|||||||
var config = _chatConfigService.Current;
|
var config = _chatConfigService.Current;
|
||||||
var baseOpacity = Math.Clamp(config.ChatWindowOpacity, MinWindowOpacity, MaxWindowOpacity);
|
var baseOpacity = Math.Clamp(config.ChatWindowOpacity, MinWindowOpacity, MaxWindowOpacity);
|
||||||
_baseWindowOpacity = baseOpacity;
|
_baseWindowOpacity = baseOpacity;
|
||||||
|
ImGui.PushStyleVar(ImGuiStyleVar.WindowBorderSize, 0);
|
||||||
|
_pushedStyle = true;
|
||||||
|
|
||||||
if (config.FadeWhenUnfocused)
|
if (config.FadeWhenUnfocused)
|
||||||
{
|
{
|
||||||
@@ -823,6 +826,16 @@ public sealed class ZoneChatUi : WindowMediatorSubscriberBase
|
|||||||
ImGui.EndPopup();
|
ImGui.EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void PostDraw()
|
||||||
|
{
|
||||||
|
if (_pushedStyle)
|
||||||
|
{
|
||||||
|
ImGui.PopStyleVar(1);
|
||||||
|
_pushedStyle = false;
|
||||||
|
}
|
||||||
|
base.PostDraw();
|
||||||
|
}
|
||||||
|
|
||||||
private void OpenReportPopup(ChatChannelSnapshot channel, ChatMessageEntry message)
|
private void OpenReportPopup(ChatChannelSnapshot channel, ChatMessageEntry message)
|
||||||
{
|
{
|
||||||
if (message.Payload is not { } payload)
|
if (message.Payload is not { } payload)
|
||||||
|
|||||||
Reference in New Issue
Block a user