Fix bubble party + Download queue + Allow pause user in syncshell + add visual feature + clean log info
This commit is contained in:
@@ -169,6 +169,14 @@ public sealed class ChangelogUi : WindowMediatorSubscriberBase
|
||||
{
|
||||
return new List<ChangelogEntry>
|
||||
{
|
||||
new(new Version(0, 1, 9, 5), "0.1.9.5", new List<ChangelogLine>
|
||||
{
|
||||
new("Fix l'affichage de la bulle dans la liste du groupe."),
|
||||
new("Amélioration de l'ajout des utilisateurs via le bouton +."),
|
||||
new("Possibilité de mettre en pause individuellement des utilisateurs d'une syncshell."),
|
||||
new("Amélioration de la stabilité du plugin en cas de petite connexion / petite configuration."),
|
||||
new("Divers fix de l'interface."),
|
||||
}),
|
||||
new(new Version(0, 1, 9, 4), "0.1.9.4", new List<ChangelogLine>
|
||||
{
|
||||
new("Réécriture complète de la bulle de frappe avec la possibilité de choisir la taille de la bulle."),
|
||||
|
||||
@@ -57,6 +57,14 @@ internal partial class CharaDataHubUi
|
||||
_configService.Save();
|
||||
}
|
||||
_uiSharedService.DrawHelpText("Draw floating wisps where other's poses are in the world.");
|
||||
int maxWisps = _configService.Current.NearbyMaxWisps;
|
||||
ImGui.SetNextItemWidth(140);
|
||||
if (ImGui.SliderInt("Maximum wisps", ref maxWisps, 0, 200))
|
||||
{
|
||||
_configService.Current.NearbyMaxWisps = maxWisps;
|
||||
_configService.Save();
|
||||
}
|
||||
_uiSharedService.DrawHelpText("Limit how many wisps are active at once. Set to 0 to disable wisps even when enabled above.");
|
||||
int poseDetectionDistance = _configService.Current.NearbyDistanceFilter;
|
||||
ImGui.SetNextItemWidth(100);
|
||||
if (ImGui.SliderInt("Detection Distance", ref poseDetectionDistance, 5, 1000))
|
||||
|
||||
@@ -88,7 +88,7 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
_characterAnalyzer = characterAnalyzer;
|
||||
var tagHandler = new TagHandler(_serverManager);
|
||||
|
||||
_groupPanel = new(this, uiShared, _pairManager, chatService, uidDisplayHandler, _configService, _serverManager, _charaDataManager);
|
||||
_groupPanel = new(this, uiShared, _pairManager, chatService, uidDisplayHandler, _configService, _serverManager, _charaDataManager, _autoDetectRequestService);
|
||||
_selectGroupForPairUi = new(tagHandler, uidDisplayHandler, _uiSharedService);
|
||||
_selectPairsForGroupUi = new(tagHandler, uidDisplayHandler);
|
||||
_pairGroupsUi = new(configService, tagHandler, uidDisplayHandler, apiController, _selectPairsForGroupUi, _uiSharedService);
|
||||
@@ -433,6 +433,8 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
|
||||
var compressedValue = UiSharedService.ByteToString(summary.TotalCompressedSize);
|
||||
Vector4? compressedColor = null;
|
||||
FontAwesomeIcon? compressedIcon = null;
|
||||
Vector4? compressedIconColor = null;
|
||||
string? compressedTooltip = null;
|
||||
if (summary.HasUncomputedEntries)
|
||||
{
|
||||
@@ -443,19 +445,25 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
{
|
||||
compressedColor = ImGuiColors.DalamudYellow;
|
||||
compressedTooltip = "Au-delà de 300 MiB, certains joueurs peuvent ne pas voir toutes vos modifications.";
|
||||
compressedIcon = FontAwesomeIcon.ExclamationTriangle;
|
||||
compressedIconColor = ImGuiColors.DalamudYellow;
|
||||
}
|
||||
|
||||
DrawSelfAnalysisStatRow("Taille compressée", compressedValue, compressedColor, compressedTooltip);
|
||||
DrawSelfAnalysisStatRow("Taille compressée", compressedValue, compressedColor, compressedTooltip, compressedIcon, compressedIconColor);
|
||||
DrawSelfAnalysisStatRow("Taille extraite", UiSharedService.ByteToString(summary.TotalOriginalSize));
|
||||
|
||||
Vector4? trianglesColor = null;
|
||||
FontAwesomeIcon? trianglesIcon = null;
|
||||
Vector4? trianglesIconColor = null;
|
||||
string? trianglesTooltip = null;
|
||||
if (summary.TotalTriangles >= SelfAnalysisTriangleWarningThreshold)
|
||||
{
|
||||
trianglesColor = ImGuiColors.DalamudYellow;
|
||||
trianglesTooltip = "Plus de 150k triangles peuvent entraîner un auto-pause et impacter les performances.";
|
||||
trianglesIcon = FontAwesomeIcon.ExclamationTriangle;
|
||||
trianglesIconColor = ImGuiColors.DalamudYellow;
|
||||
}
|
||||
DrawSelfAnalysisStatRow("Triangles moddés", UiSharedService.TrisToString(summary.TotalTriangles), trianglesColor, trianglesTooltip);
|
||||
DrawSelfAnalysisStatRow("Triangles moddés", UiSharedService.TrisToString(summary.TotalTriangles), trianglesColor, trianglesTooltip, trianglesIcon, trianglesIconColor);
|
||||
|
||||
ImGui.EndTable();
|
||||
}
|
||||
@@ -490,12 +498,29 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawSelfAnalysisStatRow(string label, string value, Vector4? valueColor = null, string? tooltip = null)
|
||||
private static void DrawSelfAnalysisStatRow(string label, string value, Vector4? valueColor = null, string? tooltip = null, FontAwesomeIcon? icon = null, Vector4? iconColor = null)
|
||||
{
|
||||
ImGui.TableNextRow();
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted(label);
|
||||
ImGui.TableNextColumn();
|
||||
if (icon.HasValue)
|
||||
{
|
||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
if (iconColor.HasValue)
|
||||
{
|
||||
using var iconColorPush = ImRaii.PushColor(ImGuiCol.Text, iconColor.Value);
|
||||
ImGui.TextUnformatted(icon.Value.ToIconString());
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.TextUnformatted(icon.Value.ToIconString());
|
||||
}
|
||||
}
|
||||
ImGui.SameLine(0f, 4f);
|
||||
}
|
||||
|
||||
if (valueColor.HasValue)
|
||||
{
|
||||
using var color = ImRaii.PushColor(ImGuiCol.Text, valueColor.Value);
|
||||
@@ -687,9 +712,9 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
ImGuiHelpers.ScaledDummy(4);
|
||||
}
|
||||
|
||||
var onlineUsers = users.Where(u => u.UserPair!.OtherPermissions.IsPaired() && (u.IsOnline || u.UserPair!.OwnPermissions.IsPaused())).Select(c => new DrawUserPair("Online" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager)).ToList();
|
||||
var visibleUsers = users.Where(u => u.IsVisible).Select(c => new DrawUserPair("Visible" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager)).ToList();
|
||||
var offlineUsers = users.Where(u => !u.UserPair!.OtherPermissions.IsPaired() || (!u.IsOnline && !u.UserPair!.OwnPermissions.IsPaused())).Select(c => new DrawUserPair("Offline" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager)).ToList();
|
||||
var onlineUsers = users.Where(u => u.UserPair!.OtherPermissions.IsPaired() && (u.IsOnline || u.UserPair!.OwnPermissions.IsPaused())).Select(c => new DrawUserPair("Online" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager, _serverManager)).ToList();
|
||||
var visibleUsers = users.Where(u => u.IsVisible).Select(c => new DrawUserPair("Visible" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager, _serverManager)).ToList();
|
||||
var offlineUsers = users.Where(u => !u.UserPair!.OtherPermissions.IsPaired() || (!u.IsOnline && !u.UserPair!.OwnPermissions.IsPaused())).Select(c => new DrawUserPair("Offline" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager, _serverManager)).ToList();
|
||||
|
||||
_pairGroupsUi.Draw(visibleUsers, onlineUsers, offlineUsers);
|
||||
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
using System.Numerics;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Colors;
|
||||
using Dalamud.Interface.Utility;
|
||||
using MareSynchronos.API.Data;
|
||||
using MareSynchronos.API.Data.Enum;
|
||||
using MareSynchronos.API.Data.Extensions;
|
||||
using MareSynchronos.API.Dto.Group;
|
||||
using MareSynchronos.API.Dto.User;
|
||||
using MareSynchronos.PlayerData.Pairs;
|
||||
using MareSynchronos.Services;
|
||||
using MareSynchronos.Services.AutoDetect;
|
||||
using MareSynchronos.Services.Mediator;
|
||||
using MareSynchronos.Services.ServerConfiguration;
|
||||
using MareSynchronos.UI.Handlers;
|
||||
using MareSynchronos.WebAPI;
|
||||
|
||||
@@ -21,16 +27,22 @@ public class DrawGroupPair : DrawPairBase
|
||||
private readonly GroupPairFullInfoDto _fullInfoDto;
|
||||
private readonly GroupFullInfoDto _group;
|
||||
private readonly CharaDataManager _charaDataManager;
|
||||
private readonly AutoDetectRequestService _autoDetectRequestService;
|
||||
private readonly ServerConfigurationManager _serverConfigurationManager;
|
||||
private const string ManualPairInvitePrefix = "[UmbraPairInvite|";
|
||||
|
||||
public DrawGroupPair(string id, Pair entry, ApiController apiController,
|
||||
MareMediator mareMediator, GroupFullInfoDto group, GroupPairFullInfoDto fullInfoDto,
|
||||
UidDisplayHandler handler, UiSharedService uiSharedService, CharaDataManager charaDataManager)
|
||||
UidDisplayHandler handler, UiSharedService uiSharedService, CharaDataManager charaDataManager,
|
||||
AutoDetectRequestService autoDetectRequestService, ServerConfigurationManager serverConfigurationManager)
|
||||
: base(id, entry, apiController, handler, uiSharedService)
|
||||
{
|
||||
_group = group;
|
||||
_fullInfoDto = fullInfoDto;
|
||||
_mediator = mareMediator;
|
||||
_charaDataManager = charaDataManager;
|
||||
_autoDetectRequestService = autoDetectRequestService;
|
||||
_serverConfigurationManager = serverConfigurationManager;
|
||||
}
|
||||
|
||||
protected override void DrawLeftSide(float textPosY, float originalY)
|
||||
@@ -153,8 +165,9 @@ public class DrawGroupPair : DrawPairBase
|
||||
|
||||
bool showShared = _charaDataManager.SharedWithYouData.TryGetValue(_pair.UserData, out var sharedData);
|
||||
bool showInfo = (individualAnimDisabled || individualSoundsDisabled || animDisabled || soundsDisabled);
|
||||
bool showPlus = _pair.UserPair == null;
|
||||
bool showPlus = _pair.UserPair == null && _pair.IsOnline;
|
||||
bool showBars = (userIsOwner || (userIsModerator && !entryIsMod && !entryIsOwner)) || !_pair.IsPaused;
|
||||
bool showPause = true;
|
||||
|
||||
var spacing = ImGui.GetStyle().ItemSpacing.X;
|
||||
var permIcon = (individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled) ? FontAwesomeIcon.ExclamationTriangle
|
||||
@@ -162,12 +175,15 @@ public class DrawGroupPair : DrawPairBase
|
||||
var runningIconWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Running).X;
|
||||
var infoIconWidth = UiSharedService.GetIconSize(permIcon).X;
|
||||
var plusButtonWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Plus).X;
|
||||
var pauseIcon = _fullInfoDto.GroupUserPermissions.IsPaused() ? FontAwesomeIcon.Play : FontAwesomeIcon.Pause;
|
||||
var pauseButtonWidth = _uiSharedService.GetIconButtonSize(pauseIcon).X;
|
||||
var barButtonWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars).X;
|
||||
|
||||
var pos = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() + spacing
|
||||
- (showShared ? (runningIconWidth + spacing) : 0)
|
||||
- (showInfo ? (infoIconWidth + spacing) : 0)
|
||||
- (showPlus ? (plusButtonWidth + spacing) : 0)
|
||||
- (showPause ? (pauseButtonWidth + spacing) : 0)
|
||||
- (showBars ? (barButtonWidth + spacing) : 0);
|
||||
|
||||
ImGui.SameLine(pos);
|
||||
@@ -280,9 +296,28 @@ public class DrawGroupPair : DrawPairBase
|
||||
|
||||
if (_uiSharedService.IconButton(FontAwesomeIcon.Plus))
|
||||
{
|
||||
_ = _apiController.UserAddPair(new UserDto(new(_pair.UserData.UID)));
|
||||
var targetUid = _pair.UserData.UID;
|
||||
if (!string.IsNullOrEmpty(targetUid))
|
||||
{
|
||||
_ = SendGroupPairInviteAsync(targetUid, entryUID);
|
||||
}
|
||||
}
|
||||
UiSharedService.AttachToolTip("Pair with " + entryUID + " individually");
|
||||
UiSharedService.AttachToolTip(AppendSeenInfo("Send pairing invite to " + entryUID));
|
||||
ImGui.SameLine();
|
||||
}
|
||||
|
||||
if (showPause)
|
||||
{
|
||||
ImGui.SetCursorPosY(originalY);
|
||||
|
||||
if (_uiSharedService.IconButton(pauseIcon))
|
||||
{
|
||||
var newPermissions = _fullInfoDto.GroupUserPermissions ^ GroupUserPermissions.Paused;
|
||||
_fullInfoDto.GroupUserPermissions = newPermissions;
|
||||
_ = _apiController.GroupChangeIndividualPermissionState(new GroupPairUserPermissionDto(_group.Group, _pair.UserData, newPermissions));
|
||||
}
|
||||
|
||||
UiSharedService.AttachToolTip(AppendSeenInfo((_fullInfoDto.GroupUserPermissions.IsPaused() ? "Resume" : "Pause") + " syncing with " + entryUID));
|
||||
ImGui.SameLine();
|
||||
}
|
||||
|
||||
@@ -383,4 +418,74 @@ public class DrawGroupPair : DrawPairBase
|
||||
|
||||
return pos - spacing;
|
||||
}
|
||||
|
||||
private string AppendSeenInfo(string tooltip)
|
||||
{
|
||||
if (_pair.IsVisible) return tooltip;
|
||||
|
||||
var lastSeen = _serverConfigurationManager.GetNameForUid(_pair.UserData.UID);
|
||||
if (string.IsNullOrWhiteSpace(lastSeen)) return tooltip;
|
||||
|
||||
return tooltip + " (Vu sous : " + lastSeen + ")";
|
||||
}
|
||||
|
||||
private async Task SendGroupPairInviteAsync(string targetUid, string displayName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var ok = await _autoDetectRequestService.SendDirectUidRequestAsync(targetUid, displayName).ConfigureAwait(false);
|
||||
if (!ok) return;
|
||||
|
||||
await SendManualInviteSignalAsync(targetUid, displayName).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// errors are logged within the request service; ignore here
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SendManualInviteSignalAsync(string targetUid, string displayName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_apiController.UID)) return;
|
||||
|
||||
var senderAliasRaw = string.IsNullOrEmpty(_apiController.DisplayName) ? _apiController.UID : _apiController.DisplayName;
|
||||
var senderAlias = EncodeInviteField(senderAliasRaw);
|
||||
var targetDisplay = EncodeInviteField(displayName);
|
||||
var inviteId = Guid.NewGuid().ToString("N");
|
||||
var payloadText = new StringBuilder()
|
||||
.Append(ManualPairInvitePrefix)
|
||||
.Append(_apiController.UID)
|
||||
.Append('|')
|
||||
.Append(senderAlias)
|
||||
.Append('|')
|
||||
.Append(targetUid)
|
||||
.Append('|')
|
||||
.Append(targetDisplay)
|
||||
.Append('|')
|
||||
.Append(inviteId)
|
||||
.Append(']')
|
||||
.ToString();
|
||||
|
||||
var payload = new SeStringBuilder().AddText(payloadText).Build().Encode();
|
||||
var chatMessage = new ChatMessage
|
||||
{
|
||||
SenderName = senderAlias,
|
||||
PayloadContent = payload
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await _apiController.GroupChatSendMsg(new GroupDto(_group.Group), chatMessage).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore - invite remains tracked locally even if group chat signal fails
|
||||
}
|
||||
}
|
||||
|
||||
private static string EncodeInviteField(string value)
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(value ?? string.Empty);
|
||||
return Convert.ToBase64String(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ using MareSynchronos.Services.Mediator;
|
||||
using MareSynchronos.UI.Handlers;
|
||||
using MareSynchronos.WebAPI;
|
||||
using System.Numerics;
|
||||
using MareSynchronos.Services.ServerConfiguration;
|
||||
|
||||
namespace MareSynchronos.UI.Components;
|
||||
|
||||
@@ -20,10 +21,12 @@ public class DrawUserPair : DrawPairBase
|
||||
protected readonly MareMediator _mediator;
|
||||
private readonly SelectGroupForPairUi _selectGroupForPairUi;
|
||||
private readonly CharaDataManager _charaDataManager;
|
||||
private readonly ServerConfigurationManager _serverConfigurationManager;
|
||||
|
||||
public DrawUserPair(string id, Pair entry, UidDisplayHandler displayHandler, ApiController apiController,
|
||||
MareMediator mareMediator, SelectGroupForPairUi selectGroupForPairUi,
|
||||
UiSharedService uiSharedService, CharaDataManager charaDataManager)
|
||||
UiSharedService uiSharedService, CharaDataManager charaDataManager,
|
||||
ServerConfigurationManager serverConfigurationManager)
|
||||
: base(id, entry, apiController, displayHandler, uiSharedService)
|
||||
{
|
||||
if (_pair.UserPair == null) throw new ArgumentException("Pair must be UserPair", nameof(entry));
|
||||
@@ -31,6 +34,7 @@ public class DrawUserPair : DrawPairBase
|
||||
_selectGroupForPairUi = selectGroupForPairUi;
|
||||
_mediator = mareMediator;
|
||||
_charaDataManager = charaDataManager;
|
||||
_serverConfigurationManager = serverConfigurationManager;
|
||||
}
|
||||
|
||||
public bool IsOnline => _pair.IsOnline;
|
||||
@@ -135,9 +139,9 @@ public class DrawUserPair : DrawPairBase
|
||||
perm.SetPaused(!perm.IsPaused());
|
||||
_ = _apiController.UserSetPairPermissions(new(_pair.UserData, perm));
|
||||
}
|
||||
UiSharedService.AttachToolTip(!_pair.UserPair!.OwnPermissions.IsPaused()
|
||||
UiSharedService.AttachToolTip(AppendSeenInfo(!_pair.UserPair!.OwnPermissions.IsPaused()
|
||||
? "Pause pairing with " + entryUID
|
||||
: "Resume pairing with " + entryUID);
|
||||
: "Resume pairing with " + entryUID));
|
||||
|
||||
|
||||
var individualSoundsDisabled = (_pair.UserPair?.OwnPermissions.IsDisableSounds() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableSounds() ?? false);
|
||||
@@ -263,7 +267,7 @@ public class DrawUserPair : DrawPairBase
|
||||
{
|
||||
_selectGroupForPairUi.Open(entry);
|
||||
}
|
||||
UiSharedService.AttachToolTip("Choose pair groups for " + entryUID);
|
||||
UiSharedService.AttachToolTip(AppendSeenInfo("Choose pair groups for " + entryUID));
|
||||
|
||||
var isDisableSounds = entry.UserPair!.OwnPermissions.IsDisableSounds();
|
||||
string disableSoundsText = isDisableSounds ? "Enable sound sync" : "Disable sound sync";
|
||||
@@ -302,6 +306,16 @@ public class DrawUserPair : DrawPairBase
|
||||
{
|
||||
_ = _apiController.UserRemovePair(new(entry.UserData));
|
||||
}
|
||||
UiSharedService.AttachToolTip("Hold CTRL and click to unpair permanently from " + entryUID);
|
||||
UiSharedService.AttachToolTip(AppendSeenInfo("Hold CTRL and click to unpair permanently from " + entryUID));
|
||||
}
|
||||
|
||||
private string AppendSeenInfo(string tooltip)
|
||||
{
|
||||
if (_pair.IsVisible) return tooltip;
|
||||
|
||||
var lastSeen = _serverConfigurationManager.GetNameForUid(_pair.UserData.UID);
|
||||
if (string.IsNullOrWhiteSpace(lastSeen)) return tooltip;
|
||||
|
||||
return tooltip + " (Vu sous : " + lastSeen + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ using MareSynchronos.API.Dto.Group;
|
||||
using MareSynchronos.MareConfiguration;
|
||||
using MareSynchronos.PlayerData.Pairs;
|
||||
using MareSynchronos.Services;
|
||||
using MareSynchronos.Services.AutoDetect;
|
||||
using MareSynchronos.Services.Mediator;
|
||||
using MareSynchronos.Services.ServerConfiguration;
|
||||
using MareSynchronos.UI.Components;
|
||||
@@ -32,6 +33,7 @@ internal sealed class GroupPanel
|
||||
private readonly MareConfigService _mareConfig;
|
||||
private readonly ServerConfigurationManager _serverConfigurationManager;
|
||||
private readonly CharaDataManager _charaDataManager;
|
||||
private readonly AutoDetectRequestService _autoDetectRequestService;
|
||||
private readonly Dictionary<string, bool> _showGidForEntry = new(StringComparer.Ordinal);
|
||||
private readonly UidDisplayHandler _uidDisplayHandler;
|
||||
private readonly UiSharedService _uiShared;
|
||||
@@ -74,7 +76,7 @@ internal sealed class GroupPanel
|
||||
|
||||
public GroupPanel(CompactUi mainUi, UiSharedService uiShared, PairManager pairManager, ChatService chatServivce,
|
||||
UidDisplayHandler uidDisplayHandler, MareConfigService mareConfig, ServerConfigurationManager serverConfigurationManager,
|
||||
CharaDataManager charaDataManager)
|
||||
CharaDataManager charaDataManager, AutoDetectRequestService autoDetectRequestService)
|
||||
{
|
||||
_mainUi = mainUi;
|
||||
_uiShared = uiShared;
|
||||
@@ -84,6 +86,7 @@ internal sealed class GroupPanel
|
||||
_mareConfig = mareConfig;
|
||||
_serverConfigurationManager = serverConfigurationManager;
|
||||
_charaDataManager = charaDataManager;
|
||||
_autoDetectRequestService = autoDetectRequestService;
|
||||
}
|
||||
|
||||
private ApiController ApiController => _uiShared.ApiController;
|
||||
@@ -566,7 +569,9 @@ internal sealed class GroupPanel
|
||||
).Value,
|
||||
_uidDisplayHandler,
|
||||
_uiShared,
|
||||
_charaDataManager);
|
||||
_charaDataManager,
|
||||
_autoDetectRequestService,
|
||||
_serverConfigurationManager);
|
||||
|
||||
if (pair.IsVisible)
|
||||
visibleUsers.Add(drawPair);
|
||||
|
||||
@@ -209,12 +209,24 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.TextUnformatted("0 = No limit/infinite");
|
||||
|
||||
bool enableDownloadQueue = _configService.Current.EnableDownloadQueue;
|
||||
if (ImGui.Checkbox("Activer la file de téléchargements", ref enableDownloadQueue))
|
||||
{
|
||||
_configService.Current.EnableDownloadQueue = enableDownloadQueue;
|
||||
_configService.Save();
|
||||
}
|
||||
UiSharedService.AttachToolTip("Lance les téléchargements de personnages de manière séquentielle plutôt que tous en même temps. "
|
||||
+ "Quand l'option est activée, seul le nombre configuré de téléchargements fonctionne en parallèle.");
|
||||
|
||||
ImGui.SetNextItemWidth(250 * ImGuiHelpers.GlobalScale);
|
||||
if (ImGui.SliderInt("Maximum Parallel Downloads", ref maxParallelDownloads, 1, 10))
|
||||
{
|
||||
_configService.Current.ParallelDownloads = maxParallelDownloads;
|
||||
_configService.Save();
|
||||
}
|
||||
UiSharedService.AttachToolTip(enableDownloadQueue
|
||||
? "Nombre maximal de téléchargements de personnages autorisés simultanément lorsque la file est activée."
|
||||
: "Nombre maximal de flux de fichiers lancés en parallèle pour chaque téléchargement.");
|
||||
|
||||
ImGui.Separator();
|
||||
_uiShared.BigText("AutoDetect");
|
||||
@@ -222,7 +234,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
||||
bool enableDiscovery = _configService.Current.EnableAutoDetectDiscovery;
|
||||
using (ImRaii.Disabled(isAutoDetectSuppressed))
|
||||
{
|
||||
if (ImGui.Checkbox("Enable AutoDetect", ref enableDiscovery))
|
||||
if (ImGui.Checkbox("Activer l'AutoDetect", ref enableDiscovery))
|
||||
{
|
||||
_configService.Current.EnableAutoDetectDiscovery = enableDiscovery;
|
||||
_configService.Save();
|
||||
@@ -248,7 +260,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
||||
using (ImRaii.Disabled(isAutoDetectSuppressed || !enableDiscovery))
|
||||
{
|
||||
bool allowRequests = _configService.Current.AllowAutoDetectPairRequests;
|
||||
if (ImGui.Checkbox("Allow pair requests", ref allowRequests))
|
||||
if (ImGui.Checkbox("Activer les invitations entrantes", ref allowRequests))
|
||||
{
|
||||
_configService.Current.AllowAutoDetectPairRequests = allowRequests;
|
||||
_configService.Save();
|
||||
@@ -275,7 +287,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
||||
ImGui.Indent();
|
||||
int maxMeters = _configService.Current.AutoDetectMaxDistanceMeters;
|
||||
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
|
||||
if (ImGui.SliderInt("Max distance (meters)", ref maxMeters, 5, 100))
|
||||
if (ImGui.SliderInt("Distance max (en mètre)", ref maxMeters, 5, 100))
|
||||
{
|
||||
_configService.Current.AutoDetectMaxDistanceMeters = maxMeters;
|
||||
_configService.Save();
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using System.Linq;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Plugin.Services;
|
||||
using MareSynchronos.API.Data;
|
||||
using MareSynchronos.API.Data.Extensions;
|
||||
using MareSynchronos.MareConfiguration;
|
||||
using MareSynchronos.MareConfiguration.Models;
|
||||
using MareSynchronos.PlayerData.Pairs;
|
||||
@@ -115,25 +117,34 @@ public sealed class TypingIndicatorOverlay : WindowMediatorSubscriberBase
|
||||
continue;
|
||||
|
||||
var pair = _pairManager.GetPairByUID(uid);
|
||||
if (pair == null)
|
||||
{
|
||||
var alias = entry.User.AliasOrUID;
|
||||
if (string.IsNullOrEmpty(alias))
|
||||
continue;
|
||||
var targetIndex = -1;
|
||||
var playerName = pair?.PlayerName;
|
||||
var objectId = pair?.PlayerCharacterId ?? uint.MaxValue;
|
||||
|
||||
var aliasIndex = GetPartyIndexForName(alias);
|
||||
if (aliasIndex >= 0)
|
||||
if (objectId != 0 && objectId != uint.MaxValue)
|
||||
{
|
||||
targetIndex = GetPartyIndexForObjectId(objectId);
|
||||
if (targetIndex >= 0 && !string.IsNullOrEmpty(playerName))
|
||||
{
|
||||
DrawPartyMemberTyping(drawList, partyAddon, aliasIndex);
|
||||
var member = _partyList[targetIndex];
|
||||
var memberName = member?.Name?.TextValue;
|
||||
if (!string.IsNullOrEmpty(memberName) && !memberName.Equals(playerName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var nameIndex = GetPartyIndexForName(playerName);
|
||||
targetIndex = nameIndex;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
var index = GetPartyIndexForObjectId(pair.PlayerCharacterId);
|
||||
if (index < 0)
|
||||
if (targetIndex < 0 && !string.IsNullOrEmpty(playerName))
|
||||
{
|
||||
targetIndex = GetPartyIndexForName(playerName);
|
||||
}
|
||||
|
||||
if (targetIndex < 0)
|
||||
continue;
|
||||
|
||||
DrawPartyMemberTyping(drawList, partyAddon, index);
|
||||
DrawPartyMemberTyping(drawList, partyAddon, targetIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,10 +209,10 @@ public sealed class TypingIndicatorOverlay : WindowMediatorSubscriberBase
|
||||
|
||||
var pair = _pairManager.GetPairByUID(uid);
|
||||
var objectId = pair?.PlayerCharacterId ?? 0;
|
||||
if (pair == null)
|
||||
{
|
||||
_logger.LogInformation("TypingIndicator: no pair found for {uid}, attempting fallback", uid);
|
||||
}
|
||||
var pairName = pair?.PlayerName ?? entry.User.AliasOrUID ?? string.Empty;
|
||||
var pairIdent = pair?.Ident ?? string.Empty;
|
||||
var isPartyMember = IsPartyMember(objectId, pairName);
|
||||
var isRelevantMember = IsPlayerRelevant(pair, isPartyMember);
|
||||
|
||||
if (objectId != uint.MaxValue && objectId != 0 && TryDrawNameplateBubble(drawList, iconWrap, objectId))
|
||||
{
|
||||
@@ -209,20 +220,28 @@ public sealed class TypingIndicatorOverlay : WindowMediatorSubscriberBase
|
||||
continue;
|
||||
}
|
||||
|
||||
var pairName = pair?.PlayerName ?? entry.User.AliasOrUID ?? string.Empty;
|
||||
var pairIdent = pair?.Ident ?? string.Empty;
|
||||
var hasWorldPosition = TryResolveWorldPosition(pair, entry.User, objectId, out var worldPos);
|
||||
var isNearby = hasWorldPosition && IsWithinRelevantDistance(worldPos);
|
||||
|
||||
_logger.LogInformation("TypingIndicator: fallback draw for {uid} (objectId={objectId}, name={name}, ident={ident})",
|
||||
if (!isRelevantMember && !isNearby)
|
||||
continue;
|
||||
|
||||
if (pair == null)
|
||||
{
|
||||
_logger.LogTrace("TypingIndicator: no pair found for {uid}, attempting fallback", uid);
|
||||
}
|
||||
|
||||
_logger.LogTrace("TypingIndicator: fallback draw for {uid} (objectId={objectId}, name={name}, ident={ident})",
|
||||
uid, objectId, pairName, pairIdent);
|
||||
|
||||
if (TryResolveWorldPosition(pair, entry.User, objectId, out var worldPos))
|
||||
if (hasWorldPosition)
|
||||
{
|
||||
DrawWorldFallbackIcon(drawList, iconWrap, worldPos);
|
||||
_logger.LogInformation("TypingIndicator: fallback world draw for {uid} at {pos}", uid, worldPos);
|
||||
_logger.LogTrace("TypingIndicator: fallback world draw for {uid} at {pos}", uid, worldPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation("TypingIndicator: could not resolve position for {uid}", uid);
|
||||
_logger.LogTrace("TypingIndicator: could not resolve position for {uid}", uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -464,6 +483,48 @@ public sealed class TypingIndicatorOverlay : WindowMediatorSubscriberBase
|
||||
return -1;
|
||||
}
|
||||
|
||||
private bool IsPartyMember(uint objectId, string? playerName)
|
||||
{
|
||||
if (objectId != 0 && objectId != uint.MaxValue && GetPartyIndexForObjectId(objectId) >= 0)
|
||||
return true;
|
||||
|
||||
if (!string.IsNullOrEmpty(playerName) && GetPartyIndexForName(playerName) >= 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsPlayerRelevant(Pair? pair, bool isPartyMember)
|
||||
{
|
||||
if (isPartyMember)
|
||||
return true;
|
||||
|
||||
if (pair?.UserPair != null)
|
||||
{
|
||||
var userPair = pair.UserPair;
|
||||
if (userPair.OtherPermissions.IsPaired() || userPair.OwnPermissions.IsPaired())
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pair?.GroupPair != null && pair.GroupPair.Any(g =>
|
||||
!g.Value.GroupUserPermissions.IsPaused() &&
|
||||
!g.Key.GroupUserPermissions.IsPaused()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsWithinRelevantDistance(Vector3 position)
|
||||
{
|
||||
if (_clientState.LocalPlayer == null)
|
||||
return false;
|
||||
|
||||
var distance = Vector3.Distance(_clientState.LocalPlayer.Position, position);
|
||||
return distance <= 40f;
|
||||
}
|
||||
|
||||
private static unsafe uint GetEntityId(nint address)
|
||||
{
|
||||
if (address == nint.Zero) return 0;
|
||||
|
||||
Reference in New Issue
Block a user