Compare commits

...

40 Commits

Author SHA1 Message Date
defnotken
2f383c3ebe Version bump 2025-09-01 09:05:56 -05:00
defnotken
5dfd859542 Adding gitea workflow 2025-09-01 09:04:37 -05:00
Pim
beb737b267 Added functionality to rename groups (#12)
* Updated logos in Profile screen.

* Updated IPC calls for Petrenamer and bumped API version.

* IPC calls updated, APIVersion pushed for Moodles

* Updated version 1.11.4 in csproj

* Added Rename Tag UI for renaming of groups
2025-09-01 08:53:28 -05:00
azyges
68c0bf1334 random ui changes 2025-09-01 07:52:50 +09:00
azyges
05daa59e40 incorrect label.. 2025-08-31 10:02:02 +09:00
azyges
c3a6f2c88d fancy settings 2025-08-31 08:29:23 +09:00
defnotken
dc0265f614 1.11.4 Release Branch (#9)
* Updated logos in Profile screen. (#8)

* UI updates + bugfixes

* Updated version 1.11.4 in csproj

---------

Co-authored-by: Pim <48980200+CakeAndBanana@users.noreply.github.com>
2025-08-30 12:39:03 -05:00
defnotken
ba0e1cea08 Update lightless-tag-and-release.yml 2025-08-29 19:40:00 -05:00
defnotken
1dea9b713e Update LightlessSync.csproj 2025-08-29 18:51:29 -05:00
defnotken
23c57aedc4 Add Nameplates + Clean up.
* Yeet Token!

* Cleaning up workflow

* Testing auto version bump

* ExistingNames

* Remove a key

* Github Token no work

* Changing Assembly Version

* Version Fix

* Fixing version v2

* Cleanup naming

* Update LightlessSync.csproj

* Add nameplate settings + run code clean up

* purple
2025-08-29 18:48:01 -05:00
azyges
15bf87feb4 bump version 2025-08-29 09:29:53 +09:00
azyges
9c0379631f adjust colors 2025-08-29 09:23:51 +09:00
defnotken
44475fda50 FINAL FINAL (#6)
* Yeet Token!

* Cleaning up workflow
2025-08-27 19:21:42 +02:00
defnotken
071885b04c Modify Variable (#4) 2025-08-27 18:21:01 +02:00
Zura
27c3231084 Merge pull request #3 from defnotken/master
Build and Release Workflow on Push to Master
2025-08-27 17:18:20 +02:00
defnotken
2b98bf6891 changing the name of the release 2025-08-27 09:13:01 -05:00
defnotken
b6b8e7bddf Clean up 2025-08-27 09:09:03 -05:00
defnotken
9f8cc48e34 One more time! 2025-08-27 09:03:55 -05:00
defnotken
ae6013adf6 Forgot to make a directory 2025-08-27 08:59:36 -05:00
defnotken
2b67f44788 Switching path of the build 2025-08-27 08:56:29 -05:00
defnotken
ad74729c4a Testing zip and publish 2025-08-26 13:43:38 -05:00
defnotken
4f3a6a8205 running on windows 2025-08-26 13:31:13 -05:00
defnotken
71e80f5c48 add dalamud 2025-08-26 13:29:23 -05:00
defnotken
77f667ccfd now with submodules 2025-08-26 13:07:45 -05:00
defnotken
97e964473b remove cache mode 2025-08-26 13:01:50 -05:00
defnotken
d5d89a759e testing builds 2025-08-26 12:59:23 -05:00
defnotken
e5c87e5d68 debugging version 2025-08-26 11:30:34 -05:00
defnotken
5559c06d2b version references 2025-08-26 11:27:46 -05:00
defnotken
53bea001ba slash? 2025-08-26 11:24:49 -05:00
defnotken
a401a18c04 renaming variable oops 2025-08-26 11:22:55 -05:00
defnotken
213f6e9f6d Testing another action 2025-08-26 11:21:41 -05:00
defnotken
4570c4b5f4 Testing out tag and release 2025-08-26 11:14:35 -05:00
Zura
e6c1120323 Update README.md 2025-08-25 22:33:26 +02:00
Zura
0d35d04a20 Update README.md 2025-08-25 22:33:07 +02:00
Zura
5fb9ec7637 Add files via upload 2025-08-25 16:15:11 +02:00
Abelfreyja
1902d09037 forgot version oops 2025-08-25 21:03:18 +09:00
Abelfreyja
e5b629fd5d wow it works 2025-08-25 20:54:07 +09:00
Abelfreyja
f29356836d same thing.. 2025-08-25 20:48:46 +09:00
Abelfreyja
96238f294a move to submodule, nuget outdated, fix routes for api too and of course update packages 2025-08-25 20:47:25 +09:00
Abelfreyja
a6e727542a fix submodule, i'm tired 2025-08-25 03:45:12 +09:00
84 changed files with 1611 additions and 816 deletions

View File

@@ -0,0 +1,182 @@
name: Tag and Release Lightless
on:
push:
branches: [ master ]
env:
PLUGIN_NAME: LightlessSync
DOTNET_VERSION: 9.x
jobs:
tag-and-release:
runs-on: ubuntu-22.04
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: |
cd /
mkdir -p root/.xlcore/dalamud/Hooks/dev
curl -O https://goatcorp.github.io/dalamud-distrib/stg/latest.zip
unzip latest.zip -d /root/.xlcore/dalamud/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: |
PUBLISH_PATH="/workspace/Lightless-Sync/LightlessClient/LightlessSync/bin/x64/Release/publish/"
if [ -d "$PUBLISH_PATH" ]; then
rm -rf "$PUBLISH_PATH"
echo "Removed $PUBLISH_PATH"
else
echo "$PUBLISH_PATH does not exist, nothing to remove."
fi
mkdir -p output
(cd /workspace/Lightless-Sync/LightlessClient/LightlessSync/bin/x64/Release/ && zip -r $OLDPWD/output/LightlessClient.zip *)
- name: Create Git tag if not exists
run: |
tag="${{ steps.package_version.outputs.version }}"
git fetch --tags
if ! git tag -l "$tag" | grep -q "$tag"; then
echo "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
echo "Tag $tag already exists. Skipping tag creation."
fi
- name: Create Release
id: create_release
run: |
echo "=== Searching for existing release ${{ steps.package_version.outputs.version }}==="
release_id=$(curl -s -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \
"https://git.lightless-sync.org/api/v1/repos/${GITHUB_REPOSITORY}/releases/tags/${{ steps.package_version.outputs.version }}" | jq -r .id)
if [ "$release_id" != "null" ]; then
echo "=== Deleting existing release ${{ steps.package_version.outputs.version }}==="
curl -X DELETE -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \
"https://git.lightless-sync.org/api/v1/repos/${GITHUB_REPOSITORY}/releases/$release_id"
fi
echo "=== Creating new release ${{ steps.package_version.outputs.version }}==="
response=$(
curl --fail-with-body -X POST \
-H "Content-Type: application/json" \
-H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \
-d '{
"tag_name": "${{ steps.package_version.outputs.version }}",
"name": "${{ steps.package_version.outputs.version }}",
"draft": false,
"prerelease": false
}' \
"https://git.lightless-sync.org/api/v1/repos/${GITHUB_REPOSITORY}/releases"
)
release_id=$(echo "$response" | jq -r .id)
echo "release_id=$release_id" >> "$GITHUB_OUTPUT"
- name: Upload Assets to release
run: |
curl --fail-with-body -s -X POST \
-H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \
-F "attachment=@output/LightlessClient.zip" \
"https://git.lightless-sync.org/api/v1/repos/${GITHUB_REPOSITORY}/releases/${{ steps.create_release.outputs.release_id }}/assets"
- name: Clone plugin hosting repo
run: |
mkdir LightlessSyncRepo
cd LightlessSyncRepo
git clone https://git.lightless-sync.org/${{ gitea.repository_owner }}/LightlessSync.git
env:
GIT_TERMINAL_PROMPT: 0
- name: Update plogonmaster.json with version
env:
VERSION: ${{ steps.package_version.outputs.version }}
run: |
set -e
pluginJsonPath="${PLUGIN_NAME}/bin/x64/Release/${PLUGIN_NAME}.json"
repoJsonPath="LightlessSyncRepo/LightlessSync/plogonmaster.json"
version="${VERSION}"
downloadUrl="https://git.lightless-sync.org/${{ gitea.repository_owner }}/LightlessClient/releases/download/$version/LightlessClient.zip"
# Read plugin JSON
pluginJson=$(cat "$pluginJsonPath")
internalName=$(jq -r '.InternalName' <<< "$pluginJson")
dalamudApiLevel=$(jq -r '.DalamudApiLevel' <<< "$pluginJson")
# Read repo JSON (force array if not already)
repoJsonRaw=$(cat "$repoJsonPath")
if echo "$repoJsonRaw" | jq 'type' | grep -q '"array"'; then
repoJson="$repoJsonRaw"
else
repoJson="[$repoJsonRaw]"
fi
# Update matching plugin entry
updatedRepoJson=$(jq \
--arg internalName "$internalName" \
--arg dalamudApiLevel "$dalamudApiLevel" \
--arg version "$version" \
--arg downloadUrl "$downloadUrl" \
'
map(
if .InternalName == $internalName
then
.DalamudApiLevel = $dalamudApiLevel
| .AssemblyVersion = $version
| .DownloadLinkInstall = $downloadUrl
| .DownloadLinkTesting = $downloadUrl
| .DownloadLinkUpdate = $downloadUrl
else
.
end
)
' <<< "$repoJson")
# Write back to file
echo "$updatedRepoJson" > "$repoJsonPath"
# Output the content of the file
cat "$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 diff-index --quiet HEAD || git commit -m "Update ${{ env.PLUGIN_NAME }} to ${{ steps.package_version.outputs.version }}"
git push https://x-access-token:${{ secrets.AUTOMATION_TOKEN }}@git.lightless-sync.org/${{ gitea.repository_owner }}/LightlessSync.git HEAD:main

View File

@@ -0,0 +1,140 @@
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

3
.gitmodules vendored
View File

@@ -1,3 +1,6 @@
[submodule "LightlessAPI"]
path = LightlessAPI
url = https://github.com/Light-Public-Syncshells/LightlessAPI
[submodule "PenumbraAPI"]
path = PenumbraAPI
url = https://github.com/Ottermandias/Penumbra.Api.git

View File

@@ -12,6 +12,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightlessSync", "LightlessS
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightlessSync.API", "LightlessAPI\LightlessSyncAPI\LightlessSync.API.csproj", "{A4E42AFA-5045-7E81-937F-3A320AC52987}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Penumbra.Api", "PenumbraAPI\Penumbra.Api.csproj", "{C104F6BE-9CC4-9CF7-271C-5C3A1F646601}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -36,6 +38,14 @@ Global
{A4E42AFA-5045-7E81-937F-3A320AC52987}.Release|Any CPU.Build.0 = Release|Any CPU
{A4E42AFA-5045-7E81-937F-3A320AC52987}.Release|x64.ActiveCfg = Release|Any CPU
{A4E42AFA-5045-7E81-937F-3A320AC52987}.Release|x64.Build.0 = Release|Any CPU
{C104F6BE-9CC4-9CF7-271C-5C3A1F646601}.Debug|Any CPU.ActiveCfg = Debug|x64
{C104F6BE-9CC4-9CF7-271C-5C3A1F646601}.Debug|Any CPU.Build.0 = Debug|x64
{C104F6BE-9CC4-9CF7-271C-5C3A1F646601}.Debug|x64.ActiveCfg = Debug|x64
{C104F6BE-9CC4-9CF7-271C-5C3A1F646601}.Debug|x64.Build.0 = Debug|x64
{C104F6BE-9CC4-9CF7-271C-5C3A1F646601}.Release|Any CPU.ActiveCfg = Release|x64
{C104F6BE-9CC4-9CF7-271C-5C3A1F646601}.Release|Any CPU.Build.0 = Release|x64
{C104F6BE-9CC4-9CF7-271C-5C3A1F646601}.Release|x64.ActiveCfg = Release|x64
{C104F6BE-9CC4-9CF7-271C-5C3A1F646601}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -27,9 +27,9 @@ public sealed class IpcCallerMoodles : IIpcCaller
_moodlesApiVersion = pi.GetIpcSubscriber<int>("Moodles.Version");
_moodlesOnChange = pi.GetIpcSubscriber<IPlayerCharacter, object>("Moodles.StatusManagerModified");
_moodlesGetStatus = pi.GetIpcSubscriber<nint, string>("Moodles.GetStatusManagerByPtr");
_moodlesSetStatus = pi.GetIpcSubscriber<nint, string, object>("Moodles.SetStatusManagerByPtr");
_moodlesRevertStatus = pi.GetIpcSubscriber<nint, object>("Moodles.ClearStatusManagerByPtr");
_moodlesGetStatus = pi.GetIpcSubscriber<nint, string>("Moodles.GetStatusManagerByPtrV2");
_moodlesSetStatus = pi.GetIpcSubscriber<nint, string, object>("Moodles.SetStatusManagerByPtrV2");
_moodlesRevertStatus = pi.GetIpcSubscriber<nint, object>("Moodles.ClearStatusManagerByPtrV2");
_moodlesOnChange.Subscribe(OnMoodlesChange);
@@ -47,7 +47,7 @@ public sealed class IpcCallerMoodles : IIpcCaller
{
try
{
APIAvailable = _moodlesApiVersion.InvokeFunc() == 1;
APIAvailable = _moodlesApiVersion.InvokeFunc() == 3;
}
catch
{

View File

@@ -216,7 +216,7 @@ public sealed class IpcCallerPenumbra : DisposableMediatorSubscriberBase, IIpcCa
return await _dalamudUtil.RunOnFrameworkThread(() =>
{
var collName = "Lightless_" + uid;
var collId = _penumbraCreateNamedTemporaryCollection.Invoke(collName);
_penumbraCreateNamedTemporaryCollection.Invoke(collName, collName, out var collId);
logger.LogTrace("Creating Temp Collection {collName}, GUID: {collId}", collName, collId);
return collId;

View File

@@ -30,12 +30,12 @@ public sealed class IpcCallerPetNames : IIpcCaller
_dalamudUtil = dalamudUtil;
_lightlessMediator = lightlessMediator;
_petnamesReady = pi.GetIpcSubscriber<object>("PetRenamer.Ready");
_petnamesDisposing = pi.GetIpcSubscriber<object>("PetRenamer.Disposing");
_petnamesReady = pi.GetIpcSubscriber<object>("PetRenamer.OnReady");
_petnamesDisposing = pi.GetIpcSubscriber<object>("PetRenamer.OnDisposing");
_apiVersion = pi.GetIpcSubscriber<(uint, uint)>("PetRenamer.ApiVersion");
_enabled = pi.GetIpcSubscriber<bool>("PetRenamer.Enabled");
_enabled = pi.GetIpcSubscriber<bool>("PetRenamer.IsEnabled");
_playerDataChanged = pi.GetIpcSubscriber<string, object>("PetRenamer.PlayerDataChanged");
_playerDataChanged = pi.GetIpcSubscriber<string, object>("PetRenamer.OnPlayerDataChanged");
_getPlayerData = pi.GetIpcSubscriber<string>("PetRenamer.GetPlayerData");
_setPlayerData = pi.GetIpcSubscriber<string, object>("PetRenamer.SetPlayerData");
_clearPlayerData = pi.GetIpcSubscriber<ushort, object>("PetRenamer.ClearPlayerData");
@@ -56,7 +56,7 @@ public sealed class IpcCallerPetNames : IIpcCaller
APIAvailable = _enabled?.InvokeFunc() ?? false;
if (APIAvailable)
{
APIAvailable = _apiVersion?.InvokeFunc() is { Item1: 3, Item2: >= 1 };
APIAvailable = _apiVersion?.InvokeFunc() is { Item1: 4, Item2: >= 0 };
}
}
catch
@@ -84,7 +84,7 @@ public sealed class IpcCallerPetNames : IIpcCaller
{
string localNameData = _getPlayerData.InvokeFunc();
return string.IsNullOrEmpty(localNameData) ? string.Empty : localNameData;
}
}
catch (Exception e)
{
_logger.LogWarning(e, "Could not obtain Pet Nicknames data");

View File

@@ -1,5 +1,4 @@
using LightlessSync.LightlessConfiguration.Configurations;
using LightlessSync.LightlessConfiguration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.Reflection;

View File

@@ -13,6 +13,8 @@ public class LightlessConfig : ILightlessConfiguration
public bool EnableDtrEntry { get; set; } = false;
public bool ShowUidInDtrTooltip { get; set; } = true;
public bool PreferNoteInDtrTooltip { get; set; } = false;
public bool IsNameplateColorsEnabled { get; set; } = false;
public DtrEntry.Colors NameplateColors { get; set; } = new(Foreground: 0xE69138u, Glow: 0xFFBA47u);
public bool UseColorsInDtr { get; set; } = true;
public DtrEntry.Colors DtrColorsDefault { get; set; } = default;
public DtrEntry.Colors DtrColorsNotConnected { get; set; } = new(Glow: 0x0428FFu);
@@ -60,4 +62,6 @@ public class LightlessConfig : ILightlessConfiguration
public int Version { get; set; } = 1;
public NotificationLocation WarningNotification { get; set; } = NotificationLocation.Both;
public bool UseFocusTarget { get; set; } = false;
public bool overrideFriendColor { get; set; } = false;
public bool overridePartyColor { get; set; } = false;
}

View File

@@ -1,5 +1,4 @@
using LightlessSync.API.Data.Enum;
using LightlessSync.LightlessConfiguration.Configurations;
namespace LightlessSync.LightlessConfiguration.Configurations;

View File

@@ -151,6 +151,7 @@ public class LightlessPlugin : MediatorSubscriberBase, IHostedService
_runtimeServiceScope.ServiceProvider.GetRequiredService<TransientResourceManager>();
_runtimeServiceScope.ServiceProvider.GetRequiredService<VisibleUserDataDistributor>();
_runtimeServiceScope.ServiceProvider.GetRequiredService<NotificationService>();
_runtimeServiceScope.ServiceProvider.GetRequiredService<NameplateService>();
#if !DEBUG
if (_lightlessConfigService.Current.LogLevel != LogLevel.Information)

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<Authors></Authors>
<Company></Company>
<Version>1.11.0</Version>
<Version>1.11.5</Version>
<Description></Description>
<Copyright></Copyright>
<PackageProjectUrl>https://github.com/Light-Public-Syncshells/LightlessClient</PackageProjectUrl>
@@ -28,20 +28,19 @@
<ItemGroup>
<PackageReference Include="DalamudPackager" Version="13.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="Meziantou.Analyzer" Version="2.0.189">
<PackageReference Include="Meziantou.Analyzer" Version="2.0.212">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.3" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="9.0.3" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.3" />
<PackageReference Include="Glamourer.Api" Version="2.4.0" />
<PackageReference Include="Glamourer.Api" Version="2.6.0" />
<PackageReference Include="NReco.Logging.File" Version="1.2.2" />
<PackageReference Include="Penumbra.Api" Version="5.6.0" />
<PackageReference Include="Penumbra.String" Version="1.0.5" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.11" />
<PackageReference Include="SonarAnalyzer.CSharp" Version="10.7.0.110445">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
@@ -75,6 +74,7 @@
<ItemGroup>
<ProjectReference Include="..\LightlessAPI\LightlessSyncAPI\LightlessSync.API.csproj" />
<ProjectReference Include="..\PenumbraAPI\Penumbra.Api.csproj" />
</ItemGroup>
</Project>

View File

@@ -8,7 +8,6 @@ using LightlessSync.PlayerData.Handlers;
using LightlessSync.Services;
using LightlessSync.Services.Mediator;
using Microsoft.Extensions.Logging;
using CharacterData = LightlessSync.PlayerData.Data.CharacterData;
namespace LightlessSync.PlayerData.Factories;

View File

@@ -119,6 +119,7 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
Mediator.Publish(new EventMessage(new Event(PlayerName, Pair.UserData, nameof(PairHandler),
EventSeverity.Informational, text)));
Mediator.Publish(new RefreshUiMessage());
Mediator.Publish(new VisibilityChange());
}
}
}

View File

@@ -48,6 +48,7 @@ public class Pair
public long LastAppliedDataTris { get; set; } = -1;
public long LastAppliedApproximateVRAMBytes { get; set; } = -1;
public string Ident => _onlineUserIdentDto?.Ident ?? string.Empty;
public uint PlayerCharacterId => CachedPlayer?.PlayerCharacterId ?? uint.MaxValue;
public UserData UserData => UserPair.User;
@@ -71,8 +72,8 @@ public class Pair
Name = openProfileSeString,
OnClicked = (a) => _mediator.Publish(new ProfileOpenStandaloneMessage(this)),
UseDefaultPrefix = false,
PrefixChar = 'M',
PrefixColor = 526
PrefixChar = 'L',
PrefixColor = 708
});
args.AddMenuItem(new MenuItem()
@@ -80,8 +81,8 @@ public class Pair
Name = reapplyDataSeString,
OnClicked = (a) => ApplyLastReceivedData(forced: true),
UseDefaultPrefix = false,
PrefixChar = 'M',
PrefixColor = 526
PrefixChar = 'L',
PrefixColor = 708
});
args.AddMenuItem(new MenuItem()
@@ -89,8 +90,8 @@ public class Pair
Name = changePermissions,
OnClicked = (a) => _mediator.Publish(new OpenPermissionWindow(this)),
UseDefaultPrefix = false,
PrefixChar = 'M',
PrefixColor = 526
PrefixChar = 'L',
PrefixColor = 708
});
args.AddMenuItem(new MenuItem()
@@ -98,8 +99,8 @@ public class Pair
Name = cyclePauseState,
OnClicked = (a) => _mediator.Publish(new CyclePauseMessage(UserData)),
UseDefaultPrefix = false,
PrefixChar = 'M',
PrefixColor = 526
PrefixChar = 'L',
PrefixColor = 708
});
}

