push character data through the server without using the database

This commit is contained in:
Stanley Dimant
2022-06-30 17:16:49 +02:00
parent 3618540402
commit afbb3eea8e
7 changed files with 150 additions and 83 deletions

View File

@@ -78,7 +78,7 @@ namespace MareSynchronos.Factories
var cache = new CharacterData
{
JobId = _dalamudUtil.PlayerJobId,
GlamourerString = _ipcManager.GlamourerGetCharacterCustomization(_dalamudUtil.PlayerName),
GlamourerString = _ipcManager.GlamourerGetCharacterCustomization(_dalamudUtil.PlayerCharacter),
ManipulationString = _ipcManager.PenumbraGetMetaManipulations(_dalamudUtil.PlayerName)
};
var model = (CharacterBase*)((Character*)_dalamudUtil.PlayerPointer)->GameObject.GetDrawObject();

View File

@@ -60,6 +60,26 @@ public class CachedPlayer
private CharacterEquipment? _currentCharacterEquipment;
public void ApplyCharacterData(CharacterCacheDto characterData)
{
Logger.Debug("Received data for " + this);
Logger.Debug("Checking for files to download for player " + PlayerName);
Logger.Debug("Hash for data is " + characterData.Hash);
if (!_cache.ContainsKey(characterData.Hash))
{
Logger.Debug("Received total " + characterData.FileReplacements.Count + " file replacement data");
_cache[characterData.Hash] = characterData;
}
else
{
Logger.Debug("Had valid local cache for " + PlayerName);
}
_lastAppliedEquipmentHash = characterData.Hash;
DownloadAndApplyCharacter();
}
private void ApiControllerOnCharacterReceived(object? sender, CharacterReceivedEventArgs e)
{
if (string.IsNullOrEmpty(PlayerName) || e.CharacterNameHash != PlayerNameHash) return;
@@ -147,7 +167,7 @@ public class CachedPlayer
Logger.Debug(
$"Request Redraw for {PlayerName}");
_ipcManager.PenumbraSetTemporaryMods(tempCollection, moddedPaths, cache.ManipulationData);
_ipcManager.GlamourerApplyAll(cache.GlamourerData, PlayerName!);
_ipcManager.GlamourerApplyAll(cache.GlamourerData, PlayerCharacter!);
}
public void DisposePlayer()
@@ -166,8 +186,8 @@ public class CachedPlayer
_ipcManager.PenumbraRemoveTemporaryCollection(PlayerName);
if (PlayerCharacter != null)
{
_ipcManager.GlamourerApplyOnlyCustomization(_originalGlamourerData, PlayerName);
_ipcManager.GlamourerApplyOnlyEquipment(_lastGlamourerData, PlayerName);
_ipcManager.GlamourerApplyOnlyCustomization(_originalGlamourerData, PlayerCharacter);
_ipcManager.GlamourerApplyOnlyEquipment(_lastGlamourerData, PlayerCharacter);
}
}
catch (Exception ex)
@@ -182,7 +202,7 @@ public class CachedPlayer
}
}
public void InitializePlayer(PlayerCharacter character)
public void InitializePlayer(PlayerCharacter character, CharacterCacheDto? cache)
{
IsVisible = true;
PlayerName = character.Name.ToString();
@@ -190,10 +210,12 @@ public class CachedPlayer
Logger.Debug("Initializing Player " + this);
_dalamudUtil.FrameworkUpdate += DalamudUtilOnFrameworkUpdate;
_ipcManager.PenumbraRedrawEvent += IpcManagerOnPenumbraRedrawEvent;
_apiController.CharacterReceived += ApiControllerOnCharacterReceived;
_originalGlamourerData = _ipcManager.GlamourerGetCharacterCustomization(PlayerName);
_originalGlamourerData = _ipcManager.GlamourerGetCharacterCustomization(PlayerCharacter);
_currentCharacterEquipment = new CharacterEquipment(PlayerCharacter);
_lastPlayerObjectCheck = DateTime.Now;
if (cache != null)
{
ApplyCharacterData(cache);
}
}
private void DalamudUtilOnFrameworkUpdate()
@@ -250,11 +272,10 @@ public class CachedPlayer
private void OnPlayerChanged()
{
Logger.Debug($"Player {PlayerName} changed, PenumbraRedraw is {RequestedPenumbraRedraw}");
PlayerCharacter = _dalamudUtil.GetPlayerCharacterFromObjectTableByName(PlayerName!);
if (!RequestedPenumbraRedraw && PlayerCharacter is not null)
{
Logger.Debug($"Saving new Glamourer data");
_lastGlamourerData = _ipcManager.GlamourerGetCharacterCustomization(PlayerName!);
_lastGlamourerData = _ipcManager.GlamourerGetCharacterCustomization(PlayerCharacter!);
}
}
}

