Add MCDO (#80)

* update api

* mcd online editor impl

* most of chara data hub impl

* some state of things

* some refactoring

* random bullshit go

* more nearby impl

* add uid to peformance msg

* cleanup/homogenization

* some split, update nuget packages

* migrate to latest packages where possible, remove lz4net, do some split, idk

* some polish and cleanup

* more cleanup, beautification, etc.

* fixes and cleanups

---------

Co-authored-by: Stanley Dimant <root.darkarchon@outlook.com>
This commit is contained in:
rootdarkarchon
2025-01-11 22:43:11 +01:00
committed by Loporrit
parent ad42b29a44
commit 30caedbf3a
44 changed files with 5128 additions and 486 deletions

View File

@@ -0,0 +1,141 @@
using MareSynchronos.API.Data.Enum;
using MareSynchronos.Interop.Ipc;
using MareSynchronos.PlayerData.Factories;
using MareSynchronos.PlayerData.Handlers;
using MareSynchronos.Services.CharaData.Models;
using MareSynchronos.Services.Mediator;
using Microsoft.Extensions.Logging;
namespace MareSynchronos.Services;
internal sealed class CharaDataCharacterHandler : DisposableMediatorSubscriberBase
{
private readonly GameObjectHandlerFactory _gameObjectHandlerFactory;
private readonly DalamudUtilService _dalamudUtilService;
private readonly IpcManager _ipcManager;
private readonly HashSet<HandledCharaDataEntry> _handledCharaData = [];
public IEnumerable<HandledCharaDataEntry> HandledCharaData => _handledCharaData;
public CharaDataCharacterHandler(ILogger<CharaDataCharacterHandler> logger, MareMediator mediator,
GameObjectHandlerFactory gameObjectHandlerFactory, DalamudUtilService dalamudUtilService,
IpcManager ipcManager)
: base(logger, mediator)
{
_gameObjectHandlerFactory = gameObjectHandlerFactory;
_dalamudUtilService = dalamudUtilService;
_ipcManager = ipcManager;
mediator.Subscribe<GposeEndMessage>(this, (_) =>
{
foreach (var chara in _handledCharaData)
{
RevertHandledChara(chara, false);
}
});
mediator.Subscribe<CutsceneFrameworkUpdateMessage>(this, (_) => HandleCutsceneFrameworkUpdate());
}
private void HandleCutsceneFrameworkUpdate()
{
if (!_dalamudUtilService.IsInGpose) return;
foreach (var entry in _handledCharaData.ToList())
{
var chara = _dalamudUtilService.GetGposeCharacterFromObjectTableByName(entry.Name, onlyGposeCharacters: true);
if (chara is null)
{
RevertChara(entry.Name, entry.CustomizePlus).GetAwaiter().GetResult();
_handledCharaData.Remove(entry);
}
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
foreach (var chara in _handledCharaData)
{
RevertHandledChara(chara, false);
}
}
public async Task RevertChara(string name, Guid? cPlusId, bool reapplyPose = true)
{
Guid applicationId = Guid.NewGuid();
await _ipcManager.Glamourer.RevertByNameAsync(Logger, name, applicationId).ConfigureAwait(false);
if (cPlusId != null)
{
await _ipcManager.CustomizePlus.RevertByIdAsync(cPlusId).ConfigureAwait(false);
}
using var handler = await _gameObjectHandlerFactory.Create(ObjectKind.Player,
() => _dalamudUtilService.GetGposeCharacterFromObjectTableByName(name, _dalamudUtilService.IsInGpose)?.Address ?? IntPtr.Zero, false)
.ConfigureAwait(false);
if (handler.Address != IntPtr.Zero)
{
var poseData = string.Empty;
API.Dto.CharaData.WorldData? worldData = null;
if (_dalamudUtilService.IsInGpose && reapplyPose)
{
poseData = await _ipcManager.Brio.GetPoseAsync(handler.Address).ConfigureAwait(false);
worldData = await _ipcManager.Brio.GetTransformAsync(handler.Address).ConfigureAwait(false);
}
await _ipcManager.Penumbra.RedrawAsync(Logger, handler, applicationId, CancellationToken.None).ConfigureAwait(false);
if (_dalamudUtilService.IsInGpose && reapplyPose)
{
await _ipcManager.Brio.SetPoseAsync(handler.Address, poseData ?? "{}").ConfigureAwait(false);
await _ipcManager.Brio.ApplyTransformAsync(handler.Address, worldData!.Value).ConfigureAwait(false);
}
}
}
public async Task<bool> RevertHandledChara(string name, bool reapplyPose = true)
{
var handled = _handledCharaData.FirstOrDefault(f => string.Equals(f.Name, name, StringComparison.Ordinal));
if (handled == null) return false;
_handledCharaData.Remove(handled);
await _dalamudUtilService.RunOnFrameworkThread(() => RevertChara(handled.Name, handled.CustomizePlus, reapplyPose)).ConfigureAwait(false);
return true;
}
public Task RevertHandledChara(HandledCharaDataEntry? handled, bool reapplyPose = true)
{
if (handled == null) return Task.CompletedTask;
_handledCharaData.Remove(handled);
return _dalamudUtilService.RunOnFrameworkThread(() => RevertChara(handled.Name, handled.CustomizePlus, reapplyPose));
}
internal void AddHandledChara(HandledCharaDataEntry handledCharaDataEntry)
{
_handledCharaData.Add(handledCharaDataEntry);
}
public void UpdateHandledData(Dictionary<string, CharaDataMetaInfoExtendedDto?> newData)
{
foreach (var handledData in _handledCharaData)
{
if (newData.TryGetValue(handledData.MetaInfo.FullId, out var metaInfo) && metaInfo != null)
{
handledData.MetaInfo = metaInfo;
}
}
}
public async Task<GameObjectHandler?> TryCreateGameObjectHandler(string name, bool gPoseOnly = false)
{
var handler = await _gameObjectHandlerFactory.Create(ObjectKind.Player,
() => _dalamudUtilService.GetGposeCharacterFromObjectTableByName(name, gPoseOnly && _dalamudUtilService.IsInGpose)?.Address ?? IntPtr.Zero, false)
.ConfigureAwait(false);
if (handler.Address == nint.Zero) return null;
return handler;
}
public async Task<GameObjectHandler?> TryCreateGameObjectHandler(int index)
{
var handler = await _gameObjectHandlerFactory.Create(ObjectKind.Player,
() => _dalamudUtilService.GetCharacterFromObjectTableByIndex(index)?.Address ?? IntPtr.Zero, false)
.ConfigureAwait(false);
if (handler.Address == nint.Zero) return null;
return handler;
}
}