View File

@@ -1,4 +1,5 @@
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Interface.ImGuiFileDialog;
using Dalamud.Interface.Windowing;
using Dalamud.Plugin;
@@ -12,6 +13,7 @@ using LightlessSync.PlayerData.Factories;
using LightlessSync.PlayerData.Pairs;
using LightlessSync.PlayerData.Services;
using LightlessSync.Services;
using LightlessSync.Services.CharaData;
using LightlessSync.Services.Events;
using LightlessSync.Services.Mediator;
using LightlessSync.Services.ServerConfiguration;
@@ -28,8 +30,6 @@ using Microsoft.Extensions.Logging;
using NReco.Logging.File;
using System.Net.Http.Headers;
using System.Reflection;
using LightlessSync.Services.CharaData;
using Dalamud.Game;
namespace LightlessSync;
@@ -41,7 +41,7 @@ public sealed class Plugin : IDalamudPlugin
IFramework framework, IObjectTable objectTable, IClientState clientState, ICondition condition, IChatGui chatGui,
IGameGui gameGui, IDtrBar dtrBar, IPluginLog pluginLog, ITargetManager targetManager, INotificationManager notificationManager,
ITextureProvider textureProvider, IContextMenu contextMenu, IGameInteropProvider gameInteropProvider, IGameConfig gameConfig,
ISigScanner sigScanner)
ISigScanner sigScanner, INamePlateGui namePlateGui)
{
if (!Directory.Exists(pluginInterface.ConfigDirectory.FullName))
Directory.CreateDirectory(pluginInterface.ConfigDirectory.FullName);
@@ -130,6 +130,7 @@ public sealed class Plugin : IDalamudPlugin
s.GetRequiredService<CharaDataManager>(),
s.GetRequiredService<LightlessMediator>()));
collection.AddSingleton<SelectPairForTagUi>();
collection.AddSingleton<RenameTagUi>();
collection.AddSingleton((s) => new EventAggregator(pluginInterface.ConfigDirectory.FullName,
s.GetRequiredService<ILogger<EventAggregator>>(), s.GetRequiredService<LightlessMediator>()));
collection.AddSingleton((s) => new DalamudUtilService(s.GetRequiredService<ILogger<DalamudUtilService>>(),
@@ -228,6 +229,8 @@ public sealed class Plugin : IDalamudPlugin
s.GetRequiredService<CacheMonitor>(), s.GetRequiredService<FileDialogManager>(), s.GetRequiredService<LightlessConfigService>(), s.GetRequiredService<DalamudUtilService>(),
pluginInterface, textureProvider, s.GetRequiredService<Dalamud.Localization>(), s.GetRequiredService<ServerConfigurationManager>(), s.GetRequiredService<TokenProvider>(),
s.GetRequiredService<LightlessMediator>()));
collection.AddScoped((s) => new NameplateService(s.GetRequiredService<ILogger<NameplateService>>(), s.GetRequiredService<LightlessConfigService>(), namePlateGui, clientState,
s.GetRequiredService<PairManager>(), s.GetRequiredService<LightlessMediator>()));
collection.AddHostedService(p => p.GetRequiredService<ConfigurationSaveService>());
collection.AddHostedService(p => p.GetRequiredService<LightlessMediator>());