View File

@@ -4,6 +4,7 @@ using Dalamud.Plugin.Ipc;
using System;
using System.Collections.Generic;
using System.Linq;
using Dalamud.Game.ClientState.Objects.Types;
using MareSynchronos.Utils;
namespace MareSynchronos.Managers
@@ -11,11 +12,11 @@ namespace MareSynchronos.Managers
public class IpcManager : IDisposable
{
private readonly ICallGateSubscriber<int> _glamourerApiVersion;
private readonly ICallGateSubscriber<string, string, object>? _glamourerApplyAll;
private readonly ICallGateSubscriber<string, string>? _glamourerGetAllCustomization;
private readonly ICallGateSubscriber<string, object> _glamourerRevertCustomization;
private readonly ICallGateSubscriber<string, string, object>? _glamourerApplyOnlyEquipment;
private readonly ICallGateSubscriber<string, string, object>? _glamourerApplyOnlyCustomization;
private readonly ICallGateSubscriber<string, GameObject?, object>? _glamourerApplyAll;
private readonly ICallGateSubscriber<GameObject?, string>? _glamourerGetAllCustomization;
private readonly ICallGateSubscriber<GameObject?, object> _glamourerRevertCustomization;
private readonly ICallGateSubscriber<string, GameObject?, object>? _glamourerApplyOnlyEquipment;
private readonly ICallGateSubscriber<string, GameObject?, object>? _glamourerApplyOnlyCustomization;
private readonly ICallGateSubscriber<int> _penumbraApiVersion;
private readonly ICallGateSubscriber<string, string, bool, (int, string)> _penumbraCreateTemporaryCollection;
private readonly ICallGateSubscriber<string, string> _penumbraGetMetaManipulations;
@@ -45,11 +46,11 @@ namespace MareSynchronos.Managers
pi.GetIpcSubscriber<string, string>("Penumbra.GetMetaManipulations");
_glamourerApiVersion = pi.GetIpcSubscriber<int>("Glamourer.ApiVersion");
_glamourerGetAllCustomization = pi.GetIpcSubscriber<string, string>("Glamourer.GetAllCustomization");
_glamourerApplyAll = pi.GetIpcSubscriber<string, string, object>("Glamourer.ApplyAll");
_glamourerApplyOnlyCustomization = pi.GetIpcSubscriber<string, string, object>("Glamourer.ApplyOnlyCustomization");
_glamourerApplyOnlyEquipment = pi.GetIpcSubscriber<string, string, object>("Glamourer.ApplyOnlyEquipment");
_glamourerRevertCustomization = pi.GetIpcSubscriber<string, object>("Glamourer.Revert");
_glamourerGetAllCustomization = pi.GetIpcSubscriber<GameObject?, string>("Glamourer.GetAllCustomizationFromCharacter");
_glamourerApplyAll = pi.GetIpcSubscriber<string, GameObject?, object>("Glamourer.ApplyAllToCharacter");
_glamourerApplyOnlyCustomization = pi.GetIpcSubscriber<string, GameObject?, object>("Glamourer.ApplyOnlyCustomizationToCharacter");
_glamourerApplyOnlyEquipment = pi.GetIpcSubscriber<string, GameObject?, object>("Glamourer.ApplyOnlyEquipmentToCharacter");
_glamourerRevertCustomization = pi.GetIpcSubscriber<GameObject?, object>("Glamourer.RevertCharacter");
_penumbraObjectIsRedrawn.Subscribe(RedrawEvent);
_penumbraInit.Subscribe(PenumbraInit);
@@ -110,37 +111,37 @@ namespace MareSynchronos.Managers
Logger.Debug("IPC Manager disposed");
}
public void GlamourerApplyAll(string customization, string characterName)
public void GlamourerApplyAll(string customization, GameObject character)
{
if (!CheckGlamourerApi()) return;
Logger.Debug("Glamourer apply all to " + characterName);
_glamourerApplyAll!.InvokeAction(customization, characterName);
Logger.Debug("Glamourer apply all to " + character);
_glamourerApplyAll!.InvokeAction(customization, character);
}
public void GlamourerApplyOnlyEquipment(string customization, string characterName)
public void GlamourerApplyOnlyEquipment(string customization, GameObject character)
{
if (!CheckGlamourerApi() || string.IsNullOrEmpty(customization)) return;
Logger.Debug("Glamourer apply only equipment to " + characterName);
_glamourerApplyOnlyEquipment!.InvokeAction(customization, characterName);
Logger.Debug("Glamourer apply only equipment to " + character);
_glamourerApplyOnlyEquipment!.InvokeAction(customization, character);
}
public void GlamourerApplyOnlyCustomization(string customization, string characterName)
public void GlamourerApplyOnlyCustomization(string customization, GameObject character)
{
if (!CheckGlamourerApi() || string.IsNullOrEmpty(customization)) return;
Logger.Debug("Glamourer apply only customization to " + characterName);
_glamourerApplyOnlyCustomization!.InvokeAction(customization, characterName);
Logger.Debug("Glamourer apply only customization to " + character);
_glamourerApplyOnlyCustomization!.InvokeAction(customization, character);
}
public string GlamourerGetCharacterCustomization(string characterName)
public string GlamourerGetCharacterCustomization(GameObject character)
{
if (!CheckGlamourerApi()) return string.Empty;
return _glamourerGetAllCustomization!.InvokeFunc(characterName);
return _glamourerGetAllCustomization!.InvokeFunc(character);
}
public void GlamourerRevertCharacterCustomization(string characterName)
public void GlamourerRevertCharacterCustomization(GameObject character)
{
if (!CheckGlamourerApi()) return;
_glamourerRevertCustomization!.InvokeAction(characterName);
_glamourerRevertCustomization!.InvokeAction(character);
}
public string PenumbraCreateTemporaryCollection(string characterName)

