server-master/srcs/_plugins/Plugin.FamilyImpl/FamilyManager.cs
2026-02-10 18:21:30 +01:00

234 lines
No EOL
8.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using PhoenixLib.Caching;
using PhoenixLib.DAL.Redis.Locks;
using PhoenixLib.Logging;
using Plugin.FamilyImpl.Logs;
using WingsAPI.Communication.Families;
using WingsAPI.Data.Families;
using WingsEmu.Game.Families;
using WingsEmu.Game.Managers;
using WingsEmu.Game.Networking;
using WingsEmu.Packets.Enums.Families;
namespace Plugin.FamilyImpl
{
public class FamilyManager : IFamilyManager
{
private readonly IExpirableLockService _expirableLockService;
private readonly IKeyValueCache<IFamily> _familyByName;
private readonly ILongKeyCachedRepository<Family> _familyCache;
private readonly IFamilyExperienceManager _familyExperienceManager;
private readonly IFamilyLogManager _familyLogManager;
private readonly IFamilyService _familyService;
private readonly ReaderWriterLockSlim _lock = new();
private readonly ILongKeyCachedRepository<FamilyMembership> _membershipCache;
private readonly ISessionManager _sessionManager;
public FamilyManager(ILongKeyCachedRepository<Family> familyCache, IFamilyService familyService, ISessionManager sessionManager, ILongKeyCachedRepository<FamilyMembership> membershipCache,
IFamilyLogManager familyLogManager, IFamilyExperienceManager familyExperienceManager, IKeyValueCache<IFamily> familyByName, IExpirableLockService expirableLockService)
{
_familyCache = familyCache;
_familyService = familyService;
_sessionManager = sessionManager;
_membershipCache = membershipCache;
_familyLogManager = familyLogManager;
_familyExperienceManager = familyExperienceManager;
_familyByName = familyByName;
_expirableLockService = expirableLockService;
}
public void AddFamily(FamilyDTO family, IReadOnlyCollection<FamilyMembershipDto> members)
{
IFamily oldFamily = _familyCache.Get(family.Id);
var newFamily = new Family(family, members, new List<FamilyLogDto>(), _sessionManager);
_familyCache.Set(family.Id, newFamily);
_familyByName.Set(family.Name, newFamily);
if (oldFamily == null)
{
return;
}
newFamily.Members.AddRange(oldFamily.Members);
oldFamily.Members.Clear();
}
public void RemoveFamily(long familyId)
{
IFamily cachedFamily = _familyCache.Get(familyId);
_familyCache.Remove(familyId);
foreach (FamilyMembership member in cachedFamily.Members)
{
_membershipCache.Remove(member.CharacterId);
IClientSession session = _sessionManager.GetSessionByCharacterId(member.CharacterId);
session?.PlayerEntity.SetFamilyMembership(null);
}
}
public IFamily GetFamilyByFamilyName(string familyName) => _familyByName.Get(familyName);
public void AddOrReplaceMember(FamilyMembershipDto membership, IFamily family)
{
if (family == null)
{
return;
}
var newMember = new FamilyMembership(membership, _sessionManager);
family.Members.RemoveAll(x => x.CharacterId == membership.CharacterId);
_membershipCache.Set(newMember.CharacterId, newMember);
if (newMember.Authority == FamilyAuthority.Head)
{
family.Head = newMember;
}
family.Members.Add(newMember);
IClientSession session = _sessionManager.GetSessionByCharacterId(membership.CharacterId);
session?.PlayerEntity.SetFamilyMembership(newMember);
}
public void AddOrReplaceMember(FamilyMembershipDto membership)
{
AddOrReplaceMember(membership, GetFamilyByFamilyId(membership.FamilyId));
}
public void RemoveMember(long characterId, long familyId)
{
IFamily family = GetFamilyByFamilyId(familyId);
family?.Members.RemoveAll(x => x.CharacterId == characterId);
_membershipCache.Remove(characterId);
IClientSession session = _sessionManager.GetSessionByCharacterId(characterId);
session?.PlayerEntity.SetFamilyMembership(null);
}
public void MemberDisconnectionUpdate(long characterId, DateTime disconnectionTime)
{
FamilyMembership member = GetFamilyMembershipByCharacterId(characterId);
if (member == null)
{
return;
}
member.LastOnlineDate = disconnectionTime;
AddOrReplaceMember(member);
}
public FamilyMembership GetFamilyMembershipByCharacterId(long characterId)
{
FamilyMembership membership = _membershipCache.Get(characterId);
if (membership != null)
{
return membership;
}
MembershipResponse response = _familyService.GetMembershipByCharacterIdAsync(
new MembershipRequest { CharacterId = characterId }).ConfigureAwait(false).GetAwaiter().GetResult();
return response.Membership == null ? null : _membershipCache.GetOrSet(response.Membership.CharacterId, () => new FamilyMembership(response.Membership, _sessionManager));
}
public void AddToFamilyLogs(IReadOnlyDictionary<long, List<FamilyLogDto>> logs)
{
try
{
foreach (KeyValuePair<long, List<FamilyLogDto>> familyLogs in logs)
{
IFamily family = _familyCache.Get(familyLogs.Key);
if (family == null)
{
continue;
}
_lock.EnterWriteLock();
try
{
foreach (FamilyLogDto log in familyLogs.Value)
{
family.Logs.Add(log);
}
family.Logs.Sort((x, y) => DateTime.Compare(y.Timestamp, x.Timestamp)); // Newest -> Older
if (family.Logs.Count <= 200)
{
continue;
}
for (int i = 200; i < family.Logs.Count; i++)
{
family.Logs.RemoveAt(i);
}
}
finally
{
_lock.ExitWriteLock();
}
}
}
catch (Exception e)
{
Log.Error("[FAMILY_MANAGER] AddToFamilyLogs", e);
}
}
public void SendLogToFamilyServer(FamilyLogDto log)
{
_familyLogManager.SaveLogToBuffer(log);
}
public IEnumerable<long> AddToFamilyExperiences(Dictionary<long, long> exps)
{
var familyIds = new HashSet<long>();
foreach ((long characterId, long experience) in exps)
{
FamilyMembership membership = _membershipCache.Get(characterId);
if (membership == null)
{
continue;
}
membership.Experience = experience;
familyIds.Add(membership.FamilyId);
}
return familyIds;
}
public void SendExperienceToFamilyServer(ExperienceGainedSubMessage experienceGainedSubMessage)
{
_familyExperienceManager.SaveFamilyExperienceToBuffer(experienceGainedSubMessage);
}
public async Task<bool> CanJoinNewFamilyAsync(int playerEntityId) =>
await _expirableLockService.TryAddTemporaryLockAsync($"game:locks:character:{playerEntityId}:join-family", DateTime.UtcNow.Date.AddDays(1));
public async Task<bool> RemovePlayerJoinCooldownAsync(int playerEntityId) => await _expirableLockService.TryRemoveTemporaryLock($"game:locks:character:{playerEntityId}:join-family");
public Family GetFamilyByFamilyId(long familyId)
{
Family family = _familyCache.Get(familyId);
if (family != null)
{
return family;
}
FamilyIdResponse response = _familyService.GetFamilyByIdAsync(new FamilyIdRequest { FamilyId = familyId }).ConfigureAwait(false).GetAwaiter().GetResult();
family = _familyCache.GetOrSet(familyId, () => new Family(response.Family, response.Members, response.Logs, _sessionManager));
_familyByName.Set(family.Name, family);
foreach (FamilyMembership member in family.Members)
{
_membershipCache.Set(member.CharacterId, member);
}
return family;
}
public Family GetFamilyByFamilyIdCache(long familyId) => _familyCache.Get(familyId);
}
}