View File

@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LightlessSync.Services.CharaData
namespace LightlessSync.Services.CharaData
{
internal class CharaDataTogetherManager
{

View File

@@ -1,6 +1,6 @@
using Dalamud.Utility;
using Lumina.Excel.Sheets;
using LightlessSync.API.Dto.CharaData;
using Lumina.Excel.Sheets;
using System.Globalization;
using System.Numerics;
using System.Text;

View File

@@ -1,10 +1,10 @@
using Lumina.Data.Files;
using LightlessSync.API.Data;
using LightlessSync.API.Data;
using LightlessSync.API.Data.Enum;
using LightlessSync.FileCache;
using LightlessSync.Services.Mediator;
using LightlessSync.UI;
using LightlessSync.Utils;
using Lumina.Data.Files;
using Microsoft.Extensions.Logging;
namespace LightlessSync.Services;

View File

@@ -1,5 +1,4 @@
using Dalamud.Game;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.ClientState.Objects.Types;
@@ -10,13 +9,13 @@ using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.Game.Control;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using Lumina.Excel.Sheets;
using LightlessSync.API.Dto.CharaData;
using LightlessSync.Interop;
using LightlessSync.LightlessConfiguration;
using LightlessSync.PlayerData.Handlers;
using LightlessSync.Services.Mediator;
using LightlessSync.Utils;
using Lumina.Excel.Sheets;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.Numerics;
@@ -135,7 +134,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber
_cid = RebuildCID();
}
private Lazy<ulong> RebuildCID() => new(GetCID);
private Lazy<ulong> RebuildCID() => new(GetCID);
public bool IsWine { get; init; }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -93,5 +93,7 @@ public record GPoseLobbyReceiveCharaData(CharaDataDownloadDto CharaDataDownloadD
public record GPoseLobbyReceivePoseData(UserData UserData, PoseData PoseData) : MessageBase;
public record GPoseLobbyReceiveWorldData(UserData UserData, WorldData WorldData) : MessageBase;
public record OpenCharaDataHubWithFilterMessage(UserData UserData) : MessageBase;
public record VisibilityChange : MessageBase;
#pragma warning restore S2094
#pragma warning restore MA0048 // File name must match type name

View File

@@ -0,0 +1,91 @@
using Dalamud.Game.ClientState.Objects.Enums;
using Dalamud.Game.Gui.NamePlate;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Plugin.Services;
using Dalamud.Utility;
using LightlessSync.LightlessConfiguration;
using LightlessSync.PlayerData.Pairs;
using LightlessSync.Services.Mediator;
using LightlessSync.UI;
using Microsoft.Extensions.Logging;
namespace LightlessSync.Services;
public class NameplateService : DisposableMediatorSubscriberBase
{
private readonly LightlessConfigService _configService;
private readonly IClientState _clientState;
private readonly INamePlateGui _namePlateGui;
private readonly PairManager _pairManager;
public NameplateService(ILogger<NameplateService> logger,
LightlessConfigService configService,
INamePlateGui namePlateGui,
IClientState clientState,
PairManager pairManager,
LightlessMediator lightlessMediator) : base(logger, lightlessMediator)
{
_configService = configService;
_namePlateGui = namePlateGui;
_clientState = clientState;
_pairManager = pairManager;
_namePlateGui.OnNamePlateUpdate += OnNamePlateUpdate;
_namePlateGui.RequestRedraw();
Mediator.Subscribe<VisibilityChange>(this, (_) => _namePlateGui.RequestRedraw());
}
private void OnNamePlateUpdate(INamePlateUpdateContext context, IReadOnlyList<INamePlateUpdateHandler> handlers)
{
if (!_configService.Current.IsNameplateColorsEnabled && !_clientState.IsPvPExcludingDen) return;
var visibleUsersIds = _pairManager.GetOnlineUserPairs().Where(u => u.IsVisible && u.PlayerCharacterId != uint.MaxValue).Select(u => (ulong)u.PlayerCharacterId).ToHashSet();
var colors = _configService.Current.NameplateColors;
foreach (var handler in handlers)
{
var playerCharacter = handler.PlayerCharacter;
if (playerCharacter == null) { continue; }
var isInParty = playerCharacter.StatusFlags.HasFlag(StatusFlags.PartyMember);
var isFriend = playerCharacter.StatusFlags.HasFlag(StatusFlags.Friend);
bool partyColorAllowed = (_configService.Current.overridePartyColor && isInParty);
bool friendColorAllowed = (_configService.Current.overrideFriendColor && isFriend);
if (visibleUsersIds.Contains(handler.GameObjectId) &&
!(
(isInParty && !partyColorAllowed) ||
(isFriend && !friendColorAllowed)
))
{
handler.NameParts.TextWrap = CreateTextWrap(colors);
}
}
}
public void RequestRedraw()
{
_namePlateGui.RequestRedraw();
}
private static (SeString, SeString) CreateTextWrap(DtrEntry.Colors color)
{
var left = new Lumina.Text.SeStringBuilder();
var right = new Lumina.Text.SeStringBuilder();
left.PushColorRgba(color.Foreground);
right.PopColor();
left.PushEdgeColorRgba(color.Glow);
right.PopEdgeColor();
return (left.ToReadOnlySeString().ToDalamudString(), right.ToReadOnlySeString().ToDalamudString());
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
_namePlateGui.OnNamePlateUpdate -= OnNamePlateUpdate;
_namePlateGui.RequestRedraw();
}
}

View File

@@ -8,187 +8,187 @@ namespace LightlessSync.UI;
internal sealed partial class CharaDataHubUi
{
private static string GetAccessTypeString(AccessTypeDto dto) => dto switch
{
AccessTypeDto.AllPairs => "All Pairs",
AccessTypeDto.ClosePairs => "Direct Pairs",
AccessTypeDto.Individuals => "Specified",
AccessTypeDto.Public => "Everyone"
};
private static string GetAccessTypeString(AccessTypeDto dto) => dto switch
{
AccessTypeDto.AllPairs => "All Pairs",
AccessTypeDto.ClosePairs => "Direct Pairs",
AccessTypeDto.Individuals => "Specified",
AccessTypeDto.Public => "Everyone"
};
private static string GetShareTypeString(ShareTypeDto dto) => dto switch
{
ShareTypeDto.Private => "Code Only",
ShareTypeDto.Shared => "Shared"
};
private static string GetShareTypeString(ShareTypeDto dto) => dto switch
{
ShareTypeDto.Private => "Code Only",
ShareTypeDto.Shared => "Shared"
};
private static string GetWorldDataTooltipText(PoseEntryExtended poseEntry)
{
if (!poseEntry.HasWorldData) return "This Pose has no world data attached.";
return poseEntry.WorldDataDescriptor;
}
private static string GetWorldDataTooltipText(PoseEntryExtended poseEntry)
{
if (!poseEntry.HasWorldData) return "This Pose has no world data attached.";
return poseEntry.WorldDataDescriptor;
}
private void GposeMetaInfoAction(Action<CharaDataMetaInfoExtendedDto?> gposeActionDraw, string actionDescription, CharaDataMetaInfoExtendedDto? dto, bool hasValidGposeTarget, bool isSpawning)
{
StringBuilder sb = new StringBuilder();
private void GposeMetaInfoAction(Action<CharaDataMetaInfoExtendedDto?> gposeActionDraw, string actionDescription, CharaDataMetaInfoExtendedDto? dto, bool hasValidGposeTarget, bool isSpawning)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(actionDescription);
bool isDisabled = false;
sb.AppendLine(actionDescription);
bool isDisabled = false;
void AddErrorStart(StringBuilder sb)
{
sb.Append(UiSharedService.TooltipSeparator);
sb.AppendLine("Cannot execute:");
}
void AddErrorStart(StringBuilder sb)
{
sb.Append(UiSharedService.TooltipSeparator);
sb.AppendLine("Cannot execute:");
}
if (dto == null)
{
if (!isDisabled) AddErrorStart(sb);
sb.AppendLine("- No metainfo present");
isDisabled = true;
}
if (!dto?.CanBeDownloaded ?? false)
{
if (!isDisabled) AddErrorStart(sb);
sb.AppendLine("- Character is not downloadable");
isDisabled = true;
}
if (!_uiSharedService.IsInGpose)
{
if (!isDisabled) AddErrorStart(sb);
sb.AppendLine("- Requires to be in GPose");
isDisabled = true;
}
if (!hasValidGposeTarget && !isSpawning)
{
if (!isDisabled) AddErrorStart(sb);
sb.AppendLine("- Requires a valid GPose target");
isDisabled = true;
}
if (isSpawning && !_charaDataManager.BrioAvailable)
{
if (!isDisabled) AddErrorStart(sb);
sb.AppendLine("- Requires Brio to be installed.");
isDisabled = true;
}
if (dto == null)
{
if (!isDisabled) AddErrorStart(sb);
sb.AppendLine("- No metainfo present");
isDisabled = true;
}
if (!dto?.CanBeDownloaded ?? false)
{
if (!isDisabled) AddErrorStart(sb);
sb.AppendLine("- Character is not downloadable");
isDisabled = true;
}
if (!_uiSharedService.IsInGpose)
{
if (!isDisabled) AddErrorStart(sb);
sb.AppendLine("- Requires to be in GPose");
isDisabled = true;
}
if (!hasValidGposeTarget && !isSpawning)
{
if (!isDisabled) AddErrorStart(sb);
sb.AppendLine("- Requires a valid GPose target");
isDisabled = true;
}
if (isSpawning && !_charaDataManager.BrioAvailable)
{
if (!isDisabled) AddErrorStart(sb);
sb.AppendLine("- Requires Brio to be installed.");
isDisabled = true;
}
using (ImRaii.Group())
{
using var dis = ImRaii.Disabled(isDisabled);
gposeActionDraw.Invoke(dto);
}
if (sb.Length > 0)
{
UiSharedService.AttachToolTip(sb.ToString());
}
}
using (ImRaii.Group())
{
using var dis = ImRaii.Disabled(isDisabled);
gposeActionDraw.Invoke(dto);
}
if (sb.Length > 0)
{
UiSharedService.AttachToolTip(sb.ToString());
}
}
private void GposePoseAction(Action poseActionDraw, string poseDescription, bool hasValidGposeTarget)
{
StringBuilder sb = new StringBuilder();
private void GposePoseAction(Action poseActionDraw, string poseDescription, bool hasValidGposeTarget)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(poseDescription);
bool isDisabled = false;
sb.AppendLine(poseDescription);
bool isDisabled = false;
void AddErrorStart(StringBuilder sb)
{
sb.Append(UiSharedService.TooltipSeparator);
sb.AppendLine("Cannot execute:");
}
void AddErrorStart(StringBuilder sb)
{
sb.Append(UiSharedService.TooltipSeparator);
sb.AppendLine("Cannot execute:");
}
if (!_uiSharedService.IsInGpose)
{
if (!isDisabled) AddErrorStart(sb);
sb.AppendLine("- Requires to be in GPose");
isDisabled = true;
}
if (!hasValidGposeTarget)
{
if (!isDisabled) AddErrorStart(sb);
sb.AppendLine("- Requires a valid GPose target");
isDisabled = true;
}
if (!_charaDataManager.BrioAvailable)
{
if (!isDisabled) AddErrorStart(sb);
sb.AppendLine("- Requires Brio to be installed.");
isDisabled = true;
}
if (!_uiSharedService.IsInGpose)
{
if (!isDisabled) AddErrorStart(sb);
sb.AppendLine("- Requires to be in GPose");
isDisabled = true;
}
if (!hasValidGposeTarget)
{
if (!isDisabled) AddErrorStart(sb);
sb.AppendLine("- Requires a valid GPose target");
isDisabled = true;
}
if (!_charaDataManager.BrioAvailable)
{
if (!isDisabled) AddErrorStart(sb);
sb.AppendLine("- Requires Brio to be installed.");
isDisabled = true;
}
using (ImRaii.Group())
{
using var dis = ImRaii.Disabled(isDisabled);
poseActionDraw.Invoke();
}
if (sb.Length > 0)
{
UiSharedService.AttachToolTip(sb.ToString());
}
}
using (ImRaii.Group())
{
using var dis = ImRaii.Disabled(isDisabled);
poseActionDraw.Invoke();
}
if (sb.Length > 0)
{
UiSharedService.AttachToolTip(sb.ToString());
}
}
private void SetWindowSizeConstraints(bool? inGposeTab = null)
{
SizeConstraints = new()
{
MinimumSize = new((inGposeTab ?? false) ? 400 : 1000, 500),
MaximumSize = new((inGposeTab ?? false) ? 400 : 1000, 2000)
};
}
private void SetWindowSizeConstraints(bool? inGposeTab = null)
{
SizeConstraints = new()
{
MinimumSize = new((inGposeTab ?? false) ? 400 : 1000, 500),
MaximumSize = new((inGposeTab ?? false) ? 400 : 1000, 2000)
};
}
private void UpdateFilteredFavorites()
{
_ = Task.Run(async () =>
{
if (_charaDataManager.DownloadMetaInfoTask != null)
{
await _charaDataManager.DownloadMetaInfoTask.ConfigureAwait(false);
}
Dictionary<string, (CharaDataFavorite, CharaDataMetaInfoExtendedDto?, bool)> newFiltered = [];
foreach (var favorite in _configService.Current.FavoriteCodes)
{
var uid = favorite.Key.Split(":")[0];
var note = _serverConfigurationManager.GetNoteForUid(uid) ?? string.Empty;
bool hasMetaInfo = _charaDataManager.TryGetMetaInfo(favorite.Key, out var metaInfo);
bool addFavorite =
(string.IsNullOrEmpty(_filterCodeNote)
|| (note.Contains(_filterCodeNote, StringComparison.OrdinalIgnoreCase)
|| uid.Contains(_filterCodeNote, StringComparison.OrdinalIgnoreCase)))
&& (string.IsNullOrEmpty(_filterDescription)
|| (favorite.Value.CustomDescription.Contains(_filterDescription, StringComparison.OrdinalIgnoreCase)
|| (metaInfo != null && metaInfo!.Description.Contains(_filterDescription, StringComparison.OrdinalIgnoreCase))))
&& (!_filterPoseOnly
|| (metaInfo != null && metaInfo!.HasPoses))
&& (!_filterWorldOnly
|| (metaInfo != null && metaInfo!.HasWorldData));
if (addFavorite)
{
newFiltered[favorite.Key] = (favorite.Value, metaInfo, hasMetaInfo);
}
}
private void UpdateFilteredFavorites()
{
_ = Task.Run(async () =>
{
if (_charaDataManager.DownloadMetaInfoTask != null)
{
await _charaDataManager.DownloadMetaInfoTask.ConfigureAwait(false);
}
Dictionary<string, (CharaDataFavorite, CharaDataMetaInfoExtendedDto?, bool)> newFiltered = [];
foreach (var favorite in _configService.Current.FavoriteCodes)
{
var uid = favorite.Key.Split(":")[0];
var note = _serverConfigurationManager.GetNoteForUid(uid) ?? string.Empty;
bool hasMetaInfo = _charaDataManager.TryGetMetaInfo(favorite.Key, out var metaInfo);
bool addFavorite =
(string.IsNullOrEmpty(_filterCodeNote)
|| (note.Contains(_filterCodeNote, StringComparison.OrdinalIgnoreCase)
|| uid.Contains(_filterCodeNote, StringComparison.OrdinalIgnoreCase)))
&& (string.IsNullOrEmpty(_filterDescription)
|| (favorite.Value.CustomDescription.Contains(_filterDescription, StringComparison.OrdinalIgnoreCase)
|| (metaInfo != null && metaInfo!.Description.Contains(_filterDescription, StringComparison.OrdinalIgnoreCase))))
&& (!_filterPoseOnly
|| (metaInfo != null && metaInfo!.HasPoses))
&& (!_filterWorldOnly
|| (metaInfo != null && metaInfo!.HasWorldData));
if (addFavorite)
{
newFiltered[favorite.Key] = (favorite.Value, metaInfo, hasMetaInfo);
}
}
_filteredFavorites = newFiltered;
});
}
_filteredFavorites = newFiltered;
});
}
private void UpdateFilteredItems()
{
if (_charaDataManager.GetSharedWithYouTask == null)
{
_filteredDict = _charaDataManager.SharedWithYouData
.SelectMany(k => k.Value)
.Where(k =>
(!_sharedWithYouDownloadableFilter || k.CanBeDownloaded)
&& (string.IsNullOrEmpty(_sharedWithYouDescriptionFilter) || k.Description.Contains(_sharedWithYouDescriptionFilter, StringComparison.OrdinalIgnoreCase)))
.GroupBy(k => k.Uploader)
.ToDictionary(k =>
{
var note = _serverConfigurationManager.GetNoteForUid(k.Key.UID);
if (note == null) return k.Key.AliasOrUID;
return $"{note} ({k.Key.AliasOrUID})";
}, k => k.ToList(), StringComparer.OrdinalIgnoreCase)
.Where(k => (string.IsNullOrEmpty(_sharedWithYouOwnerFilter) || k.Key.Contains(_sharedWithYouOwnerFilter, StringComparison.OrdinalIgnoreCase)))
.OrderBy(k => k.Key, StringComparer.OrdinalIgnoreCase).ToDictionary();
}
}
private void UpdateFilteredItems()
{
if (_charaDataManager.GetSharedWithYouTask == null)
{
_filteredDict = _charaDataManager.SharedWithYouData
.SelectMany(k => k.Value)
.Where(k =>
(!_sharedWithYouDownloadableFilter || k.CanBeDownloaded)
&& (string.IsNullOrEmpty(_sharedWithYouDescriptionFilter) || k.Description.Contains(_sharedWithYouDescriptionFilter, StringComparison.OrdinalIgnoreCase)))
.GroupBy(k => k.Uploader)
.ToDictionary(k =>
{
var note = _serverConfigurationManager.GetNoteForUid(k.Key.UID);
if (note == null) return k.Key.AliasOrUID;
return $"{note} ({k.Key.AliasOrUID})";
}, k => k.ToList(), StringComparer.OrdinalIgnoreCase)
.Where(k => (string.IsNullOrEmpty(_sharedWithYouOwnerFilter) || k.Key.Contains(_sharedWithYouOwnerFilter, StringComparison.OrdinalIgnoreCase)))
.OrderBy(k => k.Key, StringComparer.OrdinalIgnoreCase).ToDictionary();
}
}
}