View File

@@ -3,8 +3,10 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Dalamud.Game;
using MareSynchronos.API;
using MareSynchronos.Utils;
using MareSynchronos.WebAPI;
using MareSynchronos.WebAPI.Utils;
namespace MareSynchronos.Managers;
@@ -14,10 +16,15 @@ public class OnlinePlayerManager : IDisposable
private readonly DalamudUtil _dalamudUtil;
private readonly Framework _framework;
private readonly IpcManager _ipcManager;
private readonly PlayerManager _playerManager;
private readonly List<CachedPlayer> _onlineCachedPlayers = new();
private readonly Dictionary<string, CharacterCacheDto> _temporaryStoredCharacterCache = new();
private List<string> OnlineVisiblePlayerHashes => _onlineCachedPlayers.Where(p => p.PlayerCharacter != null)
.Select(p => p.PlayerNameHash).ToList();
private DateTime _lastPlayerObjectCheck = DateTime.Now;
public OnlinePlayerManager(Framework framework, ApiController apiController, DalamudUtil dalamudUtil, IpcManager ipcManager)
public OnlinePlayerManager(Framework framework, ApiController apiController, DalamudUtil dalamudUtil, IpcManager ipcManager, PlayerManager playerManager)
{
Logger.Debug("Creating " + nameof(OnlinePlayerManager));
@@ -25,12 +32,15 @@ public class OnlinePlayerManager : IDisposable
_apiController = apiController;
_dalamudUtil = dalamudUtil;
_ipcManager = ipcManager;
_playerManager = playerManager;
_apiController.PairedClientOnline += ApiControllerOnPairedClientOnline;
_apiController.PairedClientOffline += ApiControllerOnPairedClientOffline;
_apiController.PairedWithOther += ApiControllerOnPairedWithOther;
_apiController.UnpairedFromOther += ApiControllerOnUnpairedFromOther;
_apiController.Connected += ApiControllerOnConnected;
_apiController.Disconnected += ApiControllerOnDisconnected;
_apiController.CharacterReceived += ApiControllerOnCharacterReceived;
_ipcManager.PenumbraDisposed += IpcManagerOnPenumbraDisposed;
@@ -43,6 +53,37 @@ public class OnlinePlayerManager : IDisposable
}
}
private void ApiControllerOnCharacterReceived(object? sender, CharacterReceivedEventArgs e)
{
var visiblePlayer = _onlineCachedPlayers.SingleOrDefault(c => c.IsVisible && c.PlayerNameHash == e.CharacterNameHash);
if (visiblePlayer != null)
{
Logger.Debug("Received data and applying to " + e.CharacterNameHash);
visiblePlayer.ApplyCharacterData(e.CharacterData);
}
else
{
Logger.Debug("Received data but no fitting character visible for " + e.CharacterNameHash);
_temporaryStoredCharacterCache[e.CharacterNameHash] = e.CharacterData;
}
}
private void PlayerManagerOnPlayerHasChanged(CharacterCacheDto characterCache)
{
_ = _apiController.PushCharacterData(characterCache, OnlineVisiblePlayerHashes);
}
private void ApiControllerOnConnected(object? sender, EventArgs e)
{
var apiTask = _apiController.GetOnlineCharacters();
Task.WaitAll(apiTask);
AddInitialPairs(apiTask.Result);
_playerManager.PlayerHasChanged += PlayerManagerOnPlayerHasChanged;
}
private void DalamudUtilOnLogOut()
{
_framework.Update -= FrameworkOnUpdate;
@@ -61,6 +102,7 @@ public class OnlinePlayerManager : IDisposable
private void ApiControllerOnDisconnected(object? sender, EventArgs e)
{
RestoreAllCharacters();
_playerManager.PlayerHasChanged -= PlayerManagerOnPlayerHasChanged;
}
public void AddInitialPairs(List<string> apiTaskResult)
@@ -163,12 +205,24 @@ public class OnlinePlayerManager : IDisposable
continue;
}
_onlineCachedPlayers.SingleOrDefault(p => p.PlayerNameHash == hashedName)?.InitializePlayer(pChar);
if (_temporaryStoredCharacterCache.TryGetValue(hashedName, out var cache))
{
_temporaryStoredCharacterCache.Remove(hashedName);
}
_onlineCachedPlayers.SingleOrDefault(p => p.PlayerNameHash == hashedName)?.InitializePlayer(pChar, cache);
}
Task.Run(async () => await UpdatePlayersFromService(_onlineCachedPlayers
.Where(p => p.PlayerCharacter != null && p.IsVisible && !p.WasVisible)
.ToDictionary(k => k.PlayerNameHash, k => (int)k.PlayerCharacter!.ClassJob.Id)));
var newlyVisiblePlayers = _onlineCachedPlayers
.Where(p => p.PlayerCharacter != null && p.IsVisible && !p.WasVisible).Select(p => p.PlayerNameHash)
.ToList();
if (newlyVisiblePlayers.Any() && _playerManager.LastSentCharacterData != null)
{
Task.Run(async () =>
{
await _apiController.PushCharacterData(_playerManager.LastSentCharacterData.ToCharacterCacheDto(),
newlyVisiblePlayers);
});
}
_lastPlayerObjectCheck = DateTime.Now;
}

