why did I start writing this plugin

This commit is contained in:
Stanley Dimant
2022-06-27 12:31:41 +02:00
parent 61b178e2c0
commit c7439ac769
7 changed files with 53 additions and 39 deletions

View File

@@ -43,13 +43,17 @@ namespace MareSynchronos.Factories
private unsafe CharacterData CreateCharacterData() private unsafe CharacterData CreateCharacterData()
{ {
Stopwatch st = Stopwatch.StartNew(); Stopwatch st = Stopwatch.StartNew();
var cache = new CharacterData();
while (!_dalamudUtil.IsPlayerPresent) while (!_dalamudUtil.IsPlayerPresent)
{ {
Logger.Debug("Character is null but it shouldn't be, waiting"); Logger.Debug("Character is null but it shouldn't be, waiting");
Thread.Sleep(50); Thread.Sleep(50);
} }
var cache = new CharacterData
{
JobId = _dalamudUtil.PlayerJobId,
GlamourerString = _ipcManager.GlamourerGetCharacterCustomization(_dalamudUtil.PlayerName),
ManipulationString = _ipcManager.PenumbraGetMetaManipulations(_dalamudUtil.PlayerName)
};
var model = (CharacterBase*)((Character*)_dalamudUtil.PlayerPointer)->GameObject.GetDrawObject(); var model = (CharacterBase*)((Character*)_dalamudUtil.PlayerPointer)->GameObject.GetDrawObject();
for (var idx = 0; idx < model->SlotCount; ++idx) for (var idx = 0; idx < model->SlotCount; ++idx)
{ {
@@ -107,10 +111,6 @@ namespace MareSynchronos.Factories
} }
} }
cache.GlamourerString = _ipcManager.GlamourerGetCharacterCustomization(_dalamudUtil.PlayerName)!;
cache.ManipulationString = _ipcManager.PenumbraGetMetaManipulations(_dalamudUtil.PlayerName);
cache.JobId = _dalamudUtil.PlayerJobId;
st.Stop(); st.Stop();
Logger.Debug("Building Character Data took " + st.Elapsed); Logger.Debug("Building Character Data took " + st.Elapsed);

View File

