Files
LightlessClient/LightlessSync/UI/DtrEntry.cs
defnotken abe28e931c
All checks were successful
Tag and Release Lightless / tag-and-release (push) Successful in 36s
1.11.6 (#4)
1.11.6 Changelog (In Progress)
---
* Update submodule reference
* Update dalamud sdk
* Reworked the Syncshell Admin Page
   - Fixed that owners are visible in the list, Removed Pin/Remove/Ban buttons on Owners.
   - Styling is done similiar as settings page.
   - Added 1 or 3 day(s) option for inactive check.
+ Added new functions on the Server Top Bar button
   - Right click on the button will disconnect you from Lightless
   - Shift+Left click will open the settings page
+ Added colors section in the settings to change accent colors.
   - The nameplate coloring has been moved to this section
+ Added pin option from Dalamud in the UI.
+ Added ability to pause syncing while going in Instance/Duty
+ Added functionality to make syncshell folders
+ Fixed nameplate bug in PVP
+ added self-threshold warning

Co-authored-by: defnotken <itsdefnotken@gmail.com>
Co-authored-by: CakeAndBanana <admin@cakeandbanana.nl>
Co-authored-by: thijmenh <thijmenhogenkamp@gmail.com>
Co-authored-by: choco <choco@noreply.git.lightless-sync.org>
Co-authored-by: cake <cake@noreply.git.lightless-sync.org>
Co-authored-by: choco <thijmenhogenkamp@gmail.com>
Reviewed-on: #4
2025-09-11 23:43:11 +02:00

243 lines
8.6 KiB
C#

using Dalamud.Game.Gui.Dtr;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Plugin.Services;
using LightlessSync.LightlessConfiguration;
using LightlessSync.LightlessConfiguration.Configurations;
using LightlessSync.PlayerData.Pairs;
using LightlessSync.Services.Mediator;
using LightlessSync.Services.ServerConfiguration;
using LightlessSync.WebAPI;
using LightlessSync.WebAPI.SignalR.Utils;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.Runtime.InteropServices;
namespace LightlessSync.UI;
public sealed class DtrEntry : IDisposable, IHostedService
{
private readonly ApiController _apiController;
private readonly ServerConfigurationManager _serverManager;
private readonly CancellationTokenSource _cancellationTokenSource = new();
private readonly ConfigurationServiceBase<LightlessConfig> _configService;
private readonly IDtrBar _dtrBar;
private readonly Lazy<IDtrBarEntry> _entry;
private readonly ILogger<DtrEntry> _logger;
private readonly LightlessMediator _lightlessMediator;
private readonly PairManager _pairManager;
private Task? _runTask;
private string? _text;
private string? _tooltip;
private Colors _colors;
public DtrEntry(ILogger<DtrEntry> logger, IDtrBar dtrBar, ConfigurationServiceBase<LightlessConfig> configService, LightlessMediator lightlessMediator, PairManager pairManager, ApiController apiController, ServerConfigurationManager serverManager)
{
_logger = logger;
_dtrBar = dtrBar;
_entry = new(CreateEntry);
_configService = configService;
_lightlessMediator = lightlessMediator;
_pairManager = pairManager;
_apiController = apiController;
_serverManager = serverManager;
}
public void Dispose()
{
if (_entry.IsValueCreated)
{
_logger.LogDebug("Disposing DtrEntry");
Clear();
_entry.Value.Remove();
}
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Starting DtrEntry");
_runTask = Task.Run(RunAsync, _cancellationTokenSource.Token);
_logger.LogInformation("Started DtrEntry");
return Task.CompletedTask;
}
public async Task StopAsync(CancellationToken cancellationToken)
{
await _cancellationTokenSource.CancelAsync().ConfigureAwait(false);
try
{
await _runTask!.ConfigureAwait(false);
}
catch (OperationCanceledException)
{
// ignore cancelled
}
finally
{
_cancellationTokenSource.Dispose();
}
}
private void Clear()
{
if (!_entry.IsValueCreated) return;
_logger.LogInformation("Clearing entry");
_text = null;
_tooltip = null;
_colors = default;
_entry.Value.Shown = false;
}
private IDtrBarEntry CreateEntry()
{
_logger.LogTrace("Creating new DtrBar entry");
var entry = _dtrBar.Get("Lightless Sync");
entry.OnClick = interactionEvent => OnClickEvent(interactionEvent);
return entry;
}
private void OnClickEvent(DtrInteractionEvent interactionEvent)
{
if (interactionEvent.ClickType.Equals(MouseClickType.Left) && !interactionEvent.ModifierKeys.Equals(ClickModifierKeys.Shift))
{
_lightlessMediator.Publish(new UiToggleMessage(typeof(CompactUi)));
}
else if (interactionEvent.ClickType.Equals(MouseClickType.Left) && interactionEvent.ModifierKeys.Equals(ClickModifierKeys.Shift))
{
_lightlessMediator.Publish(new UiToggleMessage(typeof(SettingsUi)));
}
if (interactionEvent.ClickType.Equals(MouseClickType.Right))
{
bool isConnectingOrConnected = _apiController.ServerState is ServerState.Connected or ServerState.Connecting or ServerState.Reconnecting;
if (_apiController.ServerState is not (ServerState.Reconnecting or ServerState.Disconnecting))
{
if (isConnectingOrConnected && !_serverManager.CurrentServer.FullPause)
{
_serverManager.CurrentServer.FullPause = true;
_serverManager.Save();
}
else if (!isConnectingOrConnected && _serverManager.CurrentServer.FullPause)
{
_serverManager.CurrentServer.FullPause = false;
_serverManager.Save();
}
_ = _apiController.CreateConnectionsAsync();
}
}
}
private async Task RunAsync()
{
while (!_cancellationTokenSource.IsCancellationRequested)
{
await Task.Delay(1000, _cancellationTokenSource.Token).ConfigureAwait(false);
Update();
}
}
private void Update()
{
if (!_configService.Current.EnableDtrEntry || !_configService.Current.HasValidSetup())
{
if (_entry.IsValueCreated && _entry.Value.Shown)
{
_logger.LogInformation("Disabling entry");
Clear();
}
return;
}
if (!_entry.Value.Shown)
{
_logger.LogInformation("Showing entry");
_entry.Value.Shown = true;
}
string text;
string tooltip;
Colors colors;
if (_apiController.IsConnected)
{
var pairCount = _pairManager.GetVisibleUserCount();
text = $"\uE044 {pairCount}";
if (pairCount > 0)
{
IEnumerable<string> visiblePairs;
if (_configService.Current.ShowUidInDtrTooltip)
{
visiblePairs = _pairManager.GetOnlineUserPairs()
.Where(x => x.IsVisible)
.Select(x => string.Format("{0} ({1})", _configService.Current.PreferNoteInDtrTooltip ? x.GetNote() ?? x.PlayerName : x.PlayerName, x.UserData.AliasOrUID));
}
else
{
visiblePairs = _pairManager.GetOnlineUserPairs()
.Where(x => x.IsVisible)
.Select(x => string.Format("{0}", _configService.Current.PreferNoteInDtrTooltip ? x.GetNote() ?? x.PlayerName : x.PlayerName));
}
tooltip = $"Lightless Sync: Connected{Environment.NewLine}----------{Environment.NewLine}{string.Join(Environment.NewLine, visiblePairs)}";
colors = _configService.Current.DtrColorsPairsInRange;
}
else
{
tooltip = "Lightless Sync: Connected";
colors = _configService.Current.DtrColorsDefault;
}
}
else
{
text = "\uE044 \uE04C";
tooltip = "Lightless Sync: Not Connected";
colors = _configService.Current.DtrColorsNotConnected;
}
if (!_configService.Current.UseColorsInDtr)
colors = default;
if (!string.Equals(text, _text, StringComparison.Ordinal) || !string.Equals(tooltip, _tooltip, StringComparison.Ordinal) || colors != _colors)
{
_text = text;
_tooltip = tooltip;
_colors = colors;
_entry.Value.Text = BuildColoredSeString(text, colors);
_entry.Value.Tooltip = tooltip;
}
}
#region Colored SeString
private const byte _colorTypeForeground = 0x13;
private const byte _colorTypeGlow = 0x14;
private static SeString BuildColoredSeString(string text, Colors colors)
{
var ssb = new SeStringBuilder();
if (colors.Foreground != default)
ssb.Add(BuildColorStartPayload(_colorTypeForeground, colors.Foreground));
if (colors.Glow != default)
ssb.Add(BuildColorStartPayload(_colorTypeGlow, colors.Glow));
ssb.AddText(text);
if (colors.Glow != default)
ssb.Add(BuildColorEndPayload(_colorTypeGlow));
if (colors.Foreground != default)
ssb.Add(BuildColorEndPayload(_colorTypeForeground));
return ssb.Build();
}
private static RawPayload BuildColorStartPayload(byte colorType, uint color)
=> new(unchecked([0x02, colorType, 0x05, 0xF6, byte.Max((byte)color, 0x01), byte.Max((byte)(color >> 8), 0x01), byte.Max((byte)(color >> 16), 0x01), 0x03]));
private static RawPayload BuildColorEndPayload(byte colorType)
=> new([0x02, colorType, 0x02, 0xEC, 0x03]);
[StructLayout(LayoutKind.Sequential)]
public readonly record struct Colors(uint Foreground = default, uint Glow = default);
#endregion
}