Merge branch '1.12.0' into dev
This commit is contained in:
140
.github/workflows/lightless-tag-and-release.yml
vendored
140
.github/workflows/lightless-tag-and-release.yml
vendored
@@ -1,140 +0,0 @@
|
|||||||
name: Tag and Release Lightless
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
|
|
||||||
env:
|
|
||||||
PLUGIN_NAME: LightlessSync
|
|
||||||
DOTNET_VERSION: 9.x
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
tag-and-release:
|
|
||||||
runs-on: windows-2022
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout Lightless
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
submodules: true
|
|
||||||
|
|
||||||
- name: Setup .NET 9 SDK
|
|
||||||
uses: actions/setup-dotnet@v4
|
|
||||||
with:
|
|
||||||
dotnet-version: 9.x
|
|
||||||
|
|
||||||
- name: Download Dalamud
|
|
||||||
run: |
|
|
||||||
Invoke-WebRequest -Uri https://goatcorp.github.io/dalamud-distrib/stg/latest.zip -OutFile latest.zip
|
|
||||||
Expand-Archive -Force latest.zip "$env:AppData\XIVLauncher\addon\Hooks\dev"
|
|
||||||
|
|
||||||
- name: Lets Build Lightless!
|
|
||||||
run: |
|
|
||||||
dotnet restore
|
|
||||||
dotnet build --configuration Release --no-restore
|
|
||||||
dotnet publish --configuration Release --no-build
|
|
||||||
|
|
||||||
- name: Get version
|
|
||||||
id: package_version
|
|
||||||
uses: KageKirin/get-csproj-version@v0
|
|
||||||
with:
|
|
||||||
file: LightlessSync/LightlessSync.csproj
|
|
||||||
|
|
||||||
- name: Display version
|
|
||||||
run: |
|
|
||||||
echo "Version: ${{ steps.package_version.outputs.version }}"
|
|
||||||
|
|
||||||
- name: Prepare Lightless Client
|
|
||||||
run: |
|
|
||||||
$publishPath = "${{ env.PLUGIN_NAME }}/bin/x64/Release/publish"
|
|
||||||
if (Test-Path $publishPath) {
|
|
||||||
Remove-Item -Recurse -Force $publishPath
|
|
||||||
Write-Host "Removed $publishPath"
|
|
||||||
} else {
|
|
||||||
Write-Host "$publishPath does not exist, nothing to remove."
|
|
||||||
}
|
|
||||||
mkdir output
|
|
||||||
Compress-Archive -Path ${{ env.PLUGIN_NAME }}/bin/x64/Release/* -DestinationPath output/LightlessClient.zip
|
|
||||||
|
|
||||||
- name: Create Git tag if not exists
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
$tag = "${{ steps.package_version.outputs.version }}"
|
|
||||||
git fetch --tags
|
|
||||||
if (-not (git tag -l $tag)) {
|
|
||||||
Write-Host "Tag $tag does not exist. Creating and pushing..."
|
|
||||||
git config user.name "GitHub Action"
|
|
||||||
git config user.email "action@github.com"
|
|
||||||
git tag $tag
|
|
||||||
git push origin $tag
|
|
||||||
} else {
|
|
||||||
Write-Host "Tag $tag already exists. Skipping tag creation."
|
|
||||||
}
|
|
||||||
|
|
||||||
- name: Create GitHub Release
|
|
||||||
uses: softprops/action-gh-release@v2
|
|
||||||
with:
|
|
||||||
tag_name: ${{ steps.package_version.outputs.version }}
|
|
||||||
name: ${{ steps.package_version.outputs.version }}
|
|
||||||
draft: false
|
|
||||||
prerelease: false
|
|
||||||
files: output/LightlessClient.zip
|
|
||||||
|
|
||||||
- name: Clone plugin hosting repo
|
|
||||||
run: |
|
|
||||||
mkdir LightlessSyncRepo
|
|
||||||
cd LightlessSyncRepo
|
|
||||||
git clone https://github.com/${{ github.repository_owner }}/LightlessSync.git
|
|
||||||
env:
|
|
||||||
GIT_TERMINAL_PROMPT: 0
|
|
||||||
|
|
||||||
- name: Update plogonmaster.json with version
|
|
||||||
shell: pwsh
|
|
||||||
env:
|
|
||||||
VERSION: ${{ steps.package_version.outputs.version }}
|
|
||||||
run: |
|
|
||||||
$pluginJsonPath = "${{ env.PLUGIN_NAME }}/bin/x64/Release/${{ env.PLUGIN_NAME }}.json"
|
|
||||||
$pluginJson = Get-Content $pluginJsonPath | ConvertFrom-Json
|
|
||||||
$repoJsonPath = "LightlessSyncRepo/LightlessSync/plogonmaster.json"
|
|
||||||
$repoJsonRaw = Get-Content $repoJsonPath -Raw
|
|
||||||
$repoJson = $repoJsonRaw | ConvertFrom-Json
|
|
||||||
$version = $env:VERSION
|
|
||||||
$downloadUrl = "https://github.com/${{ github.repository_owner }}/LightlessClient/releases/download/$version/LightlessClient.zip"
|
|
||||||
|
|
||||||
if (-not ($repoJson -is [System.Collections.IEnumerable])) {
|
|
||||||
$repoJson = @($repoJson)
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($plugin in $repoJson) {
|
|
||||||
if ($plugin.InternalName -eq $pluginJson.InternalName) {
|
|
||||||
$plugin.DalamudApiLevel = $pluginJson.DalamudApiLevel
|
|
||||||
$plugin.AssemblyVersion = $version
|
|
||||||
$plugin.DownloadLinkInstall = $downloadUrl
|
|
||||||
$plugin.DownloadLinkTesting = $downloadUrl
|
|
||||||
$plugin.DownloadLinkUpdate = $downloadUrl
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$repoJson | ConvertTo-Json -Depth 100 | Set-Content $repoJsonPath
|
|
||||||
|
|
||||||
# Convert to JSON and force array brackets if necessary
|
|
||||||
$repoJsonString = $repoJson | ConvertTo-Json -Depth 100
|
|
||||||
|
|
||||||
# If the output is not an array, wrap it manually
|
|
||||||
if ($repoJsonString.Trim().StartsWith('{')) {
|
|
||||||
$repoJsonString = "[$repoJsonString]"
|
|
||||||
}
|
|
||||||
|
|
||||||
$repoJsonString | Set-Content $repoJsonPath
|
|
||||||
|
|
||||||
- name: Commit and push to LightlessSync
|
|
||||||
run: |
|
|
||||||
cd LightlessSyncRepo/LightlessSync
|
|
||||||
git config user.name "github-actions"
|
|
||||||
git config user.email "github-actions@github.com"
|
|
||||||
git add .
|
|
||||||
git commit -m "Update ${{ env.PLUGIN_NAME }} to ${{ steps.package_version.outputs.version }}"
|
|
||||||
git push https://x-access-token:${{ secrets.LIGHTLESS_TOKEN }}@github.com/${{ github.repository_owner }}/LightlessSync.git HEAD:main
|
|
||||||
@@ -67,6 +67,7 @@ public class LightlessConfig : ILightlessConfiguration
|
|||||||
public bool UseFocusTarget { get; set; } = false;
|
public bool UseFocusTarget { get; set; } = false;
|
||||||
public bool overrideFriendColor { get; set; } = false;
|
public bool overrideFriendColor { get; set; } = false;
|
||||||
public bool overridePartyColor { get; set; } = false;
|
public bool overridePartyColor { get; set; } = false;
|
||||||
|
public bool useColoredUIDs { get; set; } = true;
|
||||||
public bool BroadcastEnabled { get; set; } = false;
|
public bool BroadcastEnabled { get; set; } = false;
|
||||||
public DateTime BroadcastTtl { get; set; } = DateTime.MinValue;
|
public DateTime BroadcastTtl { get; set; } = DateTime.MinValue;
|
||||||
public bool SyncshellFinderEnabled { get; set; } = false;
|
public bool SyncshellFinderEnabled { get; set; } = false;
|
||||||
|
|||||||
@@ -147,7 +147,9 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
collection.AddSingleton<RedrawManager>();
|
collection.AddSingleton<RedrawManager>();
|
||||||
collection.AddSingleton<BroadcastService>();
|
collection.AddSingleton<BroadcastService>();
|
||||||
collection.AddSingleton(addonLifecycle);
|
collection.AddSingleton(addonLifecycle);
|
||||||
collection.AddSingleton(p => new ContextMenu(contextMenu, pluginInterface, gameData, p.GetRequiredService<ILogger<ContextMenu>>(), p.GetRequiredService<DalamudUtilService>(), p.GetRequiredService<ApiController>(), objectTable, p.GetRequiredService<LightlessConfigService>()));
|
collection.AddSingleton(p => new ContextMenuService(contextMenu, pluginInterface, gameData,
|
||||||
|
p.GetRequiredService<ILogger<ContextMenuService>>(), p.GetRequiredService<DalamudUtilService>(), p.GetRequiredService<ApiController>(), objectTable,
|
||||||
|
p.GetRequiredService<LightlessConfigService>(), p.GetRequiredService<PairManager>(), clientState));
|
||||||
collection.AddSingleton((s) => new IpcCallerPenumbra(s.GetRequiredService<ILogger<IpcCallerPenumbra>>(), pluginInterface,
|
collection.AddSingleton((s) => new IpcCallerPenumbra(s.GetRequiredService<ILogger<IpcCallerPenumbra>>(), pluginInterface,
|
||||||
s.GetRequiredService<DalamudUtilService>(), s.GetRequiredService<LightlessMediator>(), s.GetRequiredService<RedrawManager>()));
|
s.GetRequiredService<DalamudUtilService>(), s.GetRequiredService<LightlessMediator>(), s.GetRequiredService<RedrawManager>()));
|
||||||
collection.AddSingleton((s) => new IpcCallerGlamourer(s.GetRequiredService<ILogger<IpcCallerGlamourer>>(), pluginInterface,
|
collection.AddSingleton((s) => new IpcCallerGlamourer(s.GetRequiredService<ILogger<IpcCallerGlamourer>>(), pluginInterface,
|
||||||
@@ -261,7 +263,7 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
collection.AddHostedService(p => p.GetRequiredService<EventAggregator>());
|
collection.AddHostedService(p => p.GetRequiredService<EventAggregator>());
|
||||||
collection.AddHostedService(p => p.GetRequiredService<IpcProvider>());
|
collection.AddHostedService(p => p.GetRequiredService<IpcProvider>());
|
||||||
collection.AddHostedService(p => p.GetRequiredService<LightlessPlugin>());
|
collection.AddHostedService(p => p.GetRequiredService<LightlessPlugin>());
|
||||||
collection.AddHostedService(p => p.GetRequiredService<ContextMenu>());
|
collection.AddHostedService(p => p.GetRequiredService<ContextMenuService>());
|
||||||
collection.AddHostedService(p => p.GetRequiredService<BroadcastService>());
|
collection.AddHostedService(p => p.GetRequiredService<BroadcastService>());
|
||||||
})
|
})
|
||||||
.Build();
|
.Build();
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ public class BroadcastService : IHostedService, IMediatorSubscriber
|
|||||||
|
|
||||||
await _apiController.SetBroadcastStatus(msg.HashedCid, msg.Enabled, groupDto).ConfigureAwait(false);
|
await _apiController.SetBroadcastStatus(msg.HashedCid, msg.Enabled, groupDto).ConfigureAwait(false);
|
||||||
|
|
||||||
_logger.LogInformation("Broadcast {Status} for {Cid}", msg.Enabled ? "enabled" : "disabled", msg.HashedCid);
|
_logger.LogDebug("Broadcast {Status} for {Cid}", msg.Enabled ? "enabled" : "disabled", msg.HashedCid);
|
||||||
|
|
||||||
if (!msg.Enabled)
|
if (!msg.Enabled)
|
||||||
{
|
{
|
||||||
@@ -164,7 +164,7 @@ public class BroadcastService : IHostedService, IMediatorSubscriber
|
|||||||
_config.Current.BroadcastEnabled = true;
|
_config.Current.BroadcastEnabled = true;
|
||||||
_config.Save();
|
_config.Save();
|
||||||
|
|
||||||
_logger.LogInformation("Fetched TTL from server: {TTL}", remaining);
|
_logger.LogDebug("Fetched TTL from server: {TTL}", remaining);
|
||||||
_mediator.Publish(new BroadcastStatusChangedMessage(true, remaining));
|
_mediator.Publish(new BroadcastStatusChangedMessage(true, remaining));
|
||||||
Mediator.Publish(new EventMessage(new Services.Events.Event(nameof(BroadcastService), Services.Events.EventSeverity.Informational, $"Enabled Lightfinder for Player: {msg.HashedCid}")));
|
Mediator.Publish(new EventMessage(new Services.Events.Event(nameof(BroadcastService), Services.Events.EventSeverity.Informational, $"Enabled Lightfinder for Player: {msg.HashedCid}")));
|
||||||
}
|
}
|
||||||
@@ -201,13 +201,13 @@ public class BroadcastService : IHostedService, IMediatorSubscriber
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_logger.LogInformation("[BroadcastCheck] Checking CID: {cid}", targetCid);
|
_logger.LogDebug("[BroadcastCheck] Checking CID: {cid}", targetCid);
|
||||||
|
|
||||||
var info = await _apiController.IsUserBroadcasting(targetCid).ConfigureAwait(false);
|
var info = await _apiController.IsUserBroadcasting(targetCid).ConfigureAwait(false);
|
||||||
result = info?.TTL > TimeSpan.Zero;
|
result = info?.TTL > TimeSpan.Zero;
|
||||||
|
|
||||||
|
|
||||||
_logger.LogInformation("[BroadcastCheck] Result for {cid}: {result} (TTL: {ttl}, GID: {gid})", targetCid, result, info?.TTL, info?.GID);
|
_logger.LogDebug("[BroadcastCheck] Result for {cid}: {result} (TTL: {ttl}, GID: {gid})", targetCid, result, info?.TTL, info?.GID);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -251,7 +251,7 @@ public class BroadcastService : IHostedService, IMediatorSubscriber
|
|||||||
result[kv.Key] = kv.Value;
|
result[kv.Key] = kv.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation("Batch broadcast status check complete for {Count} CIDs", hashedCids.Count);
|
_logger.LogTrace("Batch broadcast status check complete for {Count} CIDs", hashedCids.Count);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -291,10 +291,10 @@ public class BroadcastService : IHostedService, IMediatorSubscriber
|
|||||||
if (!newStatus)
|
if (!newStatus)
|
||||||
{
|
{
|
||||||
_lastForcedDisableTime = DateTime.UtcNow;
|
_lastForcedDisableTime = DateTime.UtcNow;
|
||||||
_logger.LogInformation("Manual disable: cooldown timer started.");
|
_logger.LogDebug("Manual disable: cooldown timer started.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation("Toggling broadcast. Server currently broadcasting: {ServerStatus}, setting to: {NewStatus}", isCurrentlyBroadcasting, newStatus);
|
_logger.LogDebug("Toggling broadcast. Server currently broadcasting: {ServerStatus}, setting to: {NewStatus}", isCurrentlyBroadcasting, newStatus);
|
||||||
|
|
||||||
_mediator.Publish(new EnableBroadcastMessage(hashedCid, newStatus));
|
_mediator.Publish(new EnableBroadcastMessage(hashedCid, newStatus));
|
||||||
}
|
}
|
||||||
@@ -332,7 +332,7 @@ public class BroadcastService : IHostedService, IMediatorSubscriber
|
|||||||
_config.Current.BroadcastTtl = DateTime.UtcNow + remaining;
|
_config.Current.BroadcastTtl = DateTime.UtcNow + remaining;
|
||||||
_config.Current.BroadcastEnabled = true;
|
_config.Current.BroadcastEnabled = true;
|
||||||
_config.Save();
|
_config.Save();
|
||||||
_logger.LogInformation("Refreshed broadcast TTL from server on first OnTick: {TTL}", remaining);
|
_logger.LogDebug("Refreshed broadcast TTL from server on first OnTick: {TTL}", remaining);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -361,7 +361,7 @@ public class BroadcastService : IHostedService, IMediatorSubscriber
|
|||||||
_remainingTtl = remaining > TimeSpan.Zero ? remaining : null;
|
_remainingTtl = remaining > TimeSpan.Zero ? remaining : null;
|
||||||
if (_remainingTtl == null)
|
if (_remainingTtl == null)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Broadcast TTL expired. Disabling broadcast locally.");
|
_logger.LogDebug("Broadcast TTL expired. Disabling broadcast locally.");
|
||||||
_config.Current.BroadcastEnabled = false;
|
_config.Current.BroadcastEnabled = false;
|
||||||
_config.Current.BroadcastTtl = DateTime.MinValue;
|
_config.Current.BroadcastTtl = DateTime.MinValue;
|
||||||
_config.Save();
|
_config.Save();
|
||||||
|
|||||||
@@ -3,44 +3,47 @@ using Dalamud.Game.Gui.ContextMenu;
|
|||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using LightlessSync.LightlessConfiguration;
|
using LightlessSync.LightlessConfiguration;
|
||||||
using LightlessSync.Services;
|
using LightlessSync.PlayerData.Pairs;
|
||||||
using LightlessSync.Utils;
|
using LightlessSync.Utils;
|
||||||
using LightlessSync.WebAPI;
|
using LightlessSync.WebAPI;
|
||||||
using Lumina.Excel.Sheets;
|
using Lumina.Excel.Sheets;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace LightlessSync.UI;
|
namespace LightlessSync.Services;
|
||||||
|
|
||||||
internal class ContextMenu : IHostedService
|
internal class ContextMenuService : IHostedService
|
||||||
{
|
{
|
||||||
private readonly IContextMenu _contextMenu;
|
private readonly IContextMenu _contextMenu;
|
||||||
private readonly IDalamudPluginInterface _pluginInterface;
|
private readonly IDalamudPluginInterface _pluginInterface;
|
||||||
private readonly IDataManager _gameData;
|
private readonly IDataManager _gameData;
|
||||||
private readonly ILogger<ContextMenu> _logger;
|
private readonly ILogger<ContextMenuService> _logger;
|
||||||
private readonly DalamudUtilService _dalamudUtil;
|
private readonly DalamudUtilService _dalamudUtil;
|
||||||
private readonly LightlessConfigService _configService;
|
private readonly LightlessConfigService _configService;
|
||||||
|
private readonly IClientState _clientState;
|
||||||
|
private readonly PairManager _pairManager;
|
||||||
private readonly ApiController _apiController;
|
private readonly ApiController _apiController;
|
||||||
private readonly IObjectTable _objectTable;
|
private readonly IObjectTable _objectTable;
|
||||||
|
|
||||||
private static readonly string[] ValidAddons = new[]
|
private static readonly string[] _validAddons =
|
||||||
{
|
[
|
||||||
null,
|
null,
|
||||||
"PartyMemberList", "FriendList", "FreeCompany", "LinkShell", "CrossWorldLinkshell",
|
"PartyMemberList", "FriendList", "FreeCompany", "LinkShell", "CrossWorldLinkshell",
|
||||||
"_PartyList", "ChatLog", "LookingForGroup", "BlackList", "ContentMemberList",
|
"_PartyList", "ChatLog", "LookingForGroup", "BlackList", "ContentMemberList",
|
||||||
"SocialList", "ContactList", "BeginnerChatList", "MuteList"
|
"SocialList", "ContactList", "BeginnerChatList", "MuteList"
|
||||||
};
|
];
|
||||||
|
|
||||||
public ContextMenu(
|
public ContextMenuService(
|
||||||
IContextMenu contextMenu,
|
IContextMenu contextMenu,
|
||||||
IDalamudPluginInterface pluginInterface,
|
IDalamudPluginInterface pluginInterface,
|
||||||
IDataManager gameData,
|
IDataManager gameData,
|
||||||
ILogger<ContextMenu> logger,
|
ILogger<ContextMenuService> logger,
|
||||||
DalamudUtilService dalamudUtil,
|
DalamudUtilService dalamudUtil,
|
||||||
ApiController apiController,
|
ApiController apiController,
|
||||||
IObjectTable objectTable,
|
IObjectTable objectTable,
|
||||||
LightlessConfigService configService)
|
LightlessConfigService configService,
|
||||||
|
PairManager pairManager,
|
||||||
|
IClientState clientState)
|
||||||
{
|
{
|
||||||
_contextMenu = contextMenu;
|
_contextMenu = contextMenu;
|
||||||
_pluginInterface = pluginInterface;
|
_pluginInterface = pluginInterface;
|
||||||
@@ -50,6 +53,8 @@ internal class ContextMenu : IHostedService
|
|||||||
_apiController = apiController;
|
_apiController = apiController;
|
||||||
_objectTable = objectTable;
|
_objectTable = objectTable;
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
|
_pairManager = pairManager;
|
||||||
|
_clientState = clientState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
public Task StartAsync(CancellationToken cancellationToken)
|
||||||
@@ -81,19 +86,31 @@ internal class ContextMenu : IHostedService
|
|||||||
if (!_pluginInterface.UiBuilder.ShouldModifyUi)
|
if (!_pluginInterface.UiBuilder.ShouldModifyUi)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!ValidAddons.Contains(args.AddonName, StringComparer.Ordinal))
|
if (!_validAddons.Contains(args.AddonName, StringComparer.Ordinal))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
//Check if target is not menutargetdefault.
|
||||||
if (args.Target is not MenuTargetDefault target)
|
if (args.Target is not MenuTargetDefault target)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
//Check if name or target id isnt null/zero
|
||||||
if (string.IsNullOrEmpty(target.TargetName) || target.TargetObjectId == 0 || target.TargetHomeWorld.RowId == 0)
|
if (string.IsNullOrEmpty(target.TargetName) || target.TargetObjectId == 0 || target.TargetHomeWorld.RowId == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
//Check if it is a real target.
|
||||||
IPlayerCharacter? targetData = GetPlayerFromObjectTable(target);
|
IPlayerCharacter? targetData = GetPlayerFromObjectTable(target);
|
||||||
if (targetData == null || targetData.Address == IntPtr.Zero)
|
if (targetData == null || targetData.Address == nint.Zero)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
//Check if user is paired or is own.
|
||||||
|
if (VisibleUserIds.Any(u => u == target.TargetObjectId) || _clientState.LocalPlayer.GameObjectId == target.TargetObjectId)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//Check if in PVP or GPose
|
||||||
|
if (_clientState.IsPvPExcludingDen || _clientState.IsGPosing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//Check for valid world.
|
||||||
var world = GetWorld(target.TargetHomeWorld.RowId);
|
var world = GetWorld(target.TargetHomeWorld.RowId);
|
||||||
if (!IsWorldValid(world))
|
if (!IsWorldValid(world))
|
||||||
return;
|
return;
|
||||||
@@ -121,7 +138,7 @@ internal class ContextMenu : IHostedService
|
|||||||
{
|
{
|
||||||
IPlayerCharacter? targetData = GetPlayerFromObjectTable(target);
|
IPlayerCharacter? targetData = GetPlayerFromObjectTable(target);
|
||||||
|
|
||||||
if (targetData == null || targetData.Address == IntPtr.Zero)
|
if (targetData == null || targetData.Address == nint.Zero)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Target player {TargetName}@{World} not found in object table.", target.TargetName, world.Name);
|
_logger.LogWarning("Target player {TargetName}@{World} not found in object table.", target.TargetName, world.Name);
|
||||||
return;
|
return;
|
||||||
@@ -138,6 +155,9 @@ internal class ContextMenu : IHostedService
|
|||||||
_logger.LogError(ex, "Error sending pair request.");
|
_logger.LogError(ex, "Error sending pair request.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private HashSet<ulong> VisibleUserIds => [.. _pairManager.GetOnlineUserPairs()
|
||||||
|
.Where(u => u.IsVisible && u.PlayerCharacterId != uint.MaxValue)
|
||||||
|
.Select(u => (ulong)u.PlayerCharacterId)];
|
||||||
|
|
||||||
private IPlayerCharacter? GetPlayerFromObjectTable(MenuTargetDefault target)
|
private IPlayerCharacter? GetPlayerFromObjectTable(MenuTargetDefault target)
|
||||||
{
|
{
|
||||||
@@ -174,7 +194,7 @@ internal class ContextMenu : IHostedService
|
|||||||
|
|
||||||
private static bool IsChineseJapaneseKoreanString(string text) => text.All(IsChineseJapaneseKoreanCharacter);
|
private static bool IsChineseJapaneseKoreanString(string text) => text.All(IsChineseJapaneseKoreanCharacter);
|
||||||
|
|
||||||
private static bool IsChineseJapaneseKoreanCharacter(char c) => (c >= 0x4E00 && c <= 0x9FFF);
|
private static bool IsChineseJapaneseKoreanCharacter(char c) => c >= 0x4E00 && c <= 0x9FFF;
|
||||||
|
|
||||||
public bool IsWorldValid(uint worldId) => IsWorldValid(GetWorld(worldId));
|
public bool IsWorldValid(uint worldId) => IsWorldValid(GetWorld(worldId));
|
||||||
|
|
||||||
@@ -40,7 +40,6 @@ public class NameplateService : DisposableMediatorSubscriberBase
|
|||||||
|
|
||||||
private void OnNamePlateUpdate(INamePlateUpdateContext context, IReadOnlyList<INamePlateUpdateHandler> handlers)
|
private void OnNamePlateUpdate(INamePlateUpdateContext context, IReadOnlyList<INamePlateUpdateHandler> handlers)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!_configService.Current.IsNameplateColorsEnabled || (_configService.Current.IsNameplateColorsEnabled && _clientState.IsPvPExcludingDen))
|
if (!_configService.Current.IsNameplateColorsEnabled || (_configService.Current.IsNameplateColorsEnabled && _clientState.IsPvPExcludingDen))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -78,7 +77,6 @@ public class NameplateService : DisposableMediatorSubscriberBase
|
|||||||
|
|
||||||
public void RequestRedraw()
|
public void RequestRedraw()
|
||||||
{
|
{
|
||||||
|
|
||||||
_namePlateGui.RequestRedraw();
|
_namePlateGui.RequestRedraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
|
using Dalamud.Interface.Colors;
|
||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
using Dalamud.Utility;
|
using Dalamud.Utility;
|
||||||
using LightlessSync.API.Dto.Group;
|
using LightlessSync.API.Dto.Group;
|
||||||
using LightlessSync.LightlessConfiguration;
|
using LightlessSync.LightlessConfiguration;
|
||||||
using LightlessSync.Services;
|
using LightlessSync.Services;
|
||||||
using LightlessSync.Services.Mediator;
|
using LightlessSync.Services.Mediator;
|
||||||
|
using LightlessSync.Utils;
|
||||||
using LightlessSync.WebAPI;
|
using LightlessSync.WebAPI;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
@@ -44,8 +46,8 @@ namespace LightlessSync.UI
|
|||||||
IsOpen = false;
|
IsOpen = false;
|
||||||
this.SizeConstraints = new()
|
this.SizeConstraints = new()
|
||||||
{
|
{
|
||||||
MinimumSize = new(600, 340),
|
MinimumSize = new(600, 450),
|
||||||
MaximumSize = new(750, 400)
|
MaximumSize = new(750, 510)
|
||||||
};
|
};
|
||||||
|
|
||||||
mediator.Subscribe<RefreshUiMessage>(this, async _ => await RefreshSyncshells().ConfigureAwait(false));
|
mediator.Subscribe<RefreshUiMessage>(this, async _ => await RefreshSyncshells().ConfigureAwait(false));
|
||||||
@@ -137,19 +139,59 @@ namespace LightlessSync.UI
|
|||||||
{
|
{
|
||||||
_uiSharedService.MediumText("Lightfinder", UIColors.Get("PairBlue"));
|
_uiSharedService.MediumText("Lightfinder", UIColors.Get("PairBlue"));
|
||||||
|
|
||||||
ImGui.PushTextWrapPos();
|
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(1, -2));
|
||||||
ImGui.Text("This lets other Lightless users know you use Lightless.");
|
|
||||||
ImGui.Text("By enabling this, the server will allow other people to see that you are using Lightless.");
|
_uiSharedService.DrawNoteLine("# ", UIColors.Get("LightlessPurple"), "This lets other Lightless users know you use Lightless.");
|
||||||
ImGui.Text("When disabled, pairing is still possible but both parties need to mutually send each other requests, receiving party will not be notified about the request unless the pairing is complete.");
|
_uiSharedService.DrawNoteLine("# ", UIColors.Get("LightlessPurple"), "While enabled, you and other people using Lightfinder can see each other identified as Lightless users.");
|
||||||
ImGui.Text("At no point ever, even when Lightfinder is active that any Lightless data is getting sent to other people (including ID's), the server keeps this to itself.");
|
ImGui.Indent(5f);
|
||||||
ImGui.Text("You can request to pair by right-clicking any (not yourself) character and using 'Send Pair Request'.");
|
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey);
|
||||||
ImGui.PopTextWrapPos();
|
ImGui.Text("- This is done using a 'Lightless' label above player nameplates.");
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
ImGui.Unindent(5f);
|
||||||
|
|
||||||
|
ImGuiHelpers.ScaledDummy(3f);
|
||||||
|
|
||||||
|
_uiSharedService.MediumText("Pairing", UIColors.Get("PairBlue"));
|
||||||
|
_uiSharedService.DrawNoteLine("# ", UIColors.Get("LightlessPurple"), "Pairing may be initiated via the right-click context menu on another player." +
|
||||||
|
" The process requires mutual confirmation: the sender initiates the request, and the recipient completes it by responding with a request in return.");
|
||||||
|
|
||||||
|
_uiSharedService.DrawNoteLine(
|
||||||
|
"! ",
|
||||||
|
UIColors.Get("LightlessYellow"),
|
||||||
|
new SeStringUtils.RichTextEntry("If Lightfinder is "),
|
||||||
|
new SeStringUtils.RichTextEntry("ENABLED", UIColors.Get("LightlessGreen"), true),
|
||||||
|
new SeStringUtils.RichTextEntry(" when a pair request is made, the receiving user will get notified about it."));
|
||||||
|
|
||||||
|
_uiSharedService.DrawNoteLine(
|
||||||
|
"! ",
|
||||||
|
UIColors.Get("LightlessYellow"),
|
||||||
|
new SeStringUtils.RichTextEntry("If Lightfinder is "),
|
||||||
|
new SeStringUtils.RichTextEntry("DISABLED", UIColors.Get("DimRed"), true),
|
||||||
|
new SeStringUtils.RichTextEntry(" when a pair request is made, the receiving user will "),
|
||||||
|
new SeStringUtils.RichTextEntry("NOT", UIColors.Get("DimRed"), true),
|
||||||
|
new SeStringUtils.RichTextEntry(" get a notification, and the request will not be visible to them in any way."));
|
||||||
|
|
||||||
|
ImGuiHelpers.ScaledDummy(3f);
|
||||||
|
|
||||||
|
_uiSharedService.MediumText("Privacy", UIColors.Get("PairBlue"));
|
||||||
|
|
||||||
|
_uiSharedService.DrawNoteLine(
|
||||||
|
"! ",
|
||||||
|
UIColors.Get("DimRed"),
|
||||||
|
new SeStringUtils.RichTextEntry("Lightfinder is entirely "),
|
||||||
|
new SeStringUtils.RichTextEntry("opt-in", UIColors.Get("LightlessYellow"), true),
|
||||||
|
new SeStringUtils.RichTextEntry(" and does not share any data with other users. All identifying information remains private to the server."));
|
||||||
|
|
||||||
|
_uiSharedService.DrawNoteLine("! ", UIColors.Get("DimRed"), "Pairing is intended as a mutual agreement between both parties. A pair request will not be visible to the recipient unless Lightfinder is enabled.");
|
||||||
|
ImGuiHelpers.ScaledDummy(3f);
|
||||||
|
|
||||||
ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("DimRed"));
|
ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("DimRed"));
|
||||||
ImGui.Text("Use it only when you want to be visible.");
|
ImGui.Text("Use Lightfinder only when you want to be visible.");
|
||||||
ImGui.PopStyleColor();
|
ImGui.PopStyleColor();
|
||||||
|
|
||||||
ImGuiHelpers.ScaledDummy(0.2f);
|
ImGui.PopStyleVar();
|
||||||
|
|
||||||
|
ImGuiHelpers.ScaledDummy(2.2f);
|
||||||
_uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 2f);
|
_uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 2f);
|
||||||
|
|
||||||
if (_configService.Current.BroadcastEnabled)
|
if (_configService.Current.BroadcastEnabled)
|
||||||
@@ -168,7 +210,7 @@ namespace LightlessSync.UI
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("DimRed"));
|
ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("DimRed"));
|
||||||
ImGui.Text("The Lightfinder’s light wanes, but not in vain."); // cringe..
|
ImGui.Text("The Lightfinder<EFBFBD>s light wanes, but not in vain."); // cringe..
|
||||||
ImGui.PopStyleColor();
|
ImGui.PopStyleColor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,6 +109,21 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
AllowClickthrough = false;
|
AllowClickthrough = false;
|
||||||
TitleBarButtons = new()
|
TitleBarButtons = new()
|
||||||
{
|
{
|
||||||
|
new TitleBarButton()
|
||||||
|
{
|
||||||
|
Icon = FontAwesomeIcon.Cog,
|
||||||
|
Click = (msg) =>
|
||||||
|
{
|
||||||
|
Mediator.Publish(new UiToggleMessage(typeof(SettingsUi)));
|
||||||
|
},
|
||||||
|
IconOffset = new(2,1),
|
||||||
|
ShowTooltip = () =>
|
||||||
|
{
|
||||||
|
ImGui.BeginTooltip();
|
||||||
|
ImGui.Text("Open Lightless Settings");
|
||||||
|
ImGui.EndTooltip();
|
||||||
|
}
|
||||||
|
},
|
||||||
new TitleBarButton()
|
new TitleBarButton()
|
||||||
{
|
{
|
||||||
Icon = FontAwesomeIcon.Book,
|
Icon = FontAwesomeIcon.Book,
|
||||||
@@ -431,7 +446,7 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
float uidStartX = (contentWidth - uidTextSize.X) / 2f;
|
float uidStartX = (contentWidth - uidTextSize.X) / 2f;
|
||||||
float cursorY = ImGui.GetCursorPosY();
|
float cursorY = ImGui.GetCursorPosY();
|
||||||
|
|
||||||
if (_configService.Current.BroadcastEnabled)
|
if (_configService.Current.BroadcastEnabled && _apiController.IsConnected)
|
||||||
{
|
{
|
||||||
float iconYOffset = (uidTextSize.Y - iconSize.Y) * 0.5f;
|
float iconYOffset = (uidTextSize.Y - iconSize.Y) * 0.5f;
|
||||||
var buttonSize = new Vector2(iconSize.X, uidTextSize.Y);
|
var buttonSize = new Vector2(iconSize.X, uidTextSize.Y);
|
||||||
@@ -452,12 +467,6 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
ImGui.Text("Lightfinder");
|
ImGui.Text("Lightfinder");
|
||||||
ImGui.PopStyleColor();
|
ImGui.PopStyleColor();
|
||||||
|
|
||||||
ImGui.Text("This lets other Lightless users know you use Lightless.");
|
|
||||||
ImGui.Text("By enabling this, the server will allow other people to see that you are using Lightless.");
|
|
||||||
ImGui.Text("When disabled, pairing is still possible but both parties need to mutually send each other requests, receiving party will not be notified about the request unless the pairing is complete.");
|
|
||||||
ImGui.Text("At no point ever, even when Lightfinder is active that any Lightless data is getting sent to other people (including ID's), the server keeps this to itself.");
|
|
||||||
ImGui.Text("You can request to pair by right-clicking any (not yourself) character and using 'Send Pair Request'.");
|
|
||||||
|
|
||||||
ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("DimRed"));
|
ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("DimRed"));
|
||||||
ImGui.Text("Use it only when you want to be visible.");
|
ImGui.Text("Use it only when you want to be visible.");
|
||||||
ImGui.PopStyleColor();
|
ImGui.PopStyleColor();
|
||||||
|
|||||||
@@ -75,15 +75,6 @@ public class EditProfileUi : WindowMediatorSubscriberBase
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawNoteLine(string icon, Vector4 color, string text)
|
|
||||||
{
|
|
||||||
_uiSharedService.MediumText(icon, color);
|
|
||||||
ImGui.SameLine();
|
|
||||||
|
|
||||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 3);
|
|
||||||
ImGui.TextWrapped(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LoadVanity()
|
private void LoadVanity()
|
||||||
{
|
{
|
||||||
textEnabled = !string.IsNullOrEmpty(_apiController.TextColorHex);
|
textEnabled = !string.IsNullOrEmpty(_apiController.TextColorHex);
|
||||||
@@ -101,15 +92,15 @@ public class EditProfileUi : WindowMediatorSubscriberBase
|
|||||||
_uiSharedService.UnderlinedBigText("Notes and Rules for Profiles", UIColors.Get("LightlessYellow"));
|
_uiSharedService.UnderlinedBigText("Notes and Rules for Profiles", UIColors.Get("LightlessYellow"));
|
||||||
ImGui.Dummy(new Vector2(5));
|
ImGui.Dummy(new Vector2(5));
|
||||||
|
|
||||||
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(2, 2));
|
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(1, 1));
|
||||||
|
|
||||||
DrawNoteLine("# ", UIColors.Get("LightlessBlue"), "All users that are paired and unpaused with you will be able to see your profile picture and description.");
|
_uiSharedService.DrawNoteLine("# ", UIColors.Get("LightlessBlue"), "All users that are paired and unpaused with you will be able to see your profile picture and description.");
|
||||||
DrawNoteLine("! ", UIColors.Get("LightlessYellow"), "Other users have the possibility to report your profile for breaking the rules.");
|
_uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessYellow"), "Other users have the possibility to report your profile for breaking the rules.");
|
||||||
DrawNoteLine("!!! ", UIColors.Get("DimRed"), "AVOID: Anything as profile image that can be considered highly illegal or obscene (bestiality, anything that could be considered a sexual act with a minor (that includes Lalafells), etc.)");
|
_uiSharedService.DrawNoteLine("!!! ", UIColors.Get("DimRed"), "AVOID: Anything as profile image that can be considered highly illegal or obscene (bestiality, anything that could be considered a sexual act with a minor (that includes Lalafells), etc.)");
|
||||||
DrawNoteLine("!!! ", UIColors.Get("DimRed"), "AVOID: Slurs of any kind in the description that can be considered highly offensive");
|
_uiSharedService.DrawNoteLine("!!! ", UIColors.Get("DimRed"), "AVOID: Slurs of any kind in the description that can be considered highly offensive");
|
||||||
DrawNoteLine("! ", UIColors.Get("LightlessYellow"), "In case of valid reports from other users this can lead to disabling your profile forever or terminating your Lightless account indefinitely.");
|
_uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessYellow"), "In case of valid reports from other users this can lead to disabling your profile forever or terminating your Lightless account indefinitely.");
|
||||||
DrawNoteLine("! ", UIColors.Get("LightlessYellow"), "Judgement of your profile validity from reports through staff is not up to debate and the decisions to disable your profile/account permanent.");
|
_uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessYellow"), "Judgement of your profile validity from reports through staff is not up to debate and the decisions to disable your profile/account permanent.");
|
||||||
DrawNoteLine("! ", UIColors.Get("LightlessBlue"), "If your profile picture or profile description could be considered NSFW, enable the toggle in profile settings.");
|
_uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessBlue"), "If your profile picture or profile description could be considered NSFW, enable the toggle in profile settings.");
|
||||||
|
|
||||||
ImGui.PopStyleVar();
|
ImGui.PopStyleVar();
|
||||||
|
|
||||||
@@ -286,7 +277,7 @@ public class EditProfileUi : WindowMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
_uiSharedService.MediumText("Supporter Vanity Settings", UIColors.Get("LightlessPurple"));
|
_uiSharedService.MediumText("Supporter Vanity Settings", UIColors.Get("LightlessPurple"));
|
||||||
ImGui.Dummy(new Vector2(4));
|
ImGui.Dummy(new Vector2(4));
|
||||||
DrawNoteLine("# ", UIColors.Get("LightlessPurple"), "Must be a supporter through Patreon/Ko-fi to access these settings.");
|
_uiSharedService.DrawNoteLine("# ", UIColors.Get("LightlessPurple"), "Must be a supporter through Patreon/Ko-fi to access these settings.");
|
||||||
|
|
||||||
var hasVanity = _apiController.HasVanity;
|
var hasVanity = _apiController.HasVanity;
|
||||||
|
|
||||||
@@ -332,7 +323,7 @@ public class EditProfileUi : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
const float colorPickAlign = 90f;
|
const float colorPickAlign = 90f;
|
||||||
|
|
||||||
DrawNoteLine("- ", UIColors.Get("LightlessPurple"), "Text Color");
|
_uiSharedService.DrawNoteLine("- ", UIColors.Get("LightlessPurple"), "Text Color");
|
||||||
ImGui.SameLine(colorPickAlign);
|
ImGui.SameLine(colorPickAlign);
|
||||||
ImGui.Checkbox("##toggleTextColor", ref textEnabled);
|
ImGui.Checkbox("##toggleTextColor", ref textEnabled);
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
@@ -340,7 +331,7 @@ public class EditProfileUi : WindowMediatorSubscriberBase
|
|||||||
ImGui.ColorEdit4($"##color_text", ref textColor, ImGuiColorEditFlags.NoInputs | ImGuiColorEditFlags.AlphaPreviewHalf);
|
ImGui.ColorEdit4($"##color_text", ref textColor, ImGuiColorEditFlags.NoInputs | ImGuiColorEditFlags.AlphaPreviewHalf);
|
||||||
ImGui.EndDisabled();
|
ImGui.EndDisabled();
|
||||||
|
|
||||||
DrawNoteLine("- ", UIColors.Get("LightlessPurple"), "Glow Color");
|
_uiSharedService.DrawNoteLine("- ", UIColors.Get("LightlessPurple"), "Glow Color");
|
||||||
ImGui.SameLine(colorPickAlign);
|
ImGui.SameLine(colorPickAlign);
|
||||||
ImGui.Checkbox("##toggleGlowColor", ref glowEnabled);
|
ImGui.Checkbox("##toggleGlowColor", ref glowEnabled);
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
|
using Dalamud.Interface.Utility;
|
||||||
using Dalamud.Interface.Utility.Raii;
|
using Dalamud.Interface.Utility.Raii;
|
||||||
using LightlessSync.API.Dto.Group;
|
using LightlessSync.API.Dto.Group;
|
||||||
using LightlessSync.LightlessConfiguration;
|
using LightlessSync.LightlessConfiguration;
|
||||||
@@ -7,6 +8,7 @@ using LightlessSync.PlayerData.Pairs;
|
|||||||
using LightlessSync.Services.Mediator;
|
using LightlessSync.Services.Mediator;
|
||||||
using LightlessSync.Services.ServerConfiguration;
|
using LightlessSync.Services.ServerConfiguration;
|
||||||
using LightlessSync.Utils;
|
using LightlessSync.Utils;
|
||||||
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
namespace LightlessSync.UI.Handlers;
|
namespace LightlessSync.UI.Handlers;
|
||||||
@@ -114,14 +116,74 @@ public class IdDisplayHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var seString = (textColor != null || glowColor != null)
|
var useVanityColors = _lightlessConfigService.Current.useColoredUIDs && (textColor != null || glowColor != null);
|
||||||
|
var seString = useVanityColors
|
||||||
? SeStringUtils.BuildFormattedPlayerName(playerText, textColor, glowColor)
|
? SeStringUtils.BuildFormattedPlayerName(playerText, textColor, glowColor)
|
||||||
: SeStringUtils.BuildPlain(playerText);
|
: SeStringUtils.BuildPlain(playerText);
|
||||||
|
|
||||||
|
var rowStart = ImGui.GetCursorScreenPos();
|
||||||
|
var drawList = ImGui.GetWindowDrawList();
|
||||||
|
bool useHighlight = false;
|
||||||
|
float highlightPadX = 0f;
|
||||||
|
float highlightPadY = 0f;
|
||||||
|
|
||||||
|
if (useVanityColors && textColor is Vector4 contrastColor)
|
||||||
|
{
|
||||||
|
var brightness = (0.299f * contrastColor.X) + (0.587f * contrastColor.Y) + (0.114f * contrastColor.Z);
|
||||||
|
if (brightness < 0.35f)
|
||||||
|
{
|
||||||
|
var style = ImGui.GetStyle();
|
||||||
|
useHighlight = true;
|
||||||
|
highlightPadX = MathF.Max(style.FramePadding.X * 0.6f, 2f * ImGuiHelpers.GlobalScale);
|
||||||
|
highlightPadY = MathF.Max(style.FramePadding.Y * 0.55f, 1.25f * ImGuiHelpers.GlobalScale);
|
||||||
|
drawList.ChannelsSplit(2);
|
||||||
|
drawList.ChannelsSetCurrent(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 itemMin;
|
||||||
|
Vector2 itemMax;
|
||||||
|
Vector2 textSize;
|
||||||
using (ImRaii.PushFont(font, textIsUid))
|
using (ImRaii.PushFont(font, textIsUid))
|
||||||
{
|
{
|
||||||
var pos = ImGui.GetCursorScreenPos();
|
SeStringUtils.RenderSeStringWithHitbox(seString, rowStart, font);
|
||||||
SeStringUtils.RenderSeStringWithHitbox(seString, pos, font);
|
itemMin = ImGui.GetItemRectMin();
|
||||||
|
itemMax = ImGui.GetItemRectMax();
|
||||||
|
textSize = itemMax - itemMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useHighlight)
|
||||||
|
{
|
||||||
|
var style = ImGui.GetStyle();
|
||||||
|
var frameHeight = ImGui.GetFrameHeight();
|
||||||
|
var rowTop = rowStart.Y - style.FramePadding.Y;
|
||||||
|
var rowBottom = rowTop + frameHeight;
|
||||||
|
|
||||||
|
var highlightMin = new Vector2(itemMin.X - highlightPadX, rowTop - highlightPadY);
|
||||||
|
var highlightMax = new Vector2(itemMax.X + highlightPadX, rowBottom + highlightPadY);
|
||||||
|
|
||||||
|
var windowPos = ImGui.GetWindowPos();
|
||||||
|
var contentMin = windowPos + ImGui.GetWindowContentRegionMin();
|
||||||
|
var contentMax = windowPos + ImGui.GetWindowContentRegionMax();
|
||||||
|
highlightMin.X = MathF.Max(highlightMin.X, contentMin.X);
|
||||||
|
highlightMax.X = MathF.Min(highlightMax.X, contentMax.X);
|
||||||
|
highlightMin.Y = MathF.Max(highlightMin.Y, contentMin.Y);
|
||||||
|
highlightMax.Y = MathF.Min(highlightMax.Y, contentMax.Y);
|
||||||
|
|
||||||
|
var highlightColor = style.Colors[(int)ImGuiCol.TableRowBgAlt];
|
||||||
|
highlightColor.X = 0.25f;
|
||||||
|
highlightColor.Y = 0.25f;
|
||||||
|
highlightColor.Z = 0.25f;
|
||||||
|
highlightColor.W = 1f;
|
||||||
|
|
||||||
|
float rounding = style.FrameRounding > 0f ? style.FrameRounding : 5f * ImGuiHelpers.GlobalScale;
|
||||||
|
drawList.ChannelsSetCurrent(0);
|
||||||
|
drawList.AddRectFilled(highlightMin, highlightMax, ImGui.GetColorU32(highlightColor), rounding);
|
||||||
|
|
||||||
|
var borderColor = style.Colors[(int)ImGuiCol.Border];
|
||||||
|
borderColor.W *= 0.25f;
|
||||||
|
drawList.AddRect(highlightMin, highlightMax, ImGui.GetColorU32(borderColor), rounding);
|
||||||
|
drawList.ChannelsMerge();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui.IsItemHovered())
|
if (ImGui.IsItemHovered())
|
||||||
|
|||||||
@@ -1109,12 +1109,23 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f);
|
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f);
|
||||||
|
|
||||||
if (ImGui.Checkbox("Use the complete redesign of the UI for Lightless client.", ref useLightlessRedesign))
|
ImGui.TextUnformatted("UI Theme");
|
||||||
|
|
||||||
|
if (ImGui.Checkbox("Use the redesign of the UI for Lightless client", ref useLightlessRedesign))
|
||||||
{
|
{
|
||||||
_configService.Current.UseLightlessRedesign = useLightlessRedesign;
|
_configService.Current.UseLightlessRedesign = useLightlessRedesign;
|
||||||
_configService.Save();
|
_configService.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var usePairColoredUIDs = _configService.Current.useColoredUIDs;
|
||||||
|
|
||||||
|
if (ImGui.Checkbox("Toggle the colored UID's in pair list", ref usePairColoredUIDs))
|
||||||
|
{
|
||||||
|
_configService.Current.useColoredUIDs = usePairColoredUIDs;
|
||||||
|
_configService.Save();
|
||||||
|
}
|
||||||
|
_uiShared.DrawHelpText("This changes the vanity colored UID's in pair list.");
|
||||||
|
|
||||||
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
|
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
|
||||||
ImGui.TreePop();
|
ImGui.TreePop();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,6 +103,14 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DrawSyncshellTable();
|
||||||
|
|
||||||
|
if (_joinDto != null && _joinInfo != null && _joinInfo.Success)
|
||||||
|
DrawConfirmation();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawSyncshellTable()
|
||||||
|
{
|
||||||
if (ImGui.BeginTable("##NearbySyncshellsTable", 3, ImGuiTableFlags.Borders | ImGuiTableFlags.RowBg))
|
if (ImGui.BeginTable("##NearbySyncshellsTable", 3, ImGuiTableFlags.Borders | ImGuiTableFlags.RowBg))
|
||||||
{
|
{
|
||||||
ImGui.TableSetupColumn("Syncshell", ImGuiTableColumnFlags.WidthStretch);
|
ImGui.TableSetupColumn("Syncshell", ImGuiTableColumnFlags.WidthStretch);
|
||||||
@@ -122,18 +130,18 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
|||||||
var broadcasterName = "Unknown";
|
var broadcasterName = "Unknown";
|
||||||
var broadcast = _broadcastScannerService.GetActiveSyncshellBroadcasts()
|
var broadcast = _broadcastScannerService.GetActiveSyncshellBroadcasts()
|
||||||
.FirstOrDefault(b => string.Equals(b.GID, shell.Group.GID, StringComparison.Ordinal));
|
.FirstOrDefault(b => string.Equals(b.GID, shell.Group.GID, StringComparison.Ordinal));
|
||||||
|
|
||||||
if (broadcast != null)
|
if (broadcast != null)
|
||||||
{
|
{
|
||||||
var playerInfo = _dalamudUtilService.FindPlayerByNameHash(broadcast.HashedCID);
|
var (Name, Address) = _dalamudUtilService.FindPlayerByNameHash(broadcast.HashedCID);
|
||||||
if (!string.IsNullOrEmpty(playerInfo.Name))
|
if (!string.IsNullOrEmpty(Name))
|
||||||
{
|
{
|
||||||
var worldName = _dalamudUtilService.GetWorldNameFromPlayerAddress(playerInfo.Address);
|
var worldName = _dalamudUtilService.GetWorldNameFromPlayerAddress(Address);
|
||||||
broadcasterName = !string.IsNullOrEmpty(worldName) ? $"{playerInfo.Name} ({worldName})" : playerInfo.Name;
|
broadcasterName = !string.IsNullOrEmpty(worldName) ? $"{Name} ({worldName})" : Name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui.TextUnformatted(broadcasterName);
|
ImGui.TextUnformatted(broadcasterName);
|
||||||
|
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
|
|
||||||
var label = $"Join##{shell.Group.GID}";
|
var label = $"Join##{shell.Group.GID}";
|
||||||
@@ -179,7 +187,6 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
using (ImRaii.Disabled())
|
using (ImRaii.Disabled())
|
||||||
{
|
{
|
||||||
ImGui.Button(label);
|
ImGui.Button(label);
|
||||||
@@ -191,9 +198,6 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
ImGui.EndTable();
|
ImGui.EndTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_joinDto != null && _joinInfo != null && _joinInfo.Success)
|
|
||||||
DrawConfirmation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawConfirmation()
|
private void DrawConfirmation()
|
||||||
@@ -222,6 +226,7 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
|||||||
_ = _apiController.GroupJoinFinalize(new GroupJoinDto(_joinDto.Group, _joinDto.Password, finalPermissions));
|
_ = _apiController.GroupJoinFinalize(new GroupJoinDto(_joinDto.Group, _joinDto.Password, finalPermissions));
|
||||||
_joinDto = null;
|
_joinDto = null;
|
||||||
_joinInfo = null;
|
_joinInfo = null;
|
||||||
|
_ = RefreshSyncshellsAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -255,7 +260,7 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
|||||||
private async Task RefreshSyncshellsAsync()
|
private async Task RefreshSyncshellsAsync()
|
||||||
{
|
{
|
||||||
var syncshellBroadcasts = _broadcastScannerService.GetActiveSyncshellBroadcasts();
|
var syncshellBroadcasts = _broadcastScannerService.GetActiveSyncshellBroadcasts();
|
||||||
_currentSyncshells = _pairManager.GroupPairs.Select(g => g.Key).ToList();
|
_currentSyncshells = [.. _pairManager.GroupPairs.Select(g => g.Key)];
|
||||||
|
|
||||||
if (syncshellBroadcasts.Count == 0)
|
if (syncshellBroadcasts.Count == 0)
|
||||||
{
|
{
|
||||||
@@ -263,7 +268,7 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<GroupJoinDto> updatedList = [];
|
List<GroupJoinDto>? updatedList = [];
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var groups = await _apiController.GetBroadcastedGroups(syncshellBroadcasts).ConfigureAwait(false);
|
var groups = await _apiController.GetBroadcastedGroups(syncshellBroadcasts).ConfigureAwait(false);
|
||||||
@@ -276,23 +281,27 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
var currentGids = _nearbySyncshells.Select(s => s.Group.GID).ToHashSet(StringComparer.Ordinal);
|
var currentGids = _nearbySyncshells.Select(s => s.Group.GID).ToHashSet(StringComparer.Ordinal);
|
||||||
var newGids = updatedList.Select(s => s.Group.GID).ToHashSet(StringComparer.Ordinal);
|
|
||||||
|
|
||||||
if (currentGids.SetEquals(newGids))
|
if (updatedList != null)
|
||||||
return;
|
|
||||||
|
|
||||||
var previousGid = GetSelectedGid();
|
|
||||||
|
|
||||||
_nearbySyncshells.Clear();
|
|
||||||
_nearbySyncshells.AddRange(updatedList);
|
|
||||||
|
|
||||||
if (previousGid != null)
|
|
||||||
{
|
{
|
||||||
var newIndex = _nearbySyncshells.FindIndex(s => string.Equals(s.Group.GID, previousGid, StringComparison.Ordinal));
|
var newGids = updatedList.Select(s => s.Group.GID).ToHashSet(StringComparer.Ordinal);
|
||||||
if (newIndex >= 0)
|
|
||||||
{
|
if (currentGids.SetEquals(newGids))
|
||||||
_selectedNearbyIndex = newIndex;
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var previousGid = GetSelectedGid();
|
||||||
|
|
||||||
|
_nearbySyncshells.Clear();
|
||||||
|
_nearbySyncshells.AddRange(updatedList);
|
||||||
|
|
||||||
|
if (previousGid != null)
|
||||||
|
{
|
||||||
|
var newIndex = _nearbySyncshells.FindIndex(s => string.Equals(s.Group.GID, previousGid, StringComparison.Ordinal));
|
||||||
|
if (newIndex >= 0)
|
||||||
|
{
|
||||||
|
_selectedNearbyIndex = newIndex;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Dalamud.Interface.Colors;
|
using Dalamud.Interface.Colors;
|
||||||
using Dalamud.Interface.GameFonts;
|
using Dalamud.Interface.GameFonts;
|
||||||
@@ -7,6 +7,7 @@ using Dalamud.Interface.ManagedFontAtlas;
|
|||||||
using Dalamud.Interface.Textures.TextureWraps;
|
using Dalamud.Interface.Textures.TextureWraps;
|
||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
using Dalamud.Interface.Utility.Raii;
|
using Dalamud.Interface.Utility.Raii;
|
||||||
|
using System;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using Dalamud.Utility;
|
using Dalamud.Utility;
|
||||||
@@ -531,6 +532,52 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
FontText(text, MediumFont, color);
|
FontText(text, MediumFont, color);
|
||||||
}
|
}
|
||||||
|
public void DrawNoteLine(string icon, Vector4 color, string text)
|
||||||
|
{
|
||||||
|
MediumText(icon, color);
|
||||||
|
var iconHeight = ImGui.GetItemRectSize().Y;
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
float textHeight = ImGui.GetTextLineHeight();
|
||||||
|
float offset = (iconHeight - textHeight) * 0.5f;
|
||||||
|
if (offset > 0)
|
||||||
|
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + offset);
|
||||||
|
|
||||||
|
ImGui.BeginGroup();
|
||||||
|
ImGui.TextWrapped(text);
|
||||||
|
ImGui.EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawNoteLine(string icon, Vector4 color, ReadOnlySpan<SeStringUtils.RichTextEntry> fragments)
|
||||||
|
{
|
||||||
|
if (fragments.Length == 0)
|
||||||
|
{
|
||||||
|
DrawNoteLine(icon, color, string.Empty);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MediumText(icon, color);
|
||||||
|
var iconHeight = ImGui.GetItemRectSize().Y;
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
float textHeight = ImGui.GetTextLineHeight();
|
||||||
|
float offset = (iconHeight - textHeight) * 0.5f;
|
||||||
|
if (offset > 0)
|
||||||
|
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + offset);
|
||||||
|
|
||||||
|
var wrapWidth = ImGui.GetContentRegionAvail().X;
|
||||||
|
ImGui.BeginGroup();
|
||||||
|
var richText = SeStringUtils.BuildRichText(fragments);
|
||||||
|
SeStringUtils.RenderSeStringWrapped(richText, wrapWidth);
|
||||||
|
ImGui.EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawNoteLine(string icon, Vector4 color, params SeStringUtils.RichTextEntry[] fragments)
|
||||||
|
{
|
||||||
|
DrawNoteLine(icon, color, fragments.AsSpan());
|
||||||
|
}
|
||||||
|
|
||||||
public bool MediumTreeNode(string label, Vector4? textColor = null, float lineWidth = 2f, ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags.SpanAvailWidth)
|
public bool MediumTreeNode(string label, Vector4? textColor = null, float lineWidth = 2f, ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags.SpanAvailWidth)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Game.Text.SeStringHandling;
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
|
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Dalamud.Interface.ImGuiSeStringRenderer;
|
using Dalamud.Interface.ImGuiSeStringRenderer;
|
||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
|
using Lumina.Text;
|
||||||
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using DalamudSeString = Dalamud.Game.Text.SeStringHandling.SeString;
|
||||||
|
using DalamudSeStringBuilder = Dalamud.Game.Text.SeStringHandling.SeStringBuilder;
|
||||||
|
using LuminaSeStringBuilder = Lumina.Text.SeStringBuilder;
|
||||||
|
|
||||||
namespace LightlessSync.Utils;
|
namespace LightlessSync.Utils;
|
||||||
|
|
||||||
public static class SeStringUtils
|
public static class SeStringUtils
|
||||||
{
|
{
|
||||||
public static SeString BuildFormattedPlayerName(string text, Vector4? textColor, Vector4? glowColor)
|
public static DalamudSeString BuildFormattedPlayerName(string text, Vector4? textColor, Vector4? glowColor)
|
||||||
{
|
{
|
||||||
var b = new SeStringBuilder();
|
var b = new DalamudSeStringBuilder();
|
||||||
|
|
||||||
if (glowColor is Vector4 glow)
|
if (glowColor is Vector4 glow)
|
||||||
b.Add(new GlowPayload(glow));
|
b.Add(new GlowPayload(glow));
|
||||||
@@ -30,14 +36,47 @@ public static class SeStringUtils
|
|||||||
return b.Build();
|
return b.Build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SeString BuildPlain(string text)
|
public static DalamudSeString BuildPlain(string text)
|
||||||
{
|
{
|
||||||
var b = new SeStringBuilder();
|
var b = new DalamudSeStringBuilder();
|
||||||
b.AddText(text ?? string.Empty);
|
b.AddText(text ?? string.Empty);
|
||||||
return b.Build();
|
return b.Build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RenderSeString(SeString seString, Vector2 position, ImFontPtr? font = null, ImDrawListPtr? drawList = null)
|
public static DalamudSeString BuildRichText(ReadOnlySpan<RichTextEntry> fragments)
|
||||||
|
{
|
||||||
|
var builder = new LuminaSeStringBuilder();
|
||||||
|
|
||||||
|
foreach (var fragment in fragments)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(fragment.Text))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var hasColor = fragment.Color.HasValue;
|
||||||
|
Vector4 color = default;
|
||||||
|
if (hasColor)
|
||||||
|
{
|
||||||
|
color = fragment.Color!.Value;
|
||||||
|
builder.PushColorRgba(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fragment.Bold)
|
||||||
|
builder.AppendSetBold(true);
|
||||||
|
|
||||||
|
builder.Append(fragment.Text.AsSpan());
|
||||||
|
|
||||||
|
if (fragment.Bold)
|
||||||
|
builder.AppendSetBold(false);
|
||||||
|
|
||||||
|
if (hasColor)
|
||||||
|
builder.PopColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
return DalamudSeString.Parse(builder.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DalamudSeString BuildRichText(params RichTextEntry[] fragments) => BuildRichText(fragments.AsSpan());
|
||||||
|
public static void RenderSeString(DalamudSeString seString, Vector2 position, ImFontPtr? font = null, ImDrawListPtr? drawList = null)
|
||||||
{
|
{
|
||||||
drawList ??= ImGui.GetWindowDrawList();
|
drawList ??= ImGui.GetWindowDrawList();
|
||||||
|
|
||||||
@@ -51,9 +90,36 @@ public static class SeStringUtils
|
|||||||
|
|
||||||
ImGui.SetCursorScreenPos(position);
|
ImGui.SetCursorScreenPos(position);
|
||||||
ImGuiHelpers.SeStringWrapped(seString.Encode(), drawParams);
|
ImGuiHelpers.SeStringWrapped(seString.Encode(), drawParams);
|
||||||
|
|
||||||
|
var textSize = ImGui.CalcTextSize(seString.TextValue);
|
||||||
|
if (textSize.Y <= 0f)
|
||||||
|
textSize.Y = ImGui.GetTextLineHeight();
|
||||||
|
|
||||||
|
ImGui.Dummy(new Vector2(0f, textSize.Y));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Vector2 RenderSeStringWithHitbox(SeString seString, Vector2 position, ImFontPtr? font = null)
|
public static void RenderSeStringWrapped(DalamudSeString seString, float wrapWidth, ImFontPtr? font = null, ImDrawListPtr? drawList = null)
|
||||||
|
{
|
||||||
|
drawList ??= ImGui.GetWindowDrawList();
|
||||||
|
|
||||||
|
var drawParams = new SeStringDrawParams
|
||||||
|
{
|
||||||
|
Font = font ?? ImGui.GetFont(),
|
||||||
|
Color = ImGui.GetColorU32(ImGuiCol.Text),
|
||||||
|
WrapWidth = wrapWidth,
|
||||||
|
TargetDrawList = drawList
|
||||||
|
};
|
||||||
|
|
||||||
|
ImGuiHelpers.SeStringWrapped(seString.Encode(), drawParams);
|
||||||
|
|
||||||
|
var calcWrapWidth = wrapWidth > 0f ? wrapWidth : -1f;
|
||||||
|
var textSize = ImGui.CalcTextSize(seString.TextValue, wrapWidth: calcWrapWidth);
|
||||||
|
if (textSize.Y <= 0f)
|
||||||
|
textSize.Y = ImGui.GetTextLineHeight();
|
||||||
|
|
||||||
|
ImGui.Dummy(new Vector2(0f, textSize.Y));
|
||||||
|
}
|
||||||
|
public static Vector2 RenderSeStringWithHitbox(DalamudSeString seString, Vector2 position, ImFontPtr? font = null)
|
||||||
{
|
{
|
||||||
var drawList = ImGui.GetWindowDrawList();
|
var drawList = ImGui.GetWindowDrawList();
|
||||||
|
|
||||||
@@ -99,6 +165,8 @@ public static class SeStringUtils
|
|||||||
|
|
||||||
#region Internal Payloads
|
#region Internal Payloads
|
||||||
|
|
||||||
|
public readonly record struct RichTextEntry(string Text, Vector4? Color = null, bool Bold = false);
|
||||||
|
|
||||||
private abstract class AbstractColorPayload : Payload
|
private abstract class AbstractColorPayload : Payload
|
||||||
{
|
{
|
||||||
protected byte Red { get; init; }
|
protected byte Red { get; init; }
|
||||||
|
|||||||
Reference in New Issue
Block a user