View File

@@ -63,7 +63,7 @@ internal sealed partial class CharaDataHubUi
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted("GPose Lobby");
ImGui.SameLine();
UiSharedService.ColorTextWrapped(_charaDataGposeTogetherManager.CurrentGPoseLobbyId, ImGuiColors.ParsedGreen);
UiSharedService.ColorTextWrapped(_charaDataGposeTogetherManager.CurrentGPoseLobbyId, UIColors.Get("LightlessBlue"));
ImGui.SameLine();
if (_uiSharedService.IconButton(FontAwesomeIcon.Clipboard))
{
@@ -130,7 +130,7 @@ internal sealed partial class CharaDataHubUi
ImGui.AlignTextToFramePadding();
var note = _serverConfigurationManager.GetNoteForUid(user.UserData.UID);
var userText = note == null ? user.UserData.AliasOrUID : $"{note} ({user.UserData.AliasOrUID})";
UiSharedService.ColorText(userText, ImGuiColors.ParsedGreen);
UiSharedService.ColorText(userText, UIColors.Get("LightlessBlue"));
var buttonsize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.ArrowRight).X;
var buttonsize2 = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Plus).X;
@@ -165,7 +165,7 @@ internal sealed partial class CharaDataHubUi
UiSharedService.AttachToolTip(user.WorldDataDescriptor + UiSharedService.TooltipSeparator);
ImGui.SameLine();
_uiSharedService.IconText(FontAwesomeIcon.Map, sameMapAndServer.SameMap ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed);
_uiSharedService.IconText(FontAwesomeIcon.Map, sameMapAndServer.SameMap ? UIColors.Get("LightlessBlue") : ImGuiColors.DalamudRed);
if (ImGui.IsItemClicked(ImGuiMouseButton.Left) && user.WorldData != null)
{
_dalamudUtilService.SetMarkerAndOpenMap(new(user.WorldData.Value.PositionX, user.WorldData.Value.PositionY, user.WorldData.Value.PositionZ), user.Map);
@@ -175,12 +175,12 @@ internal sealed partial class CharaDataHubUi
+ "Note: For GPose synchronization to work properly, you must be on the same map.");
ImGui.SameLine();
_uiSharedService.IconText(FontAwesomeIcon.Globe, sameMapAndServer.SameServer ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed);
_uiSharedService.IconText(FontAwesomeIcon.Globe, sameMapAndServer.SameServer ? UIColors.Get("LightlessBlue") : ImGuiColors.DalamudRed);
UiSharedService.AttachToolTip((sameMapAndServer.SameMap ? "You are on the same server." : "You are not on the same server.") + UiSharedService.TooltipSeparator
+ "Note: GPose synchronization is not dependent on the current server, but you will have to spawn a character for the other lobby users.");
ImGui.SameLine();
_uiSharedService.IconText(FontAwesomeIcon.Running, sameMapAndServer.SameEverything ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed);
_uiSharedService.IconText(FontAwesomeIcon.Running, sameMapAndServer.SameEverything ? UIColors.Get("LightlessBlue") : ImGuiColors.DalamudRed);
UiSharedService.AttachToolTip(sameMapAndServer.SameEverything ? "You are in the same instanced area." : "You are not the same instanced area." + UiSharedService.TooltipSeparator +
"Note: Users not in your instance, but on the same map, will be drawn as floating wisps." + Environment.NewLine
+ "Note: GPose synchronization is not dependent on the current instance, but you will have to spawn a character for the other lobby users.");