View File

@@ -1,40 +1,41 @@
using Dalamud.Logging;
using MareSynchronos.Factories;
using MareSynchronos.Factories;
using MareSynchronos.Models;
using MareSynchronos.Utils;
using MareSynchronos.WebAPI;
using Newtonsoft.Json;
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Dalamud.Game.ClientState.Objects;
using MareSynchronos.API;
using Penumbra.GameData.Structs;
namespace MareSynchronos.Managers
{
public delegate void PlayerHasChanged(CharacterCacheDto characterCache);
public class PlayerManager : IDisposable
{
private readonly ApiController _apiController;
private readonly OnlinePlayerManager _onlinePlayerManager;
private readonly CharacterDataFactory _characterDataFactory;
private readonly DalamudUtil _dalamudUtil;
private readonly IpcManager _ipcManager;
private string _lastSentHash = string.Empty;
public event PlayerHasChanged? PlayerHasChanged;
public bool SendingData { get; private set; }
public CharacterData? LastSentCharacterData { get; private set; }
private CancellationTokenSource? _playerChangedCts;
private DateTime _lastPlayerObjectCheck;
private CharacterEquipment _currentCharacterEquipment;
private CharacterEquipment? _currentCharacterEquipment;
public PlayerManager(ApiController apiController, IpcManager ipcManager,
CharacterDataFactory characterDataFactory, OnlinePlayerManager onlinePlayerManager, DalamudUtil dalamudUtil)
CharacterDataFactory characterDataFactory, DalamudUtil dalamudUtil)
{
Logger.Debug("Creating " + nameof(PlayerManager));
_apiController = apiController;
_ipcManager = ipcManager;
_characterDataFactory = characterDataFactory;
_onlinePlayerManager = onlinePlayerManager;
_dalamudUtil = dalamudUtil;
_apiController.Connected += ApiController_Connected;
@@ -75,12 +76,6 @@ namespace MareSynchronos.Managers
private void ApiController_Connected(object? sender, EventArgs args)
{
Logger.Debug("ApiController Connected");
var apiTask = _apiController.GetOnlineCharacters();
_lastSentHash = string.Empty;
Task.WaitAll(apiTask);
_onlinePlayerManager.AddInitialPairs(apiTask.Result);
_ipcManager.PenumbraRedrawEvent += IpcManager_PenumbraRedrawEvent;
_dalamudUtil.FrameworkUpdate += DalamudUtilOnFrameworkUpdate;
@@ -154,6 +149,7 @@ namespace MareSynchronos.Managers
Task.Run(async () =>
{
SendingData = true;
int attempts = 0;
while (!_apiController.IsConnected && attempts < 10 && !token.IsCancellationRequested)
{
@@ -167,11 +163,11 @@ namespace MareSynchronos.Managers
Stopwatch st = Stopwatch.StartNew();
_dalamudUtil.WaitWhileSelfIsDrawing(token);
var characterCacheTask = await CreateFullCharacterCache(token);
var characterCache = await CreateFullCharacterCache(token);
if (token.IsCancellationRequested) return;
var cacheDto = characterCacheTask.ToCharacterCacheDto();
var cacheDto = characterCache.ToCharacterCacheDto();
st.Stop();
if (token.IsCancellationRequested)
@@ -180,13 +176,16 @@ namespace MareSynchronos.Managers
}
Logger.Debug("Elapsed time PlayerChangedTask: " + st.Elapsed);
if (cacheDto.Hash == _lastSentHash)
if (cacheDto.Hash == (LastSentCharacterData?.CacheHash ?? "-"))
{
Logger.Debug("Not sending data, already sent");
return;
}
_ = _apiController.SendCharacterData(cacheDto, _dalamudUtil.GetLocalPlayers().Select(d => d.Key).ToList());
_lastSentHash = cacheDto.Hash;
LastSentCharacterData = characterCache;
PlayerHasChanged?.Invoke(cacheDto);
SendingData = false;
}, token);
}

View File

@@ -168,10 +168,10 @@ namespace MareSynchronos
{
var characterCacheFactory =
new CharacterDataFactory(_dalamudUtil, _ipcManager);
_characterCacheManager = new OnlinePlayerManager(_framework,
_apiController, _dalamudUtil, _ipcManager);
_playerManager = new PlayerManager(_apiController, _ipcManager,
characterCacheFactory, _characterCacheManager, _dalamudUtil);
characterCacheFactory, _dalamudUtil);
_characterCacheManager = new OnlinePlayerManager(_framework,
_apiController, _dalamudUtil, _ipcManager, _playerManager);
}
catch (Exception ex)
{

View File

@@ -56,23 +56,6 @@ namespace MareSynchronos.WebAPI
foreach (var file in fileReplacementDto)
{
downloadFiles.Add(await _fileHub!.InvokeAsync<DownloadFileDto>("GetFileSize", file.Hash, ct));
/*var downloadFileDto = ;
var downloadFileTransfer = new DownloadFileTransfer(downloadFileDto);
if (CurrentDownloads.Any(f => f.Hash == downloadFileTransfer.Hash))
{
if (fileTransferList.All(f => f.Hash != downloadFileTransfer.Hash))
{
fileTransferList.Add(downloadFileTransfer);
}
continue;
}
if (fileTransferList.All(f => f.Hash != downloadFileTransfer.Hash))
{
fileTransferList.Add(downloadFileTransfer);
}
CurrentDownloads.Add(new DownloadFileTransfer(downloadFileDto));*/
}
downloadFiles = downloadFiles.Distinct().ToList();
@@ -140,7 +123,7 @@ namespace MareSynchronos.WebAPI
CurrentDownloads.RemoveAll(d => d.Transferred == d.Total);
}
public async Task SendCharacterData(CharacterCacheDto character, List<string> visibleCharacterIds)
public async Task PushCharacterData(CharacterCacheDto character, List<string> visibleCharacterIds)
{
if (!IsConnected || SecretKey == "-") return;
Logger.Debug("Sending Character data to service " + ApiUri);
@@ -155,10 +138,19 @@ namespace MareSynchronos.WebAPI
foreach (var file in filesToUpload.Where(f => !f.IsForbidden))
{
await using var db = new FileCacheContext();
CurrentUploads.Add(new UploadFileTransfer(file)
try
{
Total = new FileInfo(db.FileCaches.First(f => f.Hash == file.Hash).Filepath).Length
});
CurrentUploads.Add(new UploadFileTransfer(file)
{
Total = new FileInfo(db.FileCaches.FirstOrDefault(f => f.Hash.ToLower() == file.Hash.ToLower())
?.Filepath ?? string.Empty).Length
});
}
catch (Exception ex)
{
Logger.Warn("Tried to request file " + file.Hash + " but file was not present");
Logger.Warn(ex.StackTrace!);
}
}
foreach (var file in CurrentUploads.Where(c => c.IsForbidden))
@@ -197,7 +189,7 @@ namespace MareSynchronos.WebAPI
if (!uploadToken.IsCancellationRequested)
{
Logger.Verbose("=== Pushing character data ===");
await _userHub!.InvokeAsync("PushCharacterData", character, visibleCharacterIds, uploadToken);
await _userHub!.InvokeAsync("PushCharacterDataToVisibleClients", character, visibleCharacterIds, uploadToken);
}
else
{