@@ -144,7 +144,7 @@ namespace MareSynchronos.Managers
{ {
try try
{ {
using var fs = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None); using var fs = file.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
} }
catch catch
{ {

View File

@@ -21,6 +21,7 @@ namespace MareSynchronos.Managers
private readonly IpcManager _ipcManager; private readonly IpcManager _ipcManager;
private string _lastSentHash = string.Empty; private string _lastSentHash = string.Empty;
private Task? _playerChangedTask; private Task? _playerChangedTask;
private CancellationTokenSource? _playerChangedCts;
public PlayerManager(ApiController apiController, IpcManager ipcManager, public PlayerManager(ApiController apiController, IpcManager ipcManager,
CharacterDataFactory characterDataFactory, CachedPlayersManager cachedPlayersManager, DalamudUtil dalamudUtil) CharacterDataFactory characterDataFactory, CachedPlayersManager cachedPlayersManager, DalamudUtil dalamudUtil)
@@ -77,21 +78,23 @@ namespace MareSynchronos.Managers
_dalamudUtil.PlayerChanged -= Watcher_PlayerChanged; _dalamudUtil.PlayerChanged -= Watcher_PlayerChanged;
} }
private async Task<CharacterData> CreateFullCharacterCache() private async Task<CharacterData> CreateFullCharacterCache(CancellationToken token)
{ {
var cache = _characterDataFactory.BuildCharacterData(); var cache = _characterDataFactory.BuildCharacterData();
await Task.Run(async () => await Task.Run(async () =>
{ {
while (!cache.IsReady) while (!cache.IsReady && !token.IsCancellationRequested)
{ {
await Task.Delay(50); await Task.Delay(50, token);
} }
if (token.IsCancellationRequested) return;
var json = JsonConvert.SerializeObject(cache, Formatting.Indented); var json = JsonConvert.SerializeObject(cache, Formatting.Indented);
cache.CacheHash = Crypto.GetHash(json); cache.CacheHash = Crypto.GetHash(json);
}); }, token);
return cache; return cache;
} }
@@ -108,11 +111,14 @@ namespace MareSynchronos.Managers
{ {
//if (sender == null) return; //if (sender == null) return;
Logger.Debug("Player changed: " + name); Logger.Debug("Player changed: " + name);
_playerChangedCts?.Cancel();
_playerChangedCts = new CancellationTokenSource();
var token = _playerChangedCts.Token;/*
if (_playerChangedTask is { IsCompleted: false }) if (_playerChangedTask is { IsCompleted: false })
{ {
PluginLog.Warning("PlayerChanged Task still running"); PluginLog.Warning("PlayerChanged Task still running");
return; return;
} }*/
if (!_ipcManager.Initialized) if (!_ipcManager.Initialized)
{ {
@@ -123,23 +129,30 @@ namespace MareSynchronos.Managers
_playerChangedTask = Task.Run(async () => _playerChangedTask = Task.Run(async () =>
{ {
int attempts = 0; int attempts = 0;
while (!_apiController.IsConnected && attempts < 10) while (!_apiController.IsConnected && attempts < 10 && !token.IsCancellationRequested)
{ {
Logger.Warn("No connection to the API"); Logger.Warn("No connection to the API");
await Task.Delay(TimeSpan.FromSeconds(1)); await Task.Delay(TimeSpan.FromSeconds(1), token);
attempts++; attempts++;
} }
if (attempts == 10) return; if (attempts == 10 || token.IsCancellationRequested) return;
Stopwatch st = Stopwatch.StartNew(); Stopwatch st = Stopwatch.StartNew();
_dalamudUtil.WaitWhileSelfIsDrawing(); _dalamudUtil.WaitWhileSelfIsDrawing(token);
var characterCacheTask = await CreateFullCharacterCache(); var characterCacheTask = await CreateFullCharacterCache(token);
if (token.IsCancellationRequested) return;
var cacheDto = characterCacheTask.ToCharacterCacheDto(); var cacheDto = characterCacheTask.ToCharacterCacheDto();
st.Stop(); st.Stop();
if (token.IsCancellationRequested)
{
return;
}
Logger.Debug("Elapsed time PlayerChangedTask: " + st.Elapsed); Logger.Debug("Elapsed time PlayerChangedTask: " + st.Elapsed);
if (cacheDto.Hash == _lastSentHash) if (cacheDto.Hash == _lastSentHash)
{ {
@@ -148,7 +161,7 @@ namespace MareSynchronos.Managers
} }
_ = _apiController.SendCharacterData(cacheDto, _dalamudUtil.GetLocalPlayers().Select(d => d.Key).ToList()); _ = _apiController.SendCharacterData(cacheDto, _dalamudUtil.GetLocalPlayers().Select(d => d.Key).ToList());
_lastSentHash = cacheDto.Hash; _lastSentHash = cacheDto.Hash;
}); }, token);
} }
private void Watcher_PlayerChanged(Dalamud.Game.ClientState.Objects.Types.Character actor) private void Watcher_PlayerChanged(Dalamud.Game.ClientState.Objects.Types.Character actor)

View File

@@ -70,12 +70,12 @@ public class CachedPlayer
{ {
Logger.Debug("Received total " + e.CharacterData.FileReplacements.Count + " file replacement data"); Logger.Debug("Received total " + e.CharacterData.FileReplacements.Count + " file replacement data");
_cache[e.CharacterData.Hash] = e.CharacterData; _cache[e.CharacterData.Hash] = e.CharacterData;
_lastAppliedEquipmentHash = e.CharacterData.Hash;
} }
else else
{ {
Logger.Debug("Had valid local cache for " + PlayerName); Logger.Debug("Had valid local cache for " + PlayerName);
} }
_lastAppliedEquipmentHash = e.CharacterData.Hash;
DownloadAndApplyCharacter(); DownloadAndApplyCharacter();
} }
@@ -158,15 +158,19 @@ public class CachedPlayer
try try
{ {
Logger.Debug("Restoring state for " + PlayerName); Logger.Debug("Restoring state for " + PlayerName);
IsVisible = false;
_downloadCancellationTokenSource?.Cancel(); _downloadCancellationTokenSource?.Cancel();
_downloadCancellationTokenSource?.Dispose(); _downloadCancellationTokenSource?.Dispose();
_downloadCancellationTokenSource = null; _downloadCancellationTokenSource = null;
_dalamudUtil.RemovePlayerFromWatch(PlayerName); _dalamudUtil.RemovePlayerFromWatch(PlayerName);
_ipcManager.PenumbraRemoveTemporaryCollection(PlayerName); _ipcManager.PenumbraRemoveTemporaryCollection(PlayerName);
_ipcManager.GlamourerRevertCharacterCustomization(PlayerName); if (IsVisible)
_ipcManager.GlamourerApplyOnlyCustomization(_originalGlamourerData, PlayerName); {
_ipcManager.GlamourerApplyOnlyEquipment(_lastGlamourerData, PlayerName); _ipcManager.GlamourerRevertCharacterCustomization(PlayerName);
_ipcManager.GlamourerApplyOnlyCustomization(_originalGlamourerData, PlayerName);
_ipcManager.GlamourerApplyOnlyEquipment(_lastGlamourerData, PlayerName);
}
IsVisible = false;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -215,6 +219,7 @@ public class CachedPlayer
if (RequestedPenumbraRedraw == false && !string.IsNullOrEmpty(_lastAppliedEquipmentHash)) if (RequestedPenumbraRedraw == false && !string.IsNullOrEmpty(_lastAppliedEquipmentHash))
{ {
Logger.Warn("Unauthorized character change detected");
DownloadAndApplyCharacter(); DownloadAndApplyCharacter();
} }
else else

View File

@@ -50,7 +50,7 @@ public class DownloadUi : Window, IDisposable
var basePosition = ImGui.GetWindowPos() + ImGui.GetWindowContentRegionMin(); var basePosition = ImGui.GetWindowPos() + ImGui.GetWindowContentRegionMin();
if (_apiController.IsUploading) if (_apiController.CurrentUploads.Any())
{ {
var doneUploads = _apiController.CurrentUploads.Count(c => c.Value.Item1 == c.Value.Item2); var doneUploads = _apiController.CurrentUploads.Count(c => c.Value.Item1 == c.Value.Item2);
var totalUploads = _apiController.CurrentUploads.Keys.Count; var totalUploads = _apiController.CurrentUploads.Keys.Count;
@@ -67,9 +67,9 @@ public class DownloadUi : Window, IDisposable
UiShared.Color(255, 255, 255, 255), UiShared.Color(0, 0, 0, 255), 2); UiShared.Color(255, 255, 255, 255), UiShared.Color(0, 0, 0, 255), 2);
} }
if (_apiController.IsDownloading) if (_apiController.CurrentDownloads.Any())
{ {
var multBase = _apiController.IsDownloading ? 0 : 2; var multBase = _apiController.CurrentUploads.Any() ? 0 : 2;
var doneDownloads = _apiController.CurrentDownloads.Count(c => c.Value.Item1 == c.Value.Item2); var doneDownloads = _apiController.CurrentDownloads.Count(c => c.Value.Item1 == c.Value.Item2);
var totalDownloads = _apiController.CurrentDownloads.Keys.Count; var totalDownloads = _apiController.CurrentDownloads.Keys.Count;
var totalDownloaded = _apiController.CurrentDownloads.Sum(c => c.Value.Item1); var totalDownloaded = _apiController.CurrentDownloads.Sum(c => c.Value.Item1);

View File

@@ -100,24 +100,25 @@ namespace MareSynchronos.Utils
return null; return null;
} }
public unsafe void WaitWhileCharacterIsDrawing(IntPtr characterAddress) public unsafe void WaitWhileCharacterIsDrawing(IntPtr characterAddress, CancellationToken? ct = null)
{ {
if (!_clientState.IsLoggedIn) return; if (!_clientState.IsLoggedIn) return;
var obj = (GameObject*)characterAddress; var obj = (GameObject*)characterAddress;
// ReSharper disable once LoopVariableIsNeverChangedInsideLoop // ReSharper disable once LoopVariableIsNeverChangedInsideLoop
while ((obj->RenderFlags & 0b100000000000) == 0b100000000000) // 0b100000000000 is "still rendering" or something while ((obj->RenderFlags & 0b100000000000) == 0b100000000000 && (!ct?.IsCancellationRequested ?? true)) // 0b100000000000 is "still rendering" or something
{ {
Logger.Debug("Waiting for character to finish drawing"); Logger.Debug("Waiting for character to finish drawing");
Thread.Sleep(1000); Thread.Sleep(1000);
} }
if (ct?.IsCancellationRequested ?? false) return;
// wait half a second just in case // wait half a second just in case
Thread.Sleep(500); Thread.Sleep(500);
} }
public void WaitWhileSelfIsDrawing() => WaitWhileCharacterIsDrawing(_clientState.LocalPlayer?.Address ?? new IntPtr()); public void WaitWhileSelfIsDrawing(CancellationToken token) => WaitWhileCharacterIsDrawing(_clientState.LocalPlayer?.Address ?? new IntPtr(), token);
public void Dispose() public void Dispose()
{ {

View File

@@ -247,19 +247,14 @@ namespace MareSynchronos.WebAPI
public async Task<string> DownloadFile(string hash, CancellationToken ct) public async Task<string> DownloadFile(string hash, CancellationToken ct)
{ {
var reader = await _fileHub!.StreamAsChannelAsync<byte[]>("DownloadFile", hash, ct); var reader = _fileHub!.StreamAsync<byte[]>("DownloadFileAsync", hash, ct);
int i = 0;
string fileName = Path.GetTempFileName(); string fileName = Path.GetTempFileName();
await using var fs = File.OpenWrite(fileName); await using var fs = File.OpenWrite(fileName);
while (await reader.WaitToReadAsync(ct) && !ct.IsCancellationRequested) await foreach (var data in reader.WithCancellation(ct))
{ {
while (reader.TryRead(out var data) && !ct.IsCancellationRequested) CurrentDownloads[hash] = (CurrentDownloads[hash].Item1 + data.Length, CurrentDownloads[hash].Item2);
{ await fs.WriteAsync(data, ct);
CurrentDownloads[hash] = (CurrentDownloads[hash].Item1 + data.Length, CurrentDownloads[hash].Item2);
await fs.WriteAsync(data, ct);
}
} }
return fileName; return fileName;
} }