View File

@@ -1,8 +1,8 @@
using Dalamud.Bindings.ImGui;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Interface.Utility;
using Dalamud.Interface;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using LightlessSync.API.Dto.CharaData;
using LightlessSync.Services.CharaData.Models;
using System.Numerics;
@@ -241,7 +241,7 @@ internal sealed partial class CharaDataHubUi
ImGui.SameLine(pos);
if (!dataDto.HasMissingFiles)
{
UiSharedService.ColorTextWrapped("All files to download this character data are present on the server", ImGuiColors.HealerGreen);
UiSharedService.ColorTextWrapped("All files to download this character data are present on the server", UIColors.Get("LightlessBlue"));
}
else
{
@@ -769,7 +769,7 @@ internal sealed partial class CharaDataHubUi
}
else if (_charaDataManager.DataCreationTask != null && _charaDataManager.DataCreationTask.IsCompleted)
{
var color = _charaDataManager.DataCreationTask.Result.Success ? ImGuiColors.HealerGreen : ImGuiColors.DalamudRed;
var color = _charaDataManager.DataCreationTask.Result.Success ? UIColors.Get("LightlessBlue") : ImGuiColors.DalamudRed;
UiSharedService.ColorTextWrapped(_charaDataManager.DataCreationTask.Result.Output, color);
}

View File

@@ -1,8 +1,8 @@
using Dalamud.Bindings.ImGui;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Interface.Utility;
using Dalamud.Interface;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using System.Numerics;
namespace LightlessSync.UI;
@@ -112,7 +112,7 @@ internal partial class CharaDataHubUi
var noteText = pose.Key.MetaInfo.IsOwnData ? "YOU" : (userNote == null ? pose.Key.MetaInfo.Uploader.AliasOrUID : $"{userNote} ({pose.Key.MetaInfo.Uploader.AliasOrUID})");
ImGui.TextUnformatted("Pose by");
ImGui.SameLine();
UiSharedService.ColorText(noteText, ImGuiColors.ParsedGreen);
UiSharedService.ColorText(noteText, UIColors.Get("LightlessBlue"));
using (ImRaii.Group())
{
UiSharedService.ColorText("Character Data Description", ImGuiColors.DalamudGrey);
@@ -176,7 +176,7 @@ internal partial class CharaDataHubUi
Vector2 coneBase2 = circleCenter + baseDir2 * circleRadius;
// Draw the cone as a filled triangle
drawList.AddTriangleFilled(circleCenter, coneBase1, coneBase2, UiSharedService.Color(ImGuiColors.ParsedGreen));
drawList.AddTriangleFilled(circleCenter, coneBase1, coneBase2, UiSharedService.Color(UIColors.Get("LightlessBlue")));
drawList.AddCircle(circleCenter, circleDiameter / 2, UiSharedService.Color(ImGuiColors.DalamudWhite), 360, 2);
var distance = pose.Value.Distance.ToString("0.0") + "y";
var textSize = ImGui.CalcTextSize(distance);

View File

@@ -383,7 +383,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
UiSharedService.AttachToolTip($"Target the GPose Character {CharaName(actor.Name.TextValue)}");
ImGui.AlignTextToFramePadding();
var pos = ImGui.GetCursorPosX();
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.HealerGreen, actor.Address == (_dalamudUtilService.GetGposeTargetGameObjectAsync().GetAwaiter().GetResult()?.Address ?? nint.Zero)))
using (ImRaii.PushColor(ImGuiCol.Text, UIColors.Get("LightlessBlue"), actor.Address == (_dalamudUtilService.GetGposeTargetGameObjectAsync().GetAwaiter().GetResult()?.Address ?? nint.Zero)))
{
ImGui.TextUnformatted(CharaName(actor.Name.TextValue));
}

View File

