Files
LightlessClient/LightlessSync/PlayerData/Pairs/PairModels.cs
2025-11-27 00:29:56 +09:00

221 lines
5.9 KiB
C#

using LightlessSync.API.Data;
using LightlessSync.API.Data.Enum;
using LightlessSync.API.Data.Extensions;
using LightlessSync.API.Dto.Group;
namespace LightlessSync.PlayerData.Pairs;
/// <summary>
/// core models for the pair system
/// </summary>
public sealed class PairState
{
public CharacterData? CharacterData { get; set; }
public Guid? TemporaryCollectionId { get; set; }
public bool IsEmpty => CharacterData is null && (TemporaryCollectionId is null || TemporaryCollectionId == Guid.Empty);
}
public readonly record struct PairUniqueIdentifier(string UserId);
/// <summary>
/// link between a pair id and character ident
/// </summary>
public sealed record PairRegistration(PairUniqueIdentifier PairIdent, string? CharacterIdent);
/// <summary>
/// per group membership info for a pair
/// </summary>
public sealed class GroupPairRelationship
{
public GroupPairRelationship(string groupId, GroupPairUserInfo? info)
{
GroupId = groupId;
UserInfo = info;
}
public string GroupId { get; }
public GroupPairUserInfo? UserInfo { get; private set; }
public void SetUserInfo(GroupPairUserInfo? info)
{
UserInfo = info;
}
}
/// <summary>
/// runtime view of a single pair connection
/// </summary>
public sealed class PairConnection
{
public PairConnection(UserData user)
{
User = user;
Groups = new Dictionary<string, GroupPairRelationship>(StringComparer.Ordinal);
}
public UserData User { get; }
public bool IsOnline { get; private set; }
public string? Ident { get; private set; }
public UserPermissions SelfToOtherPermissions { get; private set; } = UserPermissions.NoneSet;
public UserPermissions OtherToSelfPermissions { get; private set; } = UserPermissions.NoneSet;
public IndividualPairStatus? IndividualPairStatus { get; private set; }
public Dictionary<string, GroupPairRelationship> Groups { get; }
public bool IsPaused => SelfToOtherPermissions.IsPaused();
public bool IsDirectlyPaired => IndividualPairStatus is not null && IndividualPairStatus != API.Data.Enum.IndividualPairStatus.None;
public bool IsOneSided => IndividualPairStatus == API.Data.Enum.IndividualPairStatus.OneSided;
public bool HasAnyConnection => IsDirectlyPaired || Groups.Count > 0;
public void SetOnline(string? ident)
{
IsOnline = true;
Ident = ident;
}
public void SetOffline()
{
IsOnline = false;
}
public void UpdatePermissions(UserPermissions own, UserPermissions other)
{
SelfToOtherPermissions = own;
OtherToSelfPermissions = other;
}
public void UpdateStatus(IndividualPairStatus? status)
{
IndividualPairStatus = status;
}
public void EnsureGroupRelationship(string groupId, GroupPairUserInfo? info)
{
if (Groups.TryGetValue(groupId, out var relationship))
{
relationship.SetUserInfo(info);
}
else
{
Groups[groupId] = new GroupPairRelationship(groupId, info);
}
}
public void RemoveGroupRelationship(string groupId)
{
Groups.Remove(groupId);
}
}
/// <summary>
/// syncshell metadata plus member connections
/// </summary>
public sealed class Syncshell
{
public Syncshell(GroupFullInfoDto dto)
{
GroupFullInfo = dto;
Users = new Dictionary<string, PairConnection>(StringComparer.Ordinal);
}
public GroupFullInfoDto GroupFullInfo { get; private set; }
public Dictionary<string, PairConnection> Users { get; }
public void Update(GroupFullInfoDto dto)
{
GroupFullInfo = dto;
}
}
/// <summary>
/// simple success/failure result
/// </summary>
public readonly struct PairOperationResult
{
private PairOperationResult(bool success, string? error)
{
Success = success;
Error = error;
}
public bool Success { get; }
public string? Error { get; }
public static PairOperationResult Ok() => new(true, null);
public static PairOperationResult Fail(string error) => new(false, error);
}
/// <summary>
/// typed success/failure result
/// </summary>
public readonly struct PairOperationResult<T>
{
private PairOperationResult(bool success, T value, string? error)
{
Success = success;
Value = value;
Error = error;
}
public bool Success { get; }
public T Value { get; }
public string? Error { get; }
public static PairOperationResult<T> Ok(T value) => new(true, value, null);
public static PairOperationResult<T> Fail(string error) => new(false, default!, error);
}
/// <summary>
/// state of which optional plugin warnings were shown
/// </summary>
public record OptionalPluginWarning
{
public bool ShownHeelsWarning { get; set; } = false;
public bool ShownCustomizePlusWarning { get; set; } = false;
public bool ShownHonorificWarning { get; set; } = false;
public bool ShownMoodlesWarning { get; set; } = false;
public bool ShowPetNicknamesWarning { get; set; } = false;
}
/// <summary>
/// tracks the handler registered pairs for an ident
/// </summary>
internal sealed class PairHandlerEntry
{
private readonly HashSet<PairUniqueIdentifier> _pairs = new();
public PairHandlerEntry(string ident, IPairHandlerAdapter handler)
{
Ident = ident;
Handler = handler;
}
public string Ident { get; }
public IPairHandlerAdapter Handler { get; }
public bool HasPairs => _pairs.Count > 0;
public int PairCount => _pairs.Count;
public void AddPair(PairUniqueIdentifier pair)
{
_pairs.Add(pair);
}
public bool RemovePair(PairUniqueIdentifier pair)
{
return _pairs.Remove(pair);
}
public IReadOnlyCollection<PairUniqueIdentifier> SnapshotPairs()
{
if (_pairs.Count == 0)
{
return Array.Empty<PairUniqueIdentifier>();
}
return _pairs.ToArray();
}
}