27 Commits

Author SHA1 Message Date
b4cad9c745 Version bump 2025-09-09 22:03:05 +01:00
100c5612dc Fix VRAM sort being a little funky. And in the wrong order. 2025-09-09 21:46:42 +01:00
b8e0100bdf Merge pull request #20 from ProfessorFartsalot/main
Colour changes, including our own colour library!
2025-09-09 21:38:10 +01:00
137db42446 Colour changes, including our own colour library!
+ Also began work on namespace changes! Will need to be merged with any current pending namespace changes.
2025-09-08 14:48:11 -04:00
956d2009eb Merge pull request #19 from ProfessorFartsalot/main
Multiple UI improvements and convenience things
2025-09-06 15:11:10 +01:00
ec66da8b5e Merge pull request #18 from BoxuChan/main
Code Optimizations for SignalR/ApiController
2025-09-06 15:08:24 +01:00
0555ee0db7 Clean up unused imports
Not sure how these got put in, but they are not used nor needed.
2025-09-05 17:34:15 -04:00
837b487281 Several UI enhancements
+ Added paused user field to main UI
+ Excluded paused users from online list
+ Excluded visible users from online list
+ Fixed an issue where remotely paused users would always show offline
+ Ensured paused users returns true if EITHER client OR remote paused them.
+ Made paused users show as Grey
+ Changed paired icon from check to snowflake
+ Fixed a bug where clients would have icons for both paired AND visible simultaneously
+ Fixed a bug where clients would show both online AND visible unnecessarily.
+ Made paused users render just above offline users.
+ Changed default ui icon from SS to Snowflake/Flower thingy.
2025-09-05 17:31:45 -04:00
9a0f2c062c Add /snow as possible command
Due to popular request, I've added /snow as a possible command.
2025-09-05 13:39:25 -04:00
BoxuChan
6e9c69c2a8 Code Optimizations for SignalR/ApiController 2025-09-05 17:47:02 +02:00
f0cef81b5e Merge pull request #17 from ProfessorFartsalot/main
Fix health check, reconnect automatically on error
2025-09-05 06:12:43 +01:00
d8160effd0 Fix up client reconnect code
Simplified the reconnect code so that redis is made aware that we have a new connection.

Made the reconnect fire immediately on error rather than waiting for subsequent errors.
2025-09-04 21:50:47 -04:00
18da07763c Add in extra check to see if hub server DC'd 2025-09-04 18:41:44 -04:00
3c448f2290 Fix health check, reconnect automatically on error
+ Made health check actually do something instead of just logging connection health issues.

+ Requires server code change to enable the health check so it's not just returning false all the time.