@@ -38,6 +38,7 @@ public class CompactUi : WindowMediatorSubscriberBase
private readonly PairManager _pairManager;
private readonly SelectTagForPairUi _selectGroupForPairUi;
private readonly SelectPairForTagUi _selectPairsForGroupUi;
private readonly RenameTagUi _renameTagUi;
private readonly IpcManager _ipcManager;
private readonly ServerConfigurationManager _serverManager;
private readonly TopTabMenu _tabMenu;
@@ -56,7 +57,7 @@ public class CompactUi : WindowMediatorSubscriberBase
public CompactUi(ILogger<CompactUi> logger, UiSharedService uiShared, LightlessConfigService configService, ApiController apiController, PairManager pairManager,
ServerConfigurationManager serverManager, LightlessMediator mediator, FileUploadManager fileTransferManager,
TagHandler tagHandler, DrawEntityFactory drawEntityFactory, SelectTagForPairUi selectTagForPairUi, SelectPairForTagUi selectPairForTagUi,
TagHandler tagHandler, DrawEntityFactory drawEntityFactory, SelectTagForPairUi selectTagForPairUi, SelectPairForTagUi selectPairForTagUi, RenameTagUi renameTagUi,
PerformanceCollectorService performanceCollectorService, IpcManager ipcManager)
: base(logger, mediator, "###LightlessSyncMainUI", performanceCollectorService)
{
@@ -70,6 +71,7 @@ public class CompactUi : WindowMediatorSubscriberBase
_drawEntityFactory = drawEntityFactory;
_selectGroupForPairUi = selectTagForPairUi;
_selectPairsForGroupUi = selectPairForTagUi;
_renameTagUi = renameTagUi;
_ipcManager = ipcManager;
_tabMenu = new TopTabMenu(Mediator, _apiController, _pairManager, _uiSharedService);
@@ -149,10 +151,10 @@ public class CompactUi : WindowMediatorSubscriberBase
var uidTextSize = ImGui.CalcTextSize(unsupported);
ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMax().X + ImGui.GetWindowContentRegionMin().X) / 2 - uidTextSize.X / 2);
ImGui.AlignTextToFramePadding();
ImGui.TextColored(ImGuiColors.DalamudRed, unsupported);
ImGui.TextColored(UIColors.Get("DimRed"), unsupported);
}
UiSharedService.ColorTextWrapped($"Your Lightless Sync installation is out of date, the current version is {ver.Major}.{ver.Minor}.{ver.Build}. " +
$"It is highly recommended to keep Lightless Sync up to date. Open /xlplugins and update the plugin.", ImGuiColors.DalamudRed);
$"It is highly recommended to keep Lightless Sync up to date. Open /xlplugins and update the plugin.", UIColors.Get("DimRed"));
}
if (!_ipcManager.Initialized)
@@ -164,12 +166,12 @@ public class CompactUi : WindowMediatorSubscriberBase
var uidTextSize = ImGui.CalcTextSize(unsupported);
ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMax().X + ImGui.GetWindowContentRegionMin().X) / 2 - uidTextSize.X / 2);
ImGui.AlignTextToFramePadding();
ImGui.TextColored(ImGuiColors.DalamudRed, unsupported);
ImGui.TextColored(UIColors.Get("DimRed"), unsupported);
}
var penumAvailable = _ipcManager.Penumbra.APIAvailable;
var glamAvailable = _ipcManager.Glamourer.APIAvailable;
UiSharedService.ColorTextWrapped($"One or more Plugins essential for Lightless operation are unavailable. Enable or update following plugins:", ImGuiColors.DalamudRed);
UiSharedService.ColorTextWrapped($"One or more Plugins essential for Lightless operation are unavailable. Enable or update following plugins:", UIColors.Get("DimRed"));
using var indent = ImRaii.PushIndent(10f);
if (!penumAvailable)
{
@@ -185,7 +187,7 @@ public class CompactUi : WindowMediatorSubscriberBase
}
using (ImRaii.PushId("header")) DrawUIDHeader();
ImGui.Separator();
_uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 2f);
using (ImRaii.PushId("serverstatus")) DrawServerStatus();
ImGui.Separator();
@@ -198,6 +200,7 @@ public class CompactUi : WindowMediatorSubscriberBase
using (ImRaii.PushId("transfers")) DrawTransfers();
_transferPartHeight = ImGui.GetCursorPosY() - pairlistEnd - ImGui.GetTextLineHeight();
using (ImRaii.PushId("group-user-popup")) _selectPairsForGroupUi.Draw(_pairManager.DirectPairs);
using (ImRaii.PushId("group-user-edit")) _renameTagUi.Draw(_pairManager.DirectPairs);
using (ImRaii.PushId("grouping-popup")) _selectGroupForPairUi.Draw();
}
@@ -276,7 +279,7 @@ public class CompactUi : WindowMediatorSubscriberBase
{
ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth()) / 2 - (userSize.X + textSize.X) / 2 - ImGui.GetStyle().ItemSpacing.X / 2);
if (!printShard) ImGui.AlignTextToFramePadding();
ImGui.TextColored(ImGuiColors.ParsedGreen, userCount);
ImGui.TextColored(UIColors.Get("LightlessPurple"), userCount);
ImGui.SameLine();
if (!printShard) ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted("Users Online");
@@ -284,7 +287,7 @@ public class CompactUi : WindowMediatorSubscriberBase
else
{
ImGui.AlignTextToFramePadding();
ImGui.TextColored(ImGuiColors.DalamudRed, "Not connected to any server");
ImGui.TextColored(UIColors.Get("DimRed"), "Not connected to any server");
}
if (printShard)
@@ -587,21 +590,21 @@ public class CompactUi : WindowMediatorSubscriberBase
{
return _apiController.ServerState switch
{
ServerState.Connecting => ImGuiColors.DalamudYellow,
ServerState.Reconnecting => ImGuiColors.DalamudRed,
ServerState.Connected => ImGuiColors.ParsedGreen,
ServerState.Disconnected => ImGuiColors.DalamudYellow,
ServerState.Disconnecting => ImGuiColors.DalamudYellow,
ServerState.Unauthorized => ImGuiColors.DalamudRed,
ServerState.VersionMisMatch => ImGuiColors.DalamudRed,
ServerState.Offline => ImGuiColors.DalamudRed,
ServerState.RateLimited => ImGuiColors.DalamudYellow,
ServerState.NoSecretKey => ImGuiColors.DalamudYellow,
ServerState.MultiChara => ImGuiColors.DalamudYellow,
ServerState.OAuthMisconfigured => ImGuiColors.DalamudRed,
ServerState.OAuthLoginTokenStale => ImGuiColors.DalamudRed,
ServerState.NoAutoLogon => ImGuiColors.DalamudYellow,
_ => ImGuiColors.DalamudRed
ServerState.Connecting => UIColors.Get("LightlessYellow"),
ServerState.Reconnecting => UIColors.Get("DimRed"),
ServerState.Connected => UIColors.Get("LightlessPurple"),
ServerState.Disconnected => UIColors.Get("LightlessYellow"),
ServerState.Disconnecting => UIColors.Get("LightlessYellow"),
ServerState.Unauthorized => UIColors.Get("DimRed"),
ServerState.VersionMisMatch => UIColors.Get("DimRed"),
ServerState.Offline => UIColors.Get("DimRed"),
ServerState.RateLimited => UIColors.Get("LightlessYellow"),
ServerState.NoSecretKey => UIColors.Get("LightlessYellow"),
ServerState.MultiChara => UIColors.Get("LightlessYellow"),
ServerState.OAuthMisconfigured => UIColors.Get("DimRed"),
ServerState.OAuthLoginTokenStale => UIColors.Get("DimRed"),
ServerState.NoAutoLogon => UIColors.Get("LightlessYellow"),
_ => UIColors.Get("DimRed")
};
}

View File

@@ -13,13 +13,15 @@ public class DrawFolderTag : DrawFolderBase
{
private readonly ApiController _apiController;
private readonly SelectPairForTagUi _selectPairForTagUi;
private readonly RenameTagUi _renameTagUi;
public DrawFolderTag(string id, IImmutableList<DrawUserPair> drawPairs, IImmutableList<Pair> allPairs,
TagHandler tagHandler, ApiController apiController, SelectPairForTagUi selectPairForTagUi, UiSharedService uiSharedService)
TagHandler tagHandler, ApiController apiController, SelectPairForTagUi selectPairForTagUi, RenameTagUi renameTagUi, UiSharedService uiSharedService)
: base(id, drawPairs, allPairs, tagHandler, uiSharedService)
{
_apiController = apiController;
_selectPairForTagUi = selectPairForTagUi;
_renameTagUi = renameTagUi;
}
protected override bool RenderIfEmpty => _id switch
@@ -100,12 +102,15 @@ public class DrawFolderTag : DrawFolderBase
protected override void DrawMenu(float menuWidth)
{
ImGui.TextUnformatted("Group Menu");
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Users, "Select Pairs", menuWidth, true))
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Users, "Select Pairs", menuWidth, isInPopup: true))
{
_selectPairForTagUi.Open(_id);
}
UiSharedService.AttachToolTip("Select Individual Pairs for this Pair Group");
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Delete Pair Group", menuWidth, true) && UiSharedService.CtrlPressed())
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Edit, "Rename Pair Group", menuWidth, isInPopup: true))
{
_renameTagUi.Open(_id);
}
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Delete Pair Group", menuWidth, isInPopup: true) && UiSharedService.CtrlPressed())
{
_tagHandler.RemoveTag(_id);
}

View File

