why did I start writing this plugin
This commit is contained in:
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user