2.0.0 (#92)
All checks were successful
Tag and Release Lightless / tag-and-release (push) Successful in 2m27s

2.0.0 Changes:

- Reworked shell finder UI with compact or list view with profile tags showing with the listing, allowing moderators to broadcast the syncshell as well to have it be used more.
- Reworked user list in syncshell admin screen to have filter visible and moved away from table to its own thing, allowing to copy uid/note/alias when clicking on the name.
- Reworked download bars and download box to make it look more modern, removed the jitter around, so it shouldn't vibrate around much.
- Chat has been added to the top menu, working in Zone or in Syncshells to be used there.
- Paired system has been revamped to make pausing and unpausing faster, and loading people should be faster as well.
- Moved to the internal object table to have faster load times for users; people should load in faster
- Compactor is running on a multi-threaded level instead of single-threaded; this should increase the speed of compacting files
- Nameplate Service has been reworked so it wouldn't use the nameplate handler anymore.
- Files can be resized when downloading to reduce load on users if they aren't compressed. (can be toggled to resize all).
- Penumbra Collections are now only made when people are visible, reducing the load on boot-up when having many syncshells in your list.
- Lightfinder plates have been moved away from using Nameplates, but will use an overlay.
- Main UI has been changed a bit with a gradient, and on hover will glow up now.
- Reworked Profile UI for Syncshell and Users to be more user-facing with more customizable items.
- Reworked Settings UI to look more modern.
- Performance should be better due to new systems that would dispose of the collections and better caching of items.

Co-authored-by: defnotken <itsdefnotken@gmail.com>
Co-authored-by: azyges <aaaaaa@aaa.aaa>
Co-authored-by: choco <choco@patat.nl>
Co-authored-by: cake <admin@cakeandbanana.nl>
Co-authored-by: Minmoose <KennethBohr@outlook.com>
Reviewed-on: #92
This commit was merged in pull request #92.
This commit is contained in:
2025-12-21 17:19:34 +00:00
parent 906f401940
commit 835a0a637d
191 changed files with 32636 additions and 8841 deletions

View File

@@ -119,6 +119,7 @@ public class PlayerDataFactory
CharacterDataFragment fragment = objectKind == ObjectKind.Player ? new CharacterDataFragmentPlayer() : new();
_logger.LogDebug("Building character data for {obj}", playerRelatedObject);
var logDebug = _logger.IsEnabled(LogLevel.Debug);
// wait until chara is not drawing and present so nothing spontaneously explodes
await _dalamudUtil.WaitWhileCharacterIsDrawing(_logger, playerRelatedObject, Guid.NewGuid(), 30000, ct: ct).ConfigureAwait(false);
@@ -132,11 +133,6 @@ public class PlayerDataFactory
ct.ThrowIfCancellationRequested();
Dictionary<string, List<ushort>>? boneIndices =
objectKind != ObjectKind.Player
? null
: await _dalamudUtil.RunOnFrameworkThread(() => _modelAnalyzer.GetSkeletonBoneIndices(playerRelatedObject)).ConfigureAwait(false);
DateTime start = DateTime.UtcNow;
// penumbra call, it's currently broken
@@ -154,11 +150,21 @@ public class PlayerDataFactory
ct.ThrowIfCancellationRequested();
_logger.LogDebug("== Static Replacements ==");
foreach (var replacement in fragment.FileReplacements.Where(i => i.HasFileReplacement).OrderBy(i => i.GamePaths.First(), StringComparer.OrdinalIgnoreCase))
if (logDebug)
{
_logger.LogDebug("=> {repl}", replacement);
ct.ThrowIfCancellationRequested();
_logger.LogDebug("== Static Replacements ==");
foreach (var replacement in fragment.FileReplacements.Where(i => i.HasFileReplacement).OrderBy(i => i.GamePaths.First(), StringComparer.OrdinalIgnoreCase))
{
_logger.LogDebug("=> {repl}", replacement);
ct.ThrowIfCancellationRequested();
}
}
else
{
foreach (var replacement in fragment.FileReplacements.Where(i => i.HasFileReplacement))
{
ct.ThrowIfCancellationRequested();
}
}
await _transientResourceManager.WaitForRecording(ct).ConfigureAwait(false);
@@ -190,11 +196,21 @@ public class PlayerDataFactory
var transientPaths = ManageSemiTransientData(objectKind);
var resolvedTransientPaths = await GetFileReplacementsFromPaths(transientPaths, new HashSet<string>(StringComparer.Ordinal)).ConfigureAwait(false);
_logger.LogDebug("== Transient Replacements ==");
foreach (var replacement in resolvedTransientPaths.Select(c => new FileReplacement([.. c.Value], c.Key)).OrderBy(f => f.ResolvedPath, StringComparer.Ordinal))
if (logDebug)
{
_logger.LogDebug("=> {repl}", replacement);
fragment.FileReplacements.Add(replacement);
_logger.LogDebug("== Transient Replacements ==");
foreach (var replacement in resolvedTransientPaths.Select(c => new FileReplacement([.. c.Value], c.Key)).OrderBy(f => f.ResolvedPath, StringComparer.Ordinal))
{
_logger.LogDebug("=> {repl}", replacement);
fragment.FileReplacements.Add(replacement);
}
}
else
{
foreach (var replacement in resolvedTransientPaths.Select(c => new FileReplacement([.. c.Value], c.Key)))
{
fragment.FileReplacements.Add(replacement);
}
}
// clean up all semi transient resources that don't have any file replacement (aka null resolve)
@@ -252,11 +268,26 @@ public class PlayerDataFactory
ct.ThrowIfCancellationRequested();
Dictionary<string, List<ushort>>? boneIndices = null;
var hasPapFiles = false;
if (objectKind == ObjectKind.Player)
{
hasPapFiles = fragment.FileReplacements.Any(f =>
!f.IsFileSwap && f.GamePaths.First().EndsWith("pap", StringComparison.OrdinalIgnoreCase));
if (hasPapFiles)
{
boneIndices = await _dalamudUtil.RunOnFrameworkThread(() => _modelAnalyzer.GetSkeletonBoneIndices(playerRelatedObject)).ConfigureAwait(false);
}
}
if (objectKind == ObjectKind.Player)
{
try
{
await VerifyPlayerAnimationBones(boneIndices, (fragment as CharacterDataFragmentPlayer)!, ct).ConfigureAwait(false);
if (hasPapFiles)
{
await VerifyPlayerAnimationBones(boneIndices, (fragment as CharacterDataFragmentPlayer)!, ct).ConfigureAwait(false);
}
}
catch (OperationCanceledException e)
{
@@ -278,12 +309,16 @@ public class PlayerDataFactory
{
if (boneIndices == null) return;
foreach (var kvp in boneIndices)
if (_logger.IsEnabled(LogLevel.Debug))
{
_logger.LogDebug("Found {skellyname} ({idx} bone indices) on player: {bones}", kvp.Key, kvp.Value.Any() ? kvp.Value.Max() : 0, string.Join(',', kvp.Value));
foreach (var kvp in boneIndices)
{
_logger.LogDebug("Found {skellyname} ({idx} bone indices) on player: {bones}", kvp.Key, kvp.Value.Any() ? kvp.Value.Max() : 0, string.Join(',', kvp.Value));
}
}
if (boneIndices.All(u => u.Value.Count == 0)) return;
var maxPlayerBoneIndex = boneIndices.SelectMany(kvp => kvp.Value).DefaultIfEmpty().Max();
if (maxPlayerBoneIndex <= 0) return;
int noValidationFailed = 0;
foreach (var file in fragment.FileReplacements.Where(f => !f.IsFileSwap && f.GamePaths.First().EndsWith("pap", StringComparison.OrdinalIgnoreCase)).ToList())
@@ -303,12 +338,13 @@ public class PlayerDataFactory
_logger.LogDebug("Verifying bone indices for {path}, found {x} skeletons", file.ResolvedPath, skeletonIndices.Count);
foreach (var boneCount in skeletonIndices.Select(k => k).ToList())
foreach (var boneCount in skeletonIndices)
{
if (boneCount.Value.Max() > boneIndices.SelectMany(b => b.Value).Max())
var maxAnimationIndex = boneCount.Value.DefaultIfEmpty().Max();
if (maxAnimationIndex > maxPlayerBoneIndex)
{
_logger.LogWarning("Found more bone indices on the animation {path} skeleton {skl} (max indice {idx}) than on any player related skeleton (max indice {idx2})",
file.ResolvedPath, boneCount.Key, boneCount.Value.Max(), boneIndices.SelectMany(b => b.Value).Max());
file.ResolvedPath, boneCount.Key, maxAnimationIndex, maxPlayerBoneIndex);
validationFailed = true;
break;
}