@@ -202,7 +202,7 @@ public class DrawUserPair
}
else if (!_pair.IsOnline)
{
using var _ = ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
using var _ = ImRaii.PushColor(ImGuiCol.Text, UIColors.Get("DimRed"));
_uiSharedService.IconText(_pair.IndividualPairStatus == API.Data.Enum.IndividualPairStatus.OneSided
? FontAwesomeIcon.ArrowsLeftRight
: (_pair.IndividualPairStatus == API.Data.Enum.IndividualPairStatus.Bidirectional
@@ -211,7 +211,7 @@ public class DrawUserPair
}
else if (_pair.IsVisible)
{
_uiSharedService.IconText(FontAwesomeIcon.Eye, ImGuiColors.ParsedGreen);
_uiSharedService.IconText(FontAwesomeIcon.Eye, UIColors.Get("LightlessBlue"));
userPairText = _pair.UserData.AliasOrUID + " is visible: " + _pair.PlayerName + Environment.NewLine + "Click to target this player";
if (ImGui.IsItemClicked())
{
@@ -220,7 +220,7 @@ public class DrawUserPair
}
else
{
using var _ = ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.HealerGreen);
using var _ = ImRaii.PushColor(ImGuiCol.Text, UIColors.Get("PairBlue"));
_uiSharedService.IconText(_pair.IndividualPairStatus == API.Data.Enum.IndividualPairStatus.Bidirectional
? FontAwesomeIcon.User : FontAwesomeIcon.Users);
userPairText = _pair.UserData.AliasOrUID + " is online";

View File

@@ -0,0 +1,93 @@
using Dalamud.Bindings.ImGui;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using LightlessSync.PlayerData.Pairs;
using LightlessSync.UI.Handlers;
using System.Numerics;
namespace LightlessSync.UI.Components;
public class RenameTagUi
{
private readonly TagHandler _tagHandler;
private readonly UiSharedService _uiSharedService;
private string _desiredName = string.Empty;
private bool _opened = false;
private HashSet<string> _peopleInGroup = new(StringComparer.Ordinal);
private bool _show = false;
private string _tag = string.Empty;
public RenameTagUi(TagHandler tagHandler, UiSharedService uiSharedService)
{
_tagHandler = tagHandler;
_uiSharedService = uiSharedService;
}
public void Draw(List<Pair> pairs)
{
var workHeight = ImGui.GetMainViewport().WorkSize.Y / ImGuiHelpers.GlobalScale;
var minSize = new Vector2(300, workHeight < 110 ? workHeight : 110) * ImGuiHelpers.GlobalScale;
var maxSize = new Vector2(300, 110) * ImGuiHelpers.GlobalScale;
var popupName = $"Renaming Group {_tag}";
if (!_show)
{
_opened = false;
}
if (_show && !_opened)
{
ImGui.SetNextWindowSize(minSize);
UiSharedService.CenterNextWindow(minSize.X, minSize.Y, ImGuiCond.Always);
ImGui.OpenPopup(popupName);
_opened = true;
}
ImGui.SetNextWindowSizeConstraints(minSize, maxSize);
if (ImGui.BeginPopupModal(popupName, ref _show, ImGuiWindowFlags.Popup | ImGuiWindowFlags.Modal))
{
ImGui.TextUnformatted($"Renaming {_tag}");
ImGui.InputTextWithHint("##desiredname", "Enter new group name", ref _desiredName, 255, ImGuiInputTextFlags.None);
using (ImRaii.Disabled(string.IsNullOrEmpty(_desiredName)))
{
if (_uiSharedService.IconTextButton(Dalamud.Interface.FontAwesomeIcon.Plus, "Rename Group"))
{
RenameTag(pairs, _tag, _desiredName);
_show = false;
}
}
ImGui.EndPopup();
}
else
{
_show = false;
}
}
public void Open(string tag)
{
_peopleInGroup = _tagHandler.GetOtherUidsForTag(tag);
_tag = tag;
_desiredName = "";
_show = true;
}
public void RenameTag(List<Pair> pairs, string oldTag, string newTag)
{
//Removal of old tag
_tagHandler.RemoveTag(oldTag);
//Creation of new tag and adding of old group pairs in new one.
_tagHandler.AddTag(newTag);
foreach (Pair pair in pairs)
{
var isInTag = _peopleInGroup.Contains(pair.UserData.UID);
if (isInTag)
{
_tagHandler.AddTagToPairedUid(pair.UserData.UID, newTag);
}
}
}
}

View File

@@ -169,7 +169,7 @@ public class DownloadUi : WindowMediatorSubscriberBase
var dlProgressPercent = transferredBytes / (double)totalBytes;
drawList.AddRectFilled(dlBarStart,
dlBarEnd with { X = dlBarStart.X + (float)(dlProgressPercent * dlBarWidth) },
UiSharedService.Color(50, 205, 50, transparency), 1);
UiSharedService.Color(173, 138, 245, transparency), 1);
if (_configService.Current.TransferBarsShowText)
{

View File

@@ -23,11 +23,12 @@ public class DrawEntityFactory
private readonly PlayerPerformanceConfigService _playerPerformanceConfigService;
private readonly CharaDataManager _charaDataManager;
private readonly SelectTagForPairUi _selectTagForPairUi;
private readonly RenameTagUi _renameTagUi;
private readonly TagHandler _tagHandler;
private readonly IdDisplayHandler _uidDisplayHandler;
public DrawEntityFactory(ILogger<DrawEntityFactory> logger, ApiController apiController, IdDisplayHandler uidDisplayHandler,
SelectTagForPairUi selectTagForPairUi, LightlessMediator mediator,
SelectTagForPairUi selectTagForPairUi, RenameTagUi renameTagUi, LightlessMediator mediator,
TagHandler tagHandler, SelectPairForTagUi selectPairForTagUi,
ServerConfigurationManager serverConfigurationManager, UiSharedService uiSharedService,
PlayerPerformanceConfigService playerPerformanceConfigService, CharaDataManager charaDataManager)
@@ -36,6 +37,7 @@ public class DrawEntityFactory
_apiController = apiController;
_uidDisplayHandler = uidDisplayHandler;
_selectTagForPairUi = selectTagForPairUi;
_renameTagUi = renameTagUi;
_mediator = mediator;
_tagHandler = tagHandler;
_selectPairForTagUi = selectPairForTagUi;
@@ -58,8 +60,8 @@ public class DrawEntityFactory
Dictionary<Pair, List<GroupFullInfoDto>> filteredPairs,
IImmutableList<Pair> allPairs)
{
return new(tag, filteredPairs.Select(u => CreateDrawPair(tag, u.Key, u.Value, null)).ToImmutableList(),
allPairs, _tagHandler, _apiController, _selectPairForTagUi, _uiSharedService);
return new(tag, filteredPairs.Select(u => CreateDrawPair(tag, u.Key, u.Value, currentGroup: null)).ToImmutableList(),
allPairs, _tagHandler, _apiController, _selectPairForTagUi, _renameTagUi, _uiSharedService);
}
public DrawUserPair CreateDrawPair(string id, Pair user, List<GroupFullInfoDto> groups, GroupFullInfoDto? currentGroup)

View File

@@ -4,9 +4,9 @@ using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Utility;
using LightlessSync.FileCache;
using LightlessSync.Localization;
using LightlessSync.LightlessConfiguration;
using LightlessSync.LightlessConfiguration.Models;
using LightlessSync.Localization;
using LightlessSync.Services;
using LightlessSync.Services.Mediator;
using LightlessSync.Services.ServerConfiguration;
@@ -308,7 +308,7 @@ public partial class IntroUi : WindowMediatorSubscriberBase
}
else
{
UiSharedService.ColorTextWrapped($"OAuth2 is connected. Linked to: Discord User {_serverConfigurationManager.GetDiscordUserFromToken(selectedServer)}", ImGuiColors.HealerGreen);
UiSharedService.ColorTextWrapped($"OAuth2 is connected. Linked to: Discord User {_serverConfigurationManager.GetDiscordUserFromToken(selectedServer)}", UIColors.Get("LightlessBlue"));
UiSharedService.TextWrapped("Now press the update UIDs button to get a list of all of your UIDs on the server.");
_uiShared.DrawUpdateOAuthUIDsButton(selectedServer);
var playerName = _dalamudUtilService.GetPlayerName();

View File

@@ -25,7 +25,7 @@ internal class JoinSyncshellUI : WindowMediatorSubscriberBase
private string _syncshellPassword = string.Empty;
public JoinSyncshellUI(ILogger<JoinSyncshellUI> logger, LightlessMediator mediator,
UiSharedService uiSharedService, ApiController apiController, PerformanceCollectorService performanceCollectorService)
UiSharedService uiSharedService, ApiController apiController, PerformanceCollectorService performanceCollectorService)
: base(logger, mediator, "Join existing Syncshell###LightlessSyncJoinSyncshell", performanceCollectorService)
{
_uiSharedService = uiSharedService;

View File

@@ -102,7 +102,7 @@ public class PermissionWindowUI : WindowMediatorSubscriberBase
{
_ownPermissions.SetDisableAnimations(disableAnimations);
}
_uiSharedService.DrawHelpText("Disabling sounds will remove all animations synced with this user on both sides." + UiSharedService.TooltipSeparator
_uiSharedService.DrawHelpText("Disabling animations will remove all animations synced with this user on both sides." + UiSharedService.TooltipSeparator
+ "Note: this is bidirectional, either user disabling animation sync will stop animation sync on both sides.");
using (ImRaii.PushIndent(indentSize, false))
{
@@ -116,7 +116,7 @@ public class PermissionWindowUI : WindowMediatorSubscriberBase
{
_ownPermissions.SetDisableVFX(disableVfx);
}
_uiSharedService.DrawHelpText("Disabling sounds will remove all VFX synced with this user on both sides." + UiSharedService.TooltipSeparator
_uiSharedService.DrawHelpText("Disabling VFX will remove all VFX synced with this user on both sides." + UiSharedService.TooltipSeparator
+ "Note: this is bidirectional, either user disabling VFX sync will stop VFX sync on both sides.");
using (ImRaii.PushIndent(indentSize, false))
{

View File

@@ -110,7 +110,7 @@ public class PopoutProfileUi : WindowMediatorSubscriberBase
var rectMax = drawList.GetClipRectMax();
using (_uiSharedService.UidFont.Push())
UiSharedService.ColorText(_pair.UserData.AliasOrUID, ImGuiColors.HealerGreen);
UiSharedService.ColorText(_pair.UserData.AliasOrUID, UIColors.Get("LightlessBlue"));
ImGuiHelpers.ScaledDummy(spacing.Y, spacing.Y);
var textPos = ImGui.GetCursorPosY();
@@ -123,7 +123,7 @@ public class PopoutProfileUi : WindowMediatorSubscriberBase
UiSharedService.ColorText(note, ImGuiColors.DalamudGrey);
}
string status = _pair.IsVisible ? "Visible" : (_pair.IsOnline ? "Online" : "Offline");
UiSharedService.ColorText(status, (_pair.IsVisible || _pair.IsOnline) ? ImGuiColors.HealerGreen : ImGuiColors.DalamudRed);
UiSharedService.ColorText(status, (_pair.IsVisible || _pair.IsOnline) ? UIColors.Get("LightlessBlue") : ImGuiColors.DalamudRed);
if (_pair.IsVisible)
{
ImGui.SameLine();

File diff suppressed because it is too large Load Diff

View File

@@ -77,7 +77,7 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase
var headerSize = ImGui.GetCursorPosY() - ImGui.GetStyle().WindowPadding.Y;
using (_uiSharedService.UidFont.Push())
UiSharedService.ColorText(Pair.UserData.AliasOrUID, ImGuiColors.HealerGreen);
UiSharedService.ColorText(Pair.UserData.AliasOrUID, UIColors.Get("LightlessBlue"));
ImGuiHelpers.ScaledDummy(new Vector2(spacing.Y, spacing.Y));
var textPos = ImGui.GetCursorPosY() - headerSize;
@@ -118,7 +118,7 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase
UiSharedService.ColorText(note, ImGuiColors.DalamudGrey);
}
string status = Pair.IsVisible ? "Visible" : (Pair.IsOnline ? "Online" : "Offline");
UiSharedService.ColorText(status, (Pair.IsVisible || Pair.IsOnline) ? ImGuiColors.HealerGreen : ImGuiColors.DalamudRed);
UiSharedService.ColorText(status, (Pair.IsVisible || Pair.IsOnline) ? UIColors.Get("LightlessBlue") : ImGuiColors.DalamudRed);
if (Pair.IsVisible)
{
ImGui.SameLine();

View File

@@ -0,0 +1,35 @@
using System.Globalization;
using System.Numerics;
namespace LightlessSync.UI
{
internal static class UIColors
{
private static readonly Dictionary<string, string> HexColors = new(StringComparer.OrdinalIgnoreCase)
{
{ "LightlessPurple", "#ad8af5" },
{ "LightlessBlue", "#a6c2ff" },
{ "LightlessYellow", "#ffe97a" },
{ "PairBlue", "#88a2db" },
{ "DimRed", "#d44444" },
};
public static Vector4 Get(string name)
{
if (!HexColors.TryGetValue(name, out var hex))
throw new ArgumentException($"Color '{name}' not found in UIColors.");
return HexToRgba(hex);
}
public static Vector4 HexToRgba(string hexColor)
{
hexColor = hexColor.TrimStart('#');
int r = int.Parse(hexColor.Substring(0, 2), NumberStyles.HexNumber);
int g = int.Parse(hexColor.Substring(2, 2), NumberStyles.HexNumber);
int b = int.Parse(hexColor.Substring(4, 2), NumberStyles.HexNumber);
int a = hexColor.Length == 8 ? int.Parse(hexColor.Substring(6, 2), NumberStyles.HexNumber) : 255;
return new Vector4(r / 255f, g / 255f, b / 255f, a / 255f);
}
}
}

View File

@@ -12,9 +12,9 @@ using Dalamud.Plugin.Services;
using Dalamud.Utility;
using LightlessSync.FileCache;
using LightlessSync.Interop.Ipc;
using LightlessSync.Localization;
using LightlessSync.LightlessConfiguration;
using LightlessSync.LightlessConfiguration.Models;
using LightlessSync.Localization;
using LightlessSync.PlayerData.Pairs;
using LightlessSync.Services;
using LightlessSync.Services.Mediator;
@@ -114,6 +114,15 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
SizePx = 35
}));
});
MediumFont = _pluginInterface.UiBuilder.FontAtlas.NewDelegateFontHandle(e =>
{
e.OnPreBuild(tk => tk.AddDalamudAssetFont(Dalamud.DalamudAsset.NotoSansJpMedium, new()
{
SizePx = 22,
}));
});
GameFont = _pluginInterface.UiBuilder.FontAtlas.NewGameFontHandle(new(GameFontFamilyAndSize.Axis12));
IconFont = _pluginInterface.UiBuilder.IconFontFixedWidthHandle;
}
@@ -133,6 +142,8 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
public string PlayerName => _dalamudUtil.GetPlayerName();
public IFontHandle UidFont { get; init; }
public IFontHandle MediumFont { get; init; }
public Dictionary<ushort, string> WorldData => _dalamudUtil.WorldData.Value;
public uint WorldId => _dalamudUtil.GetHomeWorldId();
@@ -305,7 +316,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
}
}
public static Vector4 GetBoolColor(bool input) => input ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed;
public static Vector4 GetBoolColor(bool input) => input ? UIColors.Get("LightlessBlue") : UIColors.Get("DimRed");
public static string GetNotes(List<Pair> pairs)
{
@@ -394,7 +405,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
}
public static Vector4 UploadColor((long, long) data) => data.Item1 == 0 ? ImGuiColors.DalamudGrey :
data.Item1 == data.Item2 ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudYellow;
data.Item1 == data.Item2 ? UIColors.Get("LightlessBlue") : ImGuiColors.DalamudYellow;
public bool ApplyNotesFromClipboard(string notes, bool overwrite)
{
@@ -434,9 +445,82 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
FontText(text, UidFont, color);
}
public void UnderlinedBigText(
string text,
Vector4? textColor = null,
Vector4? underlineColor = null,
float underlineThickness = 2f)
{
using var font = UidFont.Push();
var drawList = ImGui.GetWindowDrawList();
var textSize = ImGui.CalcTextSize(text);
var pos = ImGui.GetCursorScreenPos();
var text_color = textColor ?? ImGuiColors.DalamudWhite;
var line_color = underlineColor ?? text_color;
ImGui.PushStyleColor(ImGuiCol.Text, text_color);
ImGui.TextUnformatted(text);
ImGui.PopStyleColor();
var lineY = pos.Y + textSize.Y + 2f;
drawList.AddLine(
new Vector2(pos.X, lineY),
new Vector2(pos.X + textSize.X, lineY),
ImGui.GetColorU32(line_color),
underlineThickness * ImGuiHelpers.GlobalScale
);
}
public void ColoredSeparator(Vector4? color = null, float thickness = 1f, float indent = 0f)
{
var drawList = ImGui.GetWindowDrawList();
var min = ImGui.GetCursorScreenPos();
var max = new Vector2(min.X + ImGui.GetContentRegionAvail().X, min.Y);
min.X += indent;
max.X -= indent;
drawList.AddLine(
min,
new Vector2(max.X, min.Y),
ImGui.GetColorU32(color ?? ImGuiColors.DalamudGrey),
thickness * ImGuiHelpers.GlobalScale
);
ImGui.Dummy(new Vector2(0, thickness * ImGuiHelpers.GlobalScale));
}
public void MediumText(string text, Vector4? color = null)
{
FontText(text, MediumFont, color);
}
public bool MediumTreeNode(string label, Vector4? textColor = null, float lineWidth = 2f, ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags.SpanAvailWidth)
{
using var font = MediumFont.Push();
var lineColor = textColor ?? ImGuiColors.DalamudWhite;
var textSize = ImGui.CalcTextSize(label);
var cursorScreen = ImGui.GetCursorScreenPos();
var cursorLocal = ImGui.GetCursorPos();
ImGui.GetWindowDrawList().AddLine(
new Vector2(cursorScreen.X, cursorScreen.Y),
new Vector2(cursorScreen.X, cursorScreen.Y + textSize.Y),
ImGui.GetColorU32(lineColor),
lineWidth * ImGuiHelpers.GlobalScale
);
ImGui.SetCursorPosX(cursorLocal.X + 6f);
using var color = ImRaii.PushColor(ImGuiCol.Text, lineColor);
return ImGui.TreeNodeEx(label, flags);
}
public void BooleanToColoredIcon(bool value, bool inline = true)
{
using var colorgreen = ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.HealerGreen, value);
using var colorgreen = ImRaii.PushColor(ImGuiCol.Text, UIColors.Get("LightlessBlue"), value);
using var colorred = ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudRed, !value);
if (inline) ImGui.SameLine();
@@ -645,7 +729,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
{
if (_discordOAuthCheck.Result != null)
{
ColorTextWrapped("Server is compatible with Discord OAuth2", ImGuiColors.HealerGreen);
ColorTextWrapped("Server is compatible with Discord OAuth2", UIColors.Get("LightlessBlue"));
}
else
{
@@ -678,7 +762,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
selectedServer.OAuthToken = _discordOAuthGetCode.Result;
_discordOAuthGetCode = null;
_serverConfigurationManager.Save();
ColorTextWrapped("Success", ImGuiColors.HealerGreen);
ColorTextWrapped("Success", UIColors.Get("LightlessBlue"));
}
else
{
@@ -708,7 +792,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
if (tokenExpiry > DateTime.UtcNow)
{
ColorTextWrapped($"OAuth2 is enabled, linked to: Discord User {_serverConfigurationManager.GetDiscordUserFromToken(selectedServer)}", ImGuiColors.HealerGreen);
ColorTextWrapped($"OAuth2 is enabled, linked to: Discord User {_serverConfigurationManager.GetDiscordUserFromToken(selectedServer)}", UIColors.Get("LightlessBlue"));
TextWrapped($"The OAuth2 token will expire on {tokenExpiry:yyyy-MM-dd} and automatically renew itself during login on or after {(tokenExpiry - TimeSpan.FromDays(7)):yyyy-MM-dd}.");
using (ImRaii.Disabled(!CtrlPressed()))
{
@@ -740,7 +824,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
if (foundUids > 0)
{
ColorTextWrapped($"Found {foundUids} associated UIDs on the server, Primary UID: {primaryUid.Key} (Vanity UID: {vanity})",
ImGuiColors.HealerGreen);
UIColors.Get("LightlessBlue"));
}
else
{
@@ -1085,6 +1169,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
UidFont.Dispose();
GameFont.Dispose();
MediumFont.Dispose();
}
private static void CenterWindow(float width, float height, ImGuiCond cond = ImGuiCond.None)

View File

@@ -8,7 +8,6 @@ using LightlessSync.LightlessConfiguration.Models;
using LightlessSync.Services.Mediator;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.Logging;
using static FFXIVClientStructs.FFXIV.Client.Game.UI.MapMarkerData.Delegates;
namespace LightlessSync.WebAPI;

View File

@@ -1,6 +1,5 @@
using LightlessSync.API.Data;
using LightlessSync.API.Dto.CharaData;
using LightlessSync.Services.CharaData.Models;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.Logging;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 770 KiB

After

Width:  |  Height:  |  Size: 206 KiB

View File

@@ -16,18 +16,18 @@
},
"Downloader": {
"type": "Direct",
"requested": "[3.3.4, )",
"resolved": "3.3.4",
"contentHash": "/M/c80e1L0WW1XrLSSiQhgFxk8rrfbpWiWDn2CeBg1tPD393Neo+v184yG/ThyhE9rrNp36yCrugiCmEbRf+VQ==",
"requested": "[4.0.3, )",
"resolved": "4.0.3",
"contentHash": "Vg1+UqPDstpMw2CKXV9XvB8jKHC95KQfbqPxQXvOMRMFnTov4Ixvvw6GZV5DXLnKuL2sfnmVYX9CaQtcURia1Q==",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "8.0.1"
"Microsoft.Extensions.Logging.Abstractions": "8.0.3"
}
},
"Glamourer.Api": {
"type": "Direct",
"requested": "[2.4.0, )",
"resolved": "2.4.0",
"contentHash": "i8PEKb4R2tyunfHEHZHY+yCx2p6D0hsoQ24Q8UDVb7rNvynzDqMrRhGTQjuF+Tg2XGWA7sb32wJqHXCv0oKoeA=="
"requested": "[2.6.0, )",
"resolved": "2.6.0",
"contentHash": "zysCZgNBRm3k3qvibyw/31MmEckX0Uh0ZsT+Sax3ZHnYIRELr9Qhbz3cjJz7u0RHGIrNJiRpktu/LxgHEqDItw=="
},
"K4os.Compression.LZ4.Legacy": {
"type": "Direct",
@@ -40,9 +40,9 @@
},
"Meziantou.Analyzer": {
"type": "Direct",
"requested": "[2.0.189, )",
"resolved": "2.0.189",
"contentHash": "/e+dh95vDdvCTbViV2cWpXJEXAj+VHq7FsBXCTTTsLcffV0bkgXDFAPY0zMpy+Vt91Cl2cBoSOfaAoSdtn796Q=="
"requested": "[2.0.212, )",
"resolved": "2.0.212",
"contentHash": "U91ktjjTRTccUs3Lk+hrLD9vW+2+lhnsOf4G1GpRSJi1pLn3uK5CU6wGP9Bmz1KlJs6Oz1GGoMhxQBoqQsmAuQ=="
},
"Microsoft.AspNetCore.SignalR.Client": {
"type": "Direct",
@@ -105,12 +105,6 @@
"Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0"
}
},
"Penumbra.Api": {
"type": "Direct",
"requested": "[5.6.0, )",
"resolved": "5.6.0",
"contentHash": "zMmkxX1+7COn23aTeq0L+UMA79ocmvQdvj5RgksEfTKrKZLbtaqRPCe6NsChyfGvcj79sgfAW/9hJ+FAzzVcNg=="
},
"Penumbra.String": {
"type": "Direct",
"requested": "[1.0.5, )",
@@ -119,9 +113,9 @@
},
"SixLabors.ImageSharp": {
"type": "Direct",
"requested": "[3.1.7, )",
"resolved": "3.1.7",
"contentHash": "9fIOOAsyLFid6qKypM2Iy0Z3Q9yoanV8VoYAHtI2sYGMNKzhvRTjgFDHonIiVe+ANtxIxM6SuqUzj0r91nItpA=="
"requested": "[3.1.11, )",
"resolved": "3.1.11",
"contentHash": "JfPLyigLthuE50yi6tMt7Amrenr/fA31t2CvJyhy/kQmfulIBAqo5T/YFUSRHtuYPXRSaUHygFeh6Qd933EoSw=="
},
"SonarAnalyzer.CSharp": {
"type": "Direct",
@@ -523,6 +517,9 @@
"dependencies": {
"MessagePack.Annotations": "[3.1.3, )"
}
},
"penumbra.api": {
"type": "Project"
}
}
}

1
PenumbraAPI Submodule

Submodule PenumbraAPI added at 953dd227af

View File

@@ -1,6 +1,6 @@
# Lightless Sync Dalamud Plugin
Available at [This dalamud Repo](https://raw.githubusercontent.com/Light-Public-Syncshells/repo/main/plogonmaster.json)
Available at [This dalamud Repo](https://raw.githubusercontent.com/Light-Public-Syncshells/LightlessSync/refs/heads/main/plogonmaster.json)
# [Lightless Sync Discord](https://discord.gg/dsbjcXMnhA)