+ Forcibly reconnects the client when they've had connection issues.
2025-09-04 17:18:26 -04:00
cadc7e223f minor fixes 2025-09-04 14:26:15 +01:00
e1baca7940 Version bump 2025-09-03 16:11:51 +01:00
c2e0cf65a8 Packages update 2025-09-03 16:07:00 +01:00
a3d0408d6f More sensible VRAM sorting thing 2025-09-03 16:01:51 +01:00
9ca6931bb8 Fixed syncshell UI messing up if there were members you didn't have an individual pair with 2025-09-03 15:41:47 +01:00
f22eff1f72 Pause users in syncshells (prototype) 2025-09-03 14:20:43 +01:00
11e097d696 Sort syncshells by VRAM usage 2025-09-03 12:53:21 +01:00
f7ecb45774 Logo, by Wasa Bee. 2025-09-02 11:18:27 +01:00
00a7328e3a Merge pull request 'Multiple aesthetic changes with the profile editor ui and connection error on duplicate UIDs.' (#2) from ProfessorFartsalot/SnowcloakClient:main into main
Reviewed-on: Eauldane/SnowcloakClient#2
Reviewed-by: Eauldane <elf@eauldane.com>
2025-09-02 02:09:39 +00:00
c39229a28b Merge branch 'main' into main 2025-09-02 02:09:04 +00:00
00c56b0888 Merge branch 'main' of https://imbuilding.anuke.org/ProfessorFartsalot/SnowcloakClient 2025-09-01 16:12:06 -04:00
15898d54c2 Update color for online member count 2025-09-01 16:11:45 -04:00
6d5ed42e60 Version bump 2025-09-01 20:57:26 +01:00
20 changed files with 257 additions and 95 deletions

View File

@@ -12,6 +12,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.editorconfig = .editorconfig .editorconfig = .editorconfig
EndProjectSection EndProjectSection
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SnowcloakSync", "SnowcloakSync\SnowcloakSync.csproj", "{E633A968-2FB8-48FF-8136-5EBAEDF8E6F3}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -36,6 +38,14 @@ Global
{5A0B7434-8D89-4E90-B55C-B4A7AE1A6ADE}.Release|Any CPU.Build.0 = Release|Any CPU {5A0B7434-8D89-4E90-B55C-B4A7AE1A6ADE}.Release|Any CPU.Build.0 = Release|Any CPU
{5A0B7434-8D89-4E90-B55C-B4A7AE1A6ADE}.Release|x64.ActiveCfg = Release|Any CPU {5A0B7434-8D89-4E90-B55C-B4A7AE1A6ADE}.Release|x64.ActiveCfg = Release|Any CPU
{5A0B7434-8D89-4E90-B55C-B4A7AE1A6ADE}.Release|x64.Build.0 = Release|Any CPU {5A0B7434-8D89-4E90-B55C-B4A7AE1A6ADE}.Release|x64.Build.0 = Release|Any CPU
{E633A968-2FB8-48FF-8136-5EBAEDF8E6F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E633A968-2FB8-48FF-8136-5EBAEDF8E6F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E633A968-2FB8-48FF-8136-5EBAEDF8E6F3}.Debug|x64.ActiveCfg = Debug|Any CPU
{E633A968-2FB8-48FF-8136-5EBAEDF8E6F3}.Debug|x64.Build.0 = Debug|Any CPU
{E633A968-2FB8-48FF-8136-5EBAEDF8E6F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E633A968-2FB8-48FF-8136-5EBAEDF8E6F3}.Release|Any CPU.Build.0 = Release|Any CPU
{E633A968-2FB8-48FF-8136-5EBAEDF8E6F3}.Release|x64.ActiveCfg = Release|Any CPU
{E633A968-2FB8-48FF-8136-5EBAEDF8E6F3}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@@ -7,6 +7,7 @@ namespace MareSynchronos.MareConfiguration.Configurations;
[Serializable] [Serializable]
public class MareConfig : IMareConfiguration public class MareConfig : IMareConfiguration
{ {
public bool SortSyncshellsByVRAM { get; set; } = false;
public int ExpectedTOSVersion = 2; public int ExpectedTOSVersion = 2;
public int AcceptedTOSVersion { get; set; } = 0; public int AcceptedTOSVersion { get; set; } = 0;
public bool AcceptedAgreement { get; set; } = false; public bool AcceptedAgreement { get; set; } = false;

View File

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Dalamud.NET.Sdk/13.0.0"> <Project Sdk="Dalamud.NET.Sdk/13.1.0">
<PropertyGroup> <PropertyGroup>
<AssemblyName>Snowcloak</AssemblyName> <AssemblyName>Snowcloak</AssemblyName>
<Version>0.2.0.3</Version> <Version>0.2.4</Version>
<PackageProjectUrl>https://github.com/Eauldane/SnowcloakClient/</PackageProjectUrl> <PackageProjectUrl>https://git.snowcloak-sync.com/Eauldane/SnowcloakClient/</PackageProjectUrl>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -14,10 +14,12 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Chaos.NaCl.Standard" Version="1.0.0" /> <PackageReference Include="Chaos.NaCl.Standard" Version="1.0.0" />
<PackageReference Include="Downloader" Version="3.3.4" /> <PackageReference Include="Downloader" Version="4.0.3" />
<PackageReference Include="K4os.Compression.LZ4.Legacy" Version="1.3.8" /> <PackageReference Include="K4os.Compression.LZ4.Legacy" Version="1.3.8" />
<PackageReference Include="K4os.Compression.LZ4.Streams" Version="1.3.8" /> <PackageReference Include="K4os.Compression.LZ4.Streams" Version="1.3.8" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.212"> <PackageReference Include="MessagePack" Version="3.1.4" />
<PackageReference Include="MessagePack.Annotations" Version="3.1.4" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.213">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
@@ -29,6 +31,8 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.14.0" /> <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.14.0" />
<PackageReference Update="DalamudPackager" Version="13.1.0" />
<PackageReference Include="System.IO.Pipelines" Version="9.0.8" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="Exists('.\Penumbra.Api\Penumbra.Api.csproj')"> <ItemGroup Condition="Exists('.\Penumbra.Api\Penumbra.Api.csproj')">
@@ -54,6 +58,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\MareAPI\MareSynchronosAPI\MareSynchronos.API.csproj" /> <ProjectReference Include="..\MareAPI\MareSynchronosAPI\MareSynchronos.API.csproj" />
<ProjectReference Include="..\SnowcloakSync\SnowcloakSync.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -235,11 +235,17 @@ public class Pair : DisposableMediatorSubscriberBase
{ {
string? noteOrName = GetNoteOrName(); string? noteOrName = GetNoteOrName();
if (noteOrName != null) if (_mareConfig.Current.SortSyncshellsByVRAM)
{
return($"0{LastAppliedApproximateVRAMBytes}");
}
else if (noteOrName != null) {
return $"0{noteOrName}"; return $"0{noteOrName}";
else }
else {
return $"9{UserData.AliasOrUID}"; return $"9{UserData.AliasOrUID}";
} }
}
public string GetPlayerNameHash() public string GetPlayerNameHash()
{ {

View File

@@ -14,8 +14,9 @@ namespace MareSynchronos.Services;
public sealed class CommandManagerService : IDisposable public sealed class CommandManagerService : IDisposable
{ {
private const string _commandName = "/sync"; private const string _commandName = "/snow";
private const string _commandName2 = "/snowcloak"; private const string _commandName2 = "/snowcloak";
private const string _commandName3 = "/sync";
private const string _ssCommandPrefix = "/ss"; private const string _ssCommandPrefix = "/ss";
@@ -48,6 +49,10 @@ public sealed class CommandManagerService : IDisposable
{ {
HelpMessage = "Opens the Snowcloak UI" HelpMessage = "Opens the Snowcloak UI"
}); });
_commandManager.AddHandler(_commandName3, new CommandInfo(OnCommand)
{
HelpMessage = "Opens the Snowcloak UI"
});
// Lazy registration of all possible /ss# commands which tbf is what the game does for linkshells anyway // Lazy registration of all possible /ss# commands which tbf is what the game does for linkshells anyway
for (int i = 1; i <= ChatService.CommandMaxNumber; ++i) for (int i = 1; i <= ChatService.CommandMaxNumber; ++i)

View File

@@ -9,6 +9,6 @@
"customization" "customization"
], ],
"IconUrl": "https://raw.githubusercontent.com/Eauldane/SnowcloakClient/refs/heads/main/MareSynchronos/images/logo.png", "IconUrl": "https://raw.githubusercontent.com/Eauldane/SnowcloakClient/refs/heads/main/MareSynchronos/images/logo.png",
"RepoUrl": "https://github.com/Eauldane/SnowcloakClient", "RepoUrl": "https://git.snowcloak-sync.com/Eauldane/SnowcloakClient",
"CanUnloadAsync": true "CanUnloadAsync": true
} }

View File

@@ -1054,7 +1054,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
_configService.Current.OpenMareHubOnGposeStart = openInGpose; _configService.Current.OpenMareHubOnGposeStart = openInGpose;
_configService.Save(); _configService.Save();
} }
_uiSharedService.DrawHelpText("This will automatically open the import menu when loading into Gpose. If unchecked you can open the menu manually with /sync gpose"); _uiSharedService.DrawHelpText("This will automatically open the import menu when loading into Gpose. If unchecked you can open the menu manually with /snow gpose");
bool downloadDataOnConnection = _configService.Current.DownloadMcdDataOnConnection; bool downloadDataOnConnection = _configService.Current.DownloadMcdDataOnConnection;
if (ImGui.Checkbox("Download Online Character Data on connecting", ref downloadDataOnConnection)) if (ImGui.Checkbox("Download Online Character Data on connecting", ref downloadDataOnConnection))
{ {

View File

@@ -105,7 +105,7 @@ public class CompactUi : WindowMediatorSubscriberBase
protected override void DrawInternal() protected override void DrawInternal()
{ {
if (_serverManager.CurrentApiUrl.Equals(ApiController.SnowcloakServiceUri, StringComparison.Ordinal)) if (_serverManager.CurrentApiUrl.Equals(ApiController.SnowcloakServiceUri, StringComparison.Ordinal))
UiSharedService.AccentColor = new(0.4275f, 0.6863f, 1f, 1f); UiSharedService.AccentColor = SnowcloakSync.Utils.Colours._snowcloakOnline;
else else
UiSharedService.AccentColor = ImGuiColors.ParsedGreen; UiSharedService.AccentColor = ImGuiColors.ParsedGreen;
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ImGui.GetStyle().WindowPadding.Y - 1f * ImGuiHelpers.GlobalScale + ImGui.GetStyle().ItemSpacing.Y); ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ImGui.GetStyle().WindowPadding.Y - 1f * ImGuiHelpers.GlobalScale + ImGui.GetStyle().ItemSpacing.Y);
@@ -362,13 +362,14 @@ public class CompactUi : WindowMediatorSubscriberBase
: (ImGui.GetWindowContentRegionMax().Y - ImGui.GetWindowContentRegionMin().Y) - TransferPartHeight - ImGui.GetCursorPosY(); : (ImGui.GetWindowContentRegionMax().Y - ImGui.GetWindowContentRegionMin().Y) - TransferPartHeight - ImGui.GetCursorPosY();
var users = GetFilteredUsers().OrderBy(u => u.GetPairSortKey(), StringComparer.Ordinal); var users = GetFilteredUsers().OrderBy(u => u.GetPairSortKey(), StringComparer.Ordinal);
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 onlineUsers = users.Where(u => u.UserPair!.OtherPermissions.IsPaired() && (u.IsOnline && !u.IsVisible && (!u.UserPair!.OtherPermissions.IsPaused() && !u.UserPair!.OwnPermissions.IsPaused()))).Select(c => new DrawUserPair("Online" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager)).ToList();
var pausedUsers = users.Where(u => u.UserPair!.OtherPermissions.IsPaired() && (u.UserPair!.OtherPermissions.IsPaused() || u.UserPair!.OwnPermissions.IsPaused())).Select(c => new DrawUserPair("Paused" + 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 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 offlineUsers = users.Where(u => !u.UserPair!.OtherPermissions.IsPaired() || !u.IsOnline && (!u.UserPair!.OwnPermissions.IsPaused() && !u.UserPair.OtherPermissions.IsPaused())).Select(c => new DrawUserPair("Offline" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager)).ToList();
ImGui.BeginChild("list", new Vector2(WindowContentWidth, ySize), border: false); ImGui.BeginChild("list", new Vector2(WindowContentWidth, ySize), border: false);
_pairGroupsUi.Draw(visibleUsers, onlineUsers, offlineUsers); _pairGroupsUi.Draw(visibleUsers, onlineUsers, pausedUsers, offlineUsers);
ImGui.EndChild(); ImGui.EndChild();
} }
@@ -387,7 +388,7 @@ public class CompactUi : WindowMediatorSubscriberBase
{ {
ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth()) / 2 - (userSize.X + textSize.X) / 2 - ImGui.GetStyle().ItemSpacing.X / 2); ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth()) / 2 - (userSize.X + textSize.X) / 2 - ImGui.GetStyle().ItemSpacing.X / 2);
if (!printShard) ImGui.AlignTextToFramePadding(); if (!printShard) ImGui.AlignTextToFramePadding();
ImGui.TextColored(ImGuiColors.ParsedGreen, userCount); ImGui.TextColored(new Vector4(0.675f, 0.985f, 1f, 1f), userCount);
ImGui.SameLine(); ImGui.SameLine();
if (!printShard) ImGui.AlignTextToFramePadding(); if (!printShard) ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted("Users Online"); ImGui.TextUnformatted("Users Online");

View File

@@ -20,6 +20,7 @@ public class DrawGroupPair : DrawPairBase
private readonly GroupPairFullInfoDto _fullInfoDto; private readonly GroupPairFullInfoDto _fullInfoDto;
private readonly GroupFullInfoDto _group; private readonly GroupFullInfoDto _group;
private readonly CharaDataManager _charaDataManager; private readonly CharaDataManager _charaDataManager;
public long VRAMUsage { get; set; }
public DrawGroupPair(string id, Pair entry, ApiController apiController, public DrawGroupPair(string id, Pair entry, ApiController apiController,
MareMediator mareMediator, GroupFullInfoDto group, GroupPairFullInfoDto fullInfoDto, MareMediator mareMediator, GroupFullInfoDto group, GroupPairFullInfoDto fullInfoDto,
@@ -80,6 +81,7 @@ public class DrawGroupPair : DrawPairBase
} }
if (_pair.LastAppliedDataBytes >= 0) if (_pair.LastAppliedDataBytes >= 0)
{ {
presenceText += UiSharedService.TooltipSeparator; presenceText += UiSharedService.TooltipSeparator;
presenceText += ((!_pair.IsVisible) ? "(Last) " : string.Empty) + "Mods Info" + Environment.NewLine; presenceText += ((!_pair.IsVisible) ? "(Last) " : string.Empty) + "Mods Info" + Environment.NewLine;
presenceText += "Files Size: " + UiSharedService.ByteToString(_pair.LastAppliedDataBytes, true); presenceText += "Files Size: " + UiSharedService.ByteToString(_pair.LastAppliedDataBytes, true);
@@ -127,6 +129,9 @@ public class DrawGroupPair : DrawPairBase
protected override float DrawRightSide(float textPosY, float originalY) protected override float DrawRightSide(float textPosY, float originalY)
{ {
var pauseIcon = _pair.IsPaused ? FontAwesomeIcon.Play : FontAwesomeIcon.Pause;
var pauseIconSize = _uiSharedService.GetIconButtonSize(pauseIcon);
var spacingX = ImGui.GetStyle().ItemSpacing.X;
var entryUID = _fullInfoDto.UserAliasOrUID; var entryUID = _fullInfoDto.UserAliasOrUID;
var entryIsMod = _fullInfoDto.GroupPairStatusInfo.IsModerator(); var entryIsMod = _fullInfoDto.GroupPairStatusInfo.IsModerator();
var entryIsOwner = string.Equals(_pair.UserData.UID, _group.OwnerUID, StringComparison.Ordinal); var entryIsOwner = string.Equals(_pair.UserData.UID, _group.OwnerUID, StringComparison.Ordinal);
@@ -145,19 +150,27 @@ public class DrawGroupPair : DrawPairBase
bool showInfo = (individualAnimDisabled || individualSoundsDisabled || animDisabled || soundsDisabled); bool showInfo = (individualAnimDisabled || individualSoundsDisabled || animDisabled || soundsDisabled);
bool showPlus = _pair.UserPair == null; bool showPlus = _pair.UserPair == null;
bool showBars = (userIsOwner || (userIsModerator && !entryIsMod && !entryIsOwner)) || !_pair.IsPaused; bool showBars = (userIsOwner || (userIsModerator && !entryIsMod && !entryIsOwner)) || !_pair.IsPaused;
bool showPause = true;
var spacing = ImGui.GetStyle().ItemSpacing.X; var spacing = ImGui.GetStyle().ItemSpacing.X;
var permIcon = (individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled) ? FontAwesomeIcon.ExclamationTriangle var permIcon = (individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled) ? FontAwesomeIcon.ExclamationTriangle
: ((soundsDisabled || animDisabled || vfxDisabled) ? FontAwesomeIcon.InfoCircle : FontAwesomeIcon.None); : ((soundsDisabled || animDisabled || vfxDisabled) ? FontAwesomeIcon.InfoCircle : FontAwesomeIcon.None);
var runningIconWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Running).X; var runningIconWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Running).X;
var infoIconWidth = UiSharedService.GetIconSize(permIcon).X; var infoIconWidth = UiSharedService.GetIconSize(permIcon).X;
var plusButtonWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Plus).X; var plusButtonWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Plus).X;
var pauseButtonWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Plus).X;
var barButtonWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars).X; var barButtonWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars).X;
var barButtonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars);
var windowEndX = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth();
var rightSidePos = windowEndX - barButtonSize.X;
var pos = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() + spacing var pos = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() + spacing
- (showShared ? (runningIconWidth + spacing) : 0) - (showShared ? (runningIconWidth + spacing) : 0)
- (showInfo ? (infoIconWidth + spacing) : 0) - (showInfo ? (infoIconWidth + spacing) : 0)
- (showPlus ? (plusButtonWidth + spacing) : 0) - (showPlus ? (plusButtonWidth + spacing) : 0)
- (showPause ? (pauseButtonWidth + spacing) : 0)
- (showBars ? (barButtonWidth + spacing) : 0); - (showBars ? (barButtonWidth + spacing) : 0);
ImGui.SameLine(pos); ImGui.SameLine(pos);
@@ -264,6 +277,7 @@ public class DrawGroupPair : DrawPairBase
ImGui.SameLine(); ImGui.SameLine();
} }
if (showPlus) if (showPlus)
{ {
ImGui.SetCursorPosY(originalY); ImGui.SetCursorPosY(originalY);
@@ -275,7 +289,25 @@ public class DrawGroupPair : DrawPairBase
UiSharedService.AttachToolTip("Pair with " + entryUID + " individually"); UiSharedService.AttachToolTip("Pair with " + entryUID + " individually");
ImGui.SameLine(); ImGui.SameLine();
} }
if (showPause)
{
//rightSidePos -= pauseIconSize.X + spacingX;
ImGui.SetCursorPosY(originalY);
if (_uiSharedService.IconButton(pauseIcon))
{
var perm = _pair.UserPair!.OwnPermissions;
perm.SetPaused(!perm.IsPaused());
_ = _apiController.UserSetPairPermissions(new(_pair.UserData, perm));
}
UiSharedService.AttachToolTip(!_fullInfoDto.GroupUserPermissions.IsPaused()
? "Pause pairing with " + entryUID
: "Resume pairing with " + entryUID);
ImGui.SameLine();
}
if (showBars) if (showBars)
{ {
ImGui.SetCursorPosY(originalY); ImGui.SetCursorPosY(originalY);
@@ -285,7 +317,6 @@ public class DrawGroupPair : DrawPairBase
ImGui.OpenPopup("Popup"); ImGui.OpenPopup("Popup");
} }
} }
if (ImGui.BeginPopup("Popup")) if (ImGui.BeginPopup("Popup"))
{ {
if ((userIsModerator || userIsOwner) && !(entryIsMod || entryIsOwner)) if ((userIsModerator || userIsOwner) && !(entryIsMod || entryIsOwner))

View File

@@ -19,6 +19,7 @@ public class DrawUserPair : DrawPairBase
protected readonly MareMediator _mediator; protected readonly MareMediator _mediator;
private readonly SelectGroupForPairUi _selectGroupForPairUi; private readonly SelectGroupForPairUi _selectGroupForPairUi;
private readonly CharaDataManager _charaDataManager; private readonly CharaDataManager _charaDataManager;
public long VramUsage { get; set; }
public DrawUserPair(string id, Pair entry, UidDisplayHandler displayHandler, ApiController apiController, public DrawUserPair(string id, Pair entry, UidDisplayHandler displayHandler, ApiController apiController,
MareMediator mareMediator, SelectGroupForPairUi selectGroupForPairUi, MareMediator mareMediator, SelectGroupForPairUi selectGroupForPairUi,
@@ -51,26 +52,27 @@ public class DrawUserPair : DrawPairBase
{ {
connectionIcon = FontAwesomeIcon.PauseCircle; connectionIcon = FontAwesomeIcon.PauseCircle;
connectionText = "Pairing status with " + _pair.UserData.AliasOrUID + " is paused"; connectionText = "Pairing status with " + _pair.UserData.AliasOrUID + " is paused";
connectionColor = ImGuiColors.DalamudYellow; connectionColor = ImGuiColors.DalamudGrey;
} }
else else
{ {
connectionIcon = FontAwesomeIcon.Check; connectionIcon = FontAwesomeIcon.Snowflake;
connectionText = "You are paired with " + _pair.UserData.AliasOrUID; connectionText = "You are paired with " + _pair.UserData.AliasOrUID;
connectionColor = ImGuiColors.ParsedGreen; connectionColor = _pair.IsOnline ? SnowcloakSync.Utils.Colours._snowcloakOnline : ImGuiColors.DalamudGrey;
} }
if (!_pair.IsVisible)
ImGui.SetCursorPosY(textPosY);
ImGui.PushFont(UiBuilder.IconFont);
UiSharedService.ColorText(connectionIcon.ToIconString(), connectionColor);
ImGui.PopFont();
UiSharedService.AttachToolTip(connectionText);
if (_pair is { IsOnline: true, IsVisible: true })
{ {
ImGui.SameLine();
ImGui.SetCursorPosY(textPosY); ImGui.SetCursorPosY(textPosY);
ImGui.PushFont(UiBuilder.IconFont); ImGui.PushFont(UiBuilder.IconFont);
UiSharedService.ColorText(FontAwesomeIcon.Eye.ToIconString(), ImGuiColors.ParsedGreen); UiSharedService.ColorText(connectionIcon.ToIconString(), connectionColor);
ImGui.PopFont();
UiSharedService.AttachToolTip(connectionText);
}
if (_pair is { IsOnline: true, IsVisible: true })
{
ImGui.SetCursorPosY(textPosY);
ImGui.PushFont(UiBuilder.IconFont);
UiSharedService.ColorText(FontAwesomeIcon.Eye.ToIconString(), SnowcloakSync.Utils.Colours._snowcloakOnline);
if (ImGui.IsItemClicked()) if (ImGui.IsItemClicked())
{ {
_mediator.Publish(new TargetPairMessage(_pair)); _mediator.Publish(new TargetPairMessage(_pair));
@@ -84,6 +86,7 @@ public class DrawUserPair : DrawPairBase
visibleTooltip += "Files Size: " + UiSharedService.ByteToString(_pair.LastAppliedDataBytes, true); visibleTooltip += "Files Size: " + UiSharedService.ByteToString(_pair.LastAppliedDataBytes, true);
if (_pair.LastAppliedApproximateVRAMBytes >= 0) if (_pair.LastAppliedApproximateVRAMBytes >= 0)
{ {
VramUsage = _pair.LastAppliedApproximateVRAMBytes;
visibleTooltip += Environment.NewLine + "Approx. VRAM Usage: " + UiSharedService.ByteToString(_pair.LastAppliedApproximateVRAMBytes, true); visibleTooltip += Environment.NewLine + "Approx. VRAM Usage: " + UiSharedService.ByteToString(_pair.LastAppliedApproximateVRAMBytes, true);
} }
if (_pair.LastAppliedDataTris >= 0) if (_pair.LastAppliedDataTris >= 0)
@@ -97,6 +100,8 @@ public class DrawUserPair : DrawPairBase
} }
} }
protected override float DrawRightSide(float textPosY, float originalY) protected override float DrawRightSide(float textPosY, float originalY)
{ {
var pauseIcon = _pair.UserPair!.OwnPermissions.IsPaused() ? FontAwesomeIcon.Play : FontAwesomeIcon.Pause; var pauseIcon = _pair.UserPair!.OwnPermissions.IsPaused() ? FontAwesomeIcon.Play : FontAwesomeIcon.Pause;

View File

@@ -418,21 +418,34 @@ internal sealed class GroupPanel
ImGui.Indent(20); ImGui.Indent(20);
if (_expandedGroupState[groupDto.GID]) if (_expandedGroupState[groupDto.GID])
{ {
var sortedPairs = pairsInGroup IOrderedEnumerable<Pair> sortedPairs;
.OrderByDescending(u => string.Equals(u.UserData.UID, groupDto.OwnerUID, StringComparison.Ordinal)) if (!_mareConfig.Current.SortSyncshellsByVRAM)
.ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsModerator()) {
.ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsPinned()) sortedPairs = pairsInGroup
.ThenBy(u => u.GetPairSortKey(), StringComparer.OrdinalIgnoreCase); .OrderByDescending(u => string.Equals(u.UserData.UID, groupDto.OwnerUID, StringComparison.Ordinal))
.ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsModerator())
.ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsPinned())
.ThenBy(u => u.GetPairSortKey(), StringComparer.OrdinalIgnoreCase);
}
else
{
sortedPairs = pairsInGroup
.OrderByDescending(u => string.Equals(u.UserData.UID, groupDto.OwnerUID, StringComparison.Ordinal))
.ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsModerator())
.ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsPinned())
.ThenByDescending(u => u.LastAppliedApproximateVRAMBytes);
}
var visibleUsers = new List<DrawGroupPair>(); var visibleUsers = new List<DrawGroupPair>();
var onlineUsers = new List<DrawGroupPair>(); var onlineUsers = new List<DrawGroupPair>();
var offlineUsers = new List<DrawGroupPair>(); var offlineUsers = new List<DrawGroupPair>();
foreach (var pair in sortedPairs) foreach (var pair in sortedPairs)
{ {
var drawPair = new DrawGroupPair( var drawPair = new DrawGroupPair(
groupDto.GID + pair.UserData.UID, pair, groupDto.GID + pair.UserData.UID, pair,
ApiController, _mainUi.Mediator, groupDto, ApiController, _mainUi.Mediator, groupDto,
pair.GroupPair.Single( pair.GroupPair.Single(
g => GroupDataComparer.Instance.Equals(g.Key.Group, groupDto.Group) g => GroupDataComparer.Instance.Equals(g.Key.Group, groupDto.Group)
).Value, ).Value,
@@ -453,6 +466,8 @@ internal sealed class GroupPanel
ImGui.TextUnformatted("Visible"); ImGui.TextUnformatted("Visible");
ImGui.Separator(); ImGui.Separator();
_uidDisplayHandler.RenderPairList(visibleUsers); _uidDisplayHandler.RenderPairList(visibleUsers);
} }
if (onlineUsers.Count > 0) if (onlineUsers.Count > 0)

View File

@@ -28,15 +28,15 @@ public class PairGroupsUi
_uiSharedService = uiSharedService; _uiSharedService = uiSharedService;
} }
public void Draw<T>(List<T> visibleUsers, List<T> onlineUsers, List<T> offlineUsers) where T : DrawPairBase public void Draw<T>(List<T> visibleUsers, List<T> onlineUsers, List<T> pausedUsers, List<T> offlineUsers) where T : DrawPairBase
{ {
// Only render those tags that actually have pairs in them, otherwise // Only render those tags that actually have pairs in them, otherwise
// we can end up with a bunch of useless pair groups // we can end up with a bunch of useless pair groups
var tagsWithPairsInThem = _tagHandler.GetAllTagsSorted(); var tagsWithPairsInThem = _tagHandler.GetAllTagsSorted();
var allUsers = onlineUsers.Concat(offlineUsers).ToList(); var allUsers = onlineUsers.Concat(offlineUsers).Concat(pausedUsers).ToList();
if (typeof(T) == typeof(DrawUserPair)) if (typeof(T) == typeof(DrawUserPair))
{ {
DrawUserPairs(tagsWithPairsInThem, allUsers.Cast<DrawUserPair>().ToList(), visibleUsers.Cast<DrawUserPair>(), onlineUsers.Cast<DrawUserPair>(), offlineUsers.Cast<DrawUserPair>()); DrawUserPairs(tagsWithPairsInThem, allUsers.Cast<DrawUserPair>().ToList(), visibleUsers.Cast<DrawUserPair>(), onlineUsers.Cast<DrawUserPair>(), pausedUsers.Cast<DrawUserPair>(), offlineUsers.Cast<DrawUserPair>());
} }
} }
@@ -91,13 +91,19 @@ public class PairGroupsUi
} }
} }
private void DrawCategory(string tag, IEnumerable<DrawPairBase> onlineUsers, IEnumerable<DrawPairBase> allUsers, IEnumerable<DrawPairBase>? visibleUsers = null) private void DrawCategory(string tag, IEnumerable<DrawPairBase> onlineUsers, IEnumerable<DrawPairBase> pausedUsers, IEnumerable<DrawPairBase> allUsers, IEnumerable<DrawPairBase>? visibleUsers = null)
{ {
IEnumerable<DrawPairBase> usersInThisTag; IEnumerable<DrawPairBase> usersInThisTag;
HashSet<string>? otherUidsTaggedWithTag = null; HashSet<string>? otherUidsTaggedWithTag = null;
bool isSpecialTag = false; bool isSpecialTag = false;
int visibleInThisTag = 0; int visibleInThisTag = 0;
if (tag is TagHandler.CustomOfflineTag or TagHandler.CustomOnlineTag or TagHandler.CustomVisibleTag or TagHandler.CustomUnpairedTag)
if (tag is TagHandler.CustomPausedTag)
{
usersInThisTag = pausedUsers;
isSpecialTag = true;
}
else if (tag is TagHandler.CustomOfflineTag or TagHandler.CustomOnlineTag or TagHandler.CustomVisibleTag or TagHandler.CustomUnpairedTag)
{ {
usersInThisTag = onlineUsers; usersInThisTag = onlineUsers;
isSpecialTag = true; isSpecialTag = true;
@@ -113,14 +119,13 @@ public class PairGroupsUi
if (isSpecialTag && !usersInThisTag.Any()) return; if (isSpecialTag && !usersInThisTag.Any()) return;
DrawName(tag, isSpecialTag, visibleInThisTag, usersInThisTag.Count(), otherUidsTaggedWithTag?.Count); DrawName(tag, isSpecialTag, visibleInThisTag, usersInThisTag.Count(), pausedUsers.Count(), otherUidsTaggedWithTag?.Count);
if (!isSpecialTag) if (!isSpecialTag)
{ {
using (ImRaii.PushId($"group-{tag}-buttons")) DrawButtons(tag, allUsers.Cast<DrawUserPair>().Where(p => otherUidsTaggedWithTag!.Contains(p.UID)).ToList()); using (ImRaii.PushId($"group-{tag}-buttons")) DrawButtons(tag, allUsers.Cast<DrawUserPair>().Where(p => otherUidsTaggedWithTag!.Contains(p.UID)).ToList());
} }
else else
{ {
// Avoid uncomfortably close group names
if (!_tagHandler.IsTagOpen(tag)) if (!_tagHandler.IsTagOpen(tag))
{ {
var size = ImGui.CalcTextSize("").Y + ImGui.GetStyle().FramePadding.Y * 2f; var size = ImGui.CalcTextSize("").Y + ImGui.GetStyle().FramePadding.Y * 2f;
@@ -151,18 +156,19 @@ public class PairGroupsUi
UiSharedService.AttachToolTip($"Delete Group {tag} (Will not delete the pairs)" + Environment.NewLine + "Hold CTRL to delete"); UiSharedService.AttachToolTip($"Delete Group {tag} (Will not delete the pairs)" + Environment.NewLine + "Hold CTRL to delete");
} }
private void DrawName(string tag, bool isSpecialTag, int visible, int online, int? total) private void DrawName(string tag, bool isSpecialTag, int visible, int online, int paused, int? total)
{ {
string displayedName = tag switch string displayedName = tag switch
{ {
TagHandler.CustomUnpairedTag => "Unpaired", TagHandler.CustomUnpairedTag => "Unpaired",
TagHandler.CustomOfflineTag => "Offline", TagHandler.CustomOfflineTag => "Offline",
TagHandler.CustomOnlineTag => _mareConfig.Current.ShowOfflineUsersSeparately ? "Online/Paused" : "Contacts", TagHandler.CustomOnlineTag => _mareConfig.Current.ShowOfflineUsersSeparately ? "Online" : "Contacts",
TagHandler.CustomPausedTag => "Paused",
TagHandler.CustomVisibleTag => "Visible", TagHandler.CustomVisibleTag => "Visible",
_ => tag _ => tag
}; };
string resultFolderName = !isSpecialTag ? $"{displayedName} ({visible}/{online}/{total} Pairs)" : $"{displayedName} ({online} Pairs)"; string resultFolderName = !isSpecialTag ? $"{displayedName} ({visible}/{online}/{paused}/{total} Pairs)" : $"{displayedName} ({online} Pairs)";
// FontAwesomeIcon.CaretSquareDown : FontAwesomeIcon.CaretSquareRight // FontAwesomeIcon.CaretSquareDown : FontAwesomeIcon.CaretSquareRight
var icon = _tagHandler.IsTagOpen(tag) ? FontAwesomeIcon.CaretSquareDown : FontAwesomeIcon.CaretSquareRight; var icon = _tagHandler.IsTagOpen(tag) ? FontAwesomeIcon.CaretSquareDown : FontAwesomeIcon.CaretSquareRight;
@@ -184,7 +190,8 @@ public class PairGroupsUi
ImGui.TextUnformatted($"Group {tag}"); ImGui.TextUnformatted($"Group {tag}");
ImGui.Separator(); ImGui.Separator();
ImGui.TextUnformatted($"{visible} Pairs visible"); ImGui.TextUnformatted($"{visible} Pairs visible");
ImGui.TextUnformatted($"{online} Pairs online/paused"); ImGui.TextUnformatted($"{online} Pairs online");
ImGui.TextUnformatted($"{paused} Pairs paused");
ImGui.TextUnformatted($"{total} Pairs total"); ImGui.TextUnformatted($"{total} Pairs total");
ImGui.EndTooltip(); ImGui.EndTooltip();
} }
@@ -197,39 +204,45 @@ public class PairGroupsUi
ImGui.Separator(); ImGui.Separator();
} }
private void DrawUserPairs(List<string> tagsWithPairsInThem, List<DrawUserPair> allUsers, IEnumerable<DrawUserPair> visibleUsers, IEnumerable<DrawUserPair> onlineUsers, IEnumerable<DrawUserPair> offlineUsers) private void DrawUserPairs(List<string> tagsWithPairsInThem, List<DrawUserPair> allUsers, IEnumerable<DrawUserPair> visibleUsers, IEnumerable<DrawUserPair> onlineUsers, IEnumerable<DrawUserPair> pausedUsers, IEnumerable<DrawUserPair> offlineUsers)
{ {
if (_mareConfig.Current.ShowVisibleUsersSeparately) if (_mareConfig.Current.ShowVisibleUsersSeparately)
{ {
using (ImRaii.PushId("$group-VisibleCustomTag")) DrawCategory(TagHandler.CustomVisibleTag, visibleUsers, allUsers); using (ImRaii.PushId("$group-VisibleCustomTag")) DrawCategory(TagHandler.CustomVisibleTag, visibleUsers, Enumerable.Empty<DrawUserPair>(), allUsers);
} }
foreach (var tag in tagsWithPairsInThem) foreach (var tag in tagsWithPairsInThem)
{ {
if (_mareConfig.Current.ShowOfflineUsersSeparately) if (_mareConfig.Current.ShowOfflineUsersSeparately)
{ {
using (ImRaii.PushId($"group-{tag}")) DrawCategory(tag, onlineUsers, allUsers, visibleUsers); using (ImRaii.PushId($"group-{tag}")) DrawCategory(tag, onlineUsers, pausedUsers, allUsers, visibleUsers);
} }
else else
{ {
using (ImRaii.PushId($"group-{tag}")) DrawCategory(tag, allUsers, allUsers, visibleUsers); using (ImRaii.PushId($"group-{tag}")) DrawCategory(tag, allUsers, Enumerable.Empty<DrawUserPair>(), allUsers, visibleUsers);
} }
} }
if (_mareConfig.Current.ShowOfflineUsersSeparately) if (_mareConfig.Current.ShowOfflineUsersSeparately)
{ {
using (ImRaii.PushId($"group-OnlineCustomTag")) DrawCategory(TagHandler.CustomOnlineTag, using (ImRaii.PushId($"group-OnlineCustomTag")) DrawCategory(TagHandler.CustomOnlineTag,
onlineUsers.Where(u => !_tagHandler.HasAnyTag(u.UID)).ToList(), allUsers); onlineUsers.Where(u => !_tagHandler.HasAnyTag(u.UID)).ToList(), Enumerable.Empty<DrawUserPair>(), allUsers);
if (pausedUsers.Any()) using (ImRaii.PushId("group-PausedCustomTag")) DrawCategory(TagHandler.CustomPausedTag,
Enumerable.Empty<DrawUserPair>(), pausedUsers, allUsers);
using (ImRaii.PushId($"group-OfflineCustomTag")) DrawCategory(TagHandler.CustomOfflineTag, using (ImRaii.PushId($"group-OfflineCustomTag")) DrawCategory(TagHandler.CustomOfflineTag,
offlineUsers.Where(u => u.UserPair!.OtherPermissions.IsPaired()).ToList(), allUsers); offlineUsers.Where(u => u.UserPair!.OtherPermissions.IsPaired()).ToList(), Enumerable.Empty<DrawUserPair>(), allUsers);
} }
else else
{ {
using (ImRaii.PushId($"group-OnlineCustomTag")) DrawCategory(TagHandler.CustomOnlineTag, using (ImRaii.PushId($"group-OnlineCustomTag")) DrawCategory(TagHandler.CustomOnlineTag,
onlineUsers.Concat(offlineUsers.Where(u => u.UserPair!.OtherPermissions.IsPaired())).Where(u => !_tagHandler.HasAnyTag(u.UID)).ToList(), allUsers); onlineUsers.Concat(offlineUsers.Where(u => u.UserPair!.OtherPermissions.IsPaired())).Where(u => !_tagHandler.HasAnyTag(u.UID)).ToList(), Enumerable.Empty<DrawUserPair>(), allUsers);
} }
using (ImRaii.PushId($"group-UnpairedCustomTag")) DrawCategory(TagHandler.CustomUnpairedTag, using (ImRaii.PushId($"group-UnpairedCustomTag")) DrawCategory(TagHandler.CustomUnpairedTag,
offlineUsers.Where(u => !u.UserPair!.OtherPermissions.IsPaired()).ToList(), allUsers); offlineUsers.Where(u => !u.UserPair!.OtherPermissions.IsPaired()).ToList(), Enumerable.Empty<DrawUserPair>(), allUsers);
} }
private void PauseRemainingPairs(List<DrawUserPair> availablePairs) private void PauseRemainingPairs(List<DrawUserPair> availablePairs)
{ {
foreach (var pairToPause in availablePairs.Where(pair => !pair.UserPair!.OwnPermissions.IsPaused())) foreach (var pairToPause in availablePairs.Where(pair => !pair.UserPair!.OwnPermissions.IsPaused()))

View File

@@ -203,10 +203,10 @@ public sealed class DtrEntry : IDisposable, IHostedService
DtrStyle.Style4 => $"\xE03A {text}", DtrStyle.Style4 => $"\xE03A {text}",
DtrStyle.Style5 => $"\xE033 {text}", DtrStyle.Style5 => $"\xE033 {text}",
DtrStyle.Style6 => $"\xE038 {text}", DtrStyle.Style6 => $"\xE038 {text}",
DtrStyle.Style7 => $"\xE05D {text}", DtrStyle.Style7 => $"\xE044 {text}",
DtrStyle.Style8 => $"\xE03C{text}", DtrStyle.Style8 => $"\xE03C{text}",
DtrStyle.Style9 => $"\xE040 {text} \xE041", DtrStyle.Style9 => $"\xE040 {text} \xE041",
_ => $"\uE044 {text}" _ => $"\uE05D {text}"
}; };
} }

View File

@@ -9,6 +9,7 @@ public class TagHandler
public const string CustomOnlineTag = "Mare_Online"; public const string CustomOnlineTag = "Mare_Online";
public const string CustomUnpairedTag = "Mare_Unpaired"; public const string CustomUnpairedTag = "Mare_Unpaired";
public const string CustomVisibleTag = "Mare_Visible"; public const string CustomVisibleTag = "Mare_Visible";
public const string CustomPausedTag = "Mare_Paused";
private readonly ServerConfigurationManager _serverConfigurationManager; private readonly ServerConfigurationManager _serverConfigurationManager;
public TagHandler(ServerConfigurationManager serverConfigurationManager) public TagHandler(ServerConfigurationManager serverConfigurationManager)

View File

@@ -956,6 +956,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
_uiShared.BigText("UI"); _uiShared.BigText("UI");
var showCharacterNames = _configService.Current.ShowCharacterNames; var showCharacterNames = _configService.Current.ShowCharacterNames;
var showVisibleSeparate = _configService.Current.ShowVisibleUsersSeparately; var showVisibleSeparate = _configService.Current.ShowVisibleUsersSeparately;
var sortSyncshellByVRAM = _configService.Current.SortSyncshellsByVRAM;
var showOfflineSeparate = _configService.Current.ShowOfflineUsersSeparately; var showOfflineSeparate = _configService.Current.ShowOfflineUsersSeparately;
var showProfiles = _configService.Current.ProfilesShow; var showProfiles = _configService.Current.ProfilesShow;
var showNsfwProfiles = _configService.Current.ProfilesAllowNsfw; var showNsfwProfiles = _configService.Current.ProfilesAllowNsfw;
@@ -1074,13 +1075,20 @@ public class SettingsUi : WindowMediatorSubscriberBase
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("This will show all currently visible users in a special 'Visible' group in the main UI."); _uiShared.DrawHelpText("This will show all currently visible users in a special 'Visible' group in the main UI.");
if (ImGui.Checkbox("Sort visible syncshell users by VRAM usage", ref sortSyncshellByVRAM))
{
_configService.Current.SortSyncshellsByVRAM = sortSyncshellByVRAM;
_logger.LogWarning("Changing value: {sortSyncshellsByVRAM}", sortSyncshellByVRAM);
if (ImGui.Checkbox("Show separate Offline group", ref showOfflineSeparate)) _configService.Save();
}
_uiShared.DrawHelpText("This will put users using the most VRAM in a syncshell at the top of the list.");
if (ImGui.Checkbox("Group users by connection status", ref showOfflineSeparate))
{ {
_configService.Current.ShowOfflineUsersSeparately = showOfflineSeparate; _configService.Current.ShowOfflineUsersSeparately = showOfflineSeparate;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("This will show all currently offline users in a special 'Offline' group in the main UI."); _uiShared.DrawHelpText("This will categorize users by their connection status in the main UI.");
if (ImGui.Checkbox("Show player names", ref showCharacterNames)) if (ImGui.Checkbox("Show player names", ref showCharacterNames))
{ {

View File

@@ -183,10 +183,12 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM
_connectionDto = await GetConnectionDto().ConfigureAwait(false); _connectionDto = await GetConnectionDto().ConfigureAwait(false);
await CheckClientHealth().ConfigureAwait(false);
ServerState = ServerState.Connected; ServerState = ServerState.Connected;
var currentClientVer = Assembly.GetExecutingAssembly().GetName().Version!; var currentClientVer = Assembly.GetExecutingAssembly().GetName().Version!;
if (_connectionDto.ServerVersion != IMareHub.ApiVersion) if (_connectionDto.ServerVersion != IMareHub.ApiVersion)
{ {
if (_connectionDto.CurrentClientVersion > currentClientVer) if (_connectionDto.CurrentClientVersion > currentClientVer)
@@ -308,14 +310,18 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM
_ = Task.Run(async () => await StopConnection(ServerState.Disconnected).ConfigureAwait(false)); _ = Task.Run(async () => await StopConnection(ServerState.Disconnected).ConfigureAwait(false));
_connectionCancellationTokenSource?.Cancel(); _connectionCancellationTokenSource?.Cancel();
} }
private async Task ClientHealthCheck(CancellationToken ct) private async Task ClientHealthCheck(CancellationToken ct)
{ {
while (!ct.IsCancellationRequested && _mareHub != null) while (!ct.IsCancellationRequested && _mareHub != null)
{ {
await Task.Delay(TimeSpan.FromSeconds(30), ct).ConfigureAwait(false); await Task.Delay(TimeSpan.FromSeconds(30), ct).ConfigureAwait(false);
Logger.LogDebug("Checking Client Health State"); var healthy = await CheckClientHealth().ConfigureAwait(false);
_ = await CheckClientHealth().ConfigureAwait(false); if (!healthy || _mareHub.State != HubConnectionState.Connected)
{
Logger.LogWarning("Health check failed, forcing reconnect. ClientHealth: {0} HubConnected: {1}", healthy, _mareHub.State != HubConnectionState.Connected);
await ForceResetConnection().ConfigureAwait(false);
}
} }
} }
@@ -391,7 +397,7 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM
{ {
var users = await GroupsGetUsersInGroup(group).ConfigureAwait(false); var users = await GroupsGetUsersInGroup(group).ConfigureAwait(false);
foreach (var user in users) foreach (var user in users)
{ {
Logger.LogDebug("Group Pair: {user}", user); Logger.LogDebug("Group Pair: {user}", user);
_pairManager.AddGroupPair(user); _pairManager.AddGroupPair(user);
} }
@@ -478,5 +484,30 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM
ServerState = state; ServerState = state;
} }
//Because this plugin really likes to bug out with connections, lets "fix" it....
public async Task ForceResetConnection()
{
if (!_initialized) return;
Logger.LogInformation("ForceReconnect called");
try
{
await StopConnection(ServerState.Disconnected).ConfigureAwait(false);
// Cancel any ongoing health checks to prevent conflicts
_healthCheckTokenSource?.Cancel();
_healthCheckTokenSource?.Dispose();
_healthCheckTokenSource = null;
await CreateConnections().ConfigureAwait(false);
Logger.LogInformation("ForceReconnect completed successfully");
}
catch (Exception ex)
{
Logger.LogError(ex, "Failure during ForceReconnect, disconnecting");
await StopConnection(ServerState.Disconnected).ConfigureAwait(false);
}
}
} }
#pragma warning restore MA0040 #pragma warning restore MA0040

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View File

@@ -10,9 +10,9 @@
}, },
"DalamudPackager": { "DalamudPackager": {
"type": "Direct", "type": "Direct",
"requested": "[13.0.0, )", "requested": "[13.1.0, )",
"resolved": "13.0.0", "resolved": "13.1.0",
"contentHash": "Mb3cUDSK/vDPQ8gQIeuCw03EMYrej1B4J44a1AvIJ9C759p9XeqdU9Hg4WgOmlnlPe0G7ILTD32PKSUpkQNa8w==" "contentHash": "XdoNhJGyFby5M/sdcRhnc5xTop9PHy+H50PTWpzLhJugjB19EDBiHD/AsiDF66RETM+0qKUdJBZrNuebn7qswQ=="
}, },
"DotNet.ReproducibleBuilds": { "DotNet.ReproducibleBuilds": {
"type": "Direct", "type": "Direct",
@@ -22,11 +22,11 @@
}, },
"Downloader": { "Downloader": {
"type": "Direct", "type": "Direct",
"requested": "[3.3.4, )", "requested": "[4.0.3, )",
"resolved": "3.3.4", "resolved": "4.0.3",
"contentHash": "/M/c80e1L0WW1XrLSSiQhgFxk8rrfbpWiWDn2CeBg1tPD393Neo+v184yG/ThyhE9rrNp36yCrugiCmEbRf+VQ==", "contentHash": "Vg1+UqPDstpMw2CKXV9XvB8jKHC95KQfbqPxQXvOMRMFnTov4Ixvvw6GZV5DXLnKuL2sfnmVYX9CaQtcURia1Q==",
"dependencies": { "dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "8.0.1" "Microsoft.Extensions.Logging.Abstractions": "8.0.3"
} }
}, },
"Glamourer.Api": { "Glamourer.Api": {
@@ -55,11 +55,28 @@
"System.IO.Pipelines": "6.0.3" "System.IO.Pipelines": "6.0.3"
} }
}, },
"MessagePack": {
"type": "Direct",
"requested": "[3.1.4, )",
"resolved": "3.1.4",
"contentHash": "BH0wlHWmVoZpbAPyyt2Awbq30C+ZsS3eHSkYdnyUAbqVJ22fAJDzn2xTieBeoT5QlcBzp61vHcv878YJGfi3mg==",
"dependencies": {
"MessagePack.Annotations": "3.1.4",
"MessagePackAnalyzer": "3.1.4",
"Microsoft.NET.StringTools": "17.11.4"
}
},
"MessagePack.Annotations": {
"type": "Direct",
"requested": "[3.1.4, )",
"resolved": "3.1.4",
"contentHash": "aVWrDAkCdqxwQsz/q0ldPh2EFn48M99YUzE9OvZjMq2RNLKz4o2z88iGFvSvbMqOWRweRvKPHBJZe22PRqzslQ=="
},
"Meziantou.Analyzer": { "Meziantou.Analyzer": {
"type": "Direct", "type": "Direct",
"requested": "[2.0.212, )", "requested": "[2.0.213, )",
"resolved": "2.0.212", "resolved": "2.0.213",
"contentHash": "U91ktjjTRTccUs3Lk+hrLD9vW+2+lhnsOf4G1GpRSJi1pLn3uK5CU6wGP9Bmz1KlJs6Oz1GGoMhxQBoqQsmAuQ==" "contentHash": "LHnFGBqhlBjbf8Uo4OIzGM0llRxFrIMuo/hP9oHq+aldS+28G4LqG12LK0co9b+S0yj1Vbf0rclDHN0Ji2DTkA=="
}, },
"Microsoft.AspNetCore.SignalR.Client": { "Microsoft.AspNetCore.SignalR.Client": {
"type": "Direct", "type": "Direct",
@@ -133,6 +150,12 @@
"Microsoft.IdentityModel.Tokens": "8.14.0" "Microsoft.IdentityModel.Tokens": "8.14.0"
} }
}, },
"System.IO.Pipelines": {
"type": "Direct",
"requested": "[9.0.8, )",
"resolved": "9.0.8",
"contentHash": "6vPmJt73mgUo1gzc/OcXlJvClz/2jxZ4TQPRfriVaLoGRH2mye530D9WHJYbFQRNMxF3PWCoeofsFdCyN7fLzA=="
},
"K4os.Compression.LZ4": { "K4os.Compression.LZ4": {
"type": "Transitive", "type": "Transitive",
"resolved": "1.3.8", "resolved": "1.3.8",
@@ -143,19 +166,10 @@
"resolved": "1.0.8", "resolved": "1.0.8",
"contentHash": "Wp2F7BamQ2Q/7Hk834nV9vRQapgcr8kgv9Jvfm8J3D0IhDqZMMl+a2yxUq5ltJitvXvQfB8W6K4F4fCbw/P6YQ==" "contentHash": "Wp2F7BamQ2Q/7Hk834nV9vRQapgcr8kgv9Jvfm8J3D0IhDqZMMl+a2yxUq5ltJitvXvQfB8W6K4F4fCbw/P6YQ=="
}, },
"MessagePack": { "MessagePackAnalyzer": {
"type": "Transitive", "type": "Transitive",
"resolved": "2.5.187", "resolved": "3.1.4",
"contentHash": "uW4j8m4Nc+2Mk5n6arOChavJ9bLjkis0qWASOj2h2OwmfINuzYv+mjCHUymrYhmyyKTu3N+ObtTXAY4uQ7jIhg==", "contentHash": "CTaSsN/liJ7MhLCAB7Z4ZLBNuVGCq9lt2BT/cbrc9vzGv89yK3CqIA+z9T19a11eQYl9etZHL6MQJgCqECRVpg=="
"dependencies": {
"MessagePack.Annotations": "2.5.187",
"Microsoft.NET.StringTools": "17.6.3"
}
},
"MessagePack.Annotations": {
"type": "Transitive",
"resolved": "2.5.198",
"contentHash": "3U9OvqQGTra+Mz1k1zfNAScSdNHobnqtQ51qdMGUZppkNDZJl0X/igq6Qz5zDBLEZoYqZrFtZwFx6wBJHHI8BA=="
}, },
"Microsoft.AspNetCore.Connections.Abstractions": { "Microsoft.AspNetCore.Connections.Abstractions": {
"type": "Transitive", "type": "Transitive",
@@ -499,19 +513,14 @@
}, },
"Microsoft.NET.StringTools": { "Microsoft.NET.StringTools": {
"type": "Transitive", "type": "Transitive",
"resolved": "17.6.3", "resolved": "17.11.4",
"contentHash": "N0ZIanl1QCgvUumEL1laasU0a7sOE5ZwLZVTn0pAePnfhq8P7SvTjF8Axq+CnavuQkmdQpGNXQ1efZtu5kDFbA==" "contentHash": "mudqUHhNpeqIdJoUx2YDWZO/I9uEDYVowan89R6wsomfnUJQk6HteoQTlNjZDixhT2B4IXMkMtgZtoceIjLRmA=="
}, },
"System.Diagnostics.EventLog": { "System.Diagnostics.EventLog": {
"type": "Transitive", "type": "Transitive",
"resolved": "9.0.8", "resolved": "9.0.8",
"contentHash": "gebRF3JLLJ76jz1CQpvwezNapZUjFq20JQsaGHzBH0DzlkHBLpdhwkOei9usiOkIGMwU/L0ALWpNe1JE+5/itw==" "contentHash": "gebRF3JLLJ76jz1CQpvwezNapZUjFq20JQsaGHzBH0DzlkHBLpdhwkOei9usiOkIGMwU/L0ALWpNe1JE+5/itw=="
}, },
"System.IO.Pipelines": {
"type": "Transitive",
"resolved": "6.0.3",
"contentHash": "ryTgF+iFkpGZY1vRQhfCzX0xTdlV3pyaTTqRu2ETbEv+HlV7O6y7hyQURnghNIXvctl5DuZ//Dpks6HdL/Txgw=="
},
"System.Net.ServerSentEvents": { "System.Net.ServerSentEvents": {
"type": "Transitive", "type": "Transitive",
"resolved": "9.0.8", "resolved": "9.0.8",
@@ -525,8 +534,11 @@
"maresynchronos.api": { "maresynchronos.api": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"MessagePack.Annotations": "[2.5.198, )" "MessagePack.Annotations": "[2.5.129, )"
} }
},
"snowcloaksync": {
"type": "Project"
} }
} }
} }

View File

@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,9 @@
using System.Numerics;
namespace SnowcloakSync.Utils
{
public static class Colours
{
public static readonly Vector4 _snowcloakOnline = new(0.4275f, 0.6863f, 1f, 1f);
}
}