add semi transient resource handling, wait max 3s for pets to change
This commit is contained in:
@@ -237,14 +237,15 @@ public class CharacterDataFactory
|
|||||||
previousData.FileReplacements[objectKind].Clear();
|
previousData.FileReplacements[objectKind].Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Stopwatch st = Stopwatch.StartNew();
|
|
||||||
var chara = _dalamudUtil.CreateGameObject(charaPointer)!;
|
var chara = _dalamudUtil.CreateGameObject(charaPointer)!;
|
||||||
while (!_dalamudUtil.IsObjectPresent(chara))
|
while (!_dalamudUtil.IsObjectPresent(chara))
|
||||||
{
|
{
|
||||||
Logger.Verbose("Character is null but it shouldn't be, waiting");
|
Logger.Verbose("Character is null but it shouldn't be, waiting");
|
||||||
Thread.Sleep(50);
|
Thread.Sleep(50);
|
||||||
}
|
}
|
||||||
_dalamudUtil.WaitWhileCharacterIsDrawing(charaPointer);
|
//_dalamudUtil.WaitWhileCharacterIsDrawing(charaPointer);
|
||||||
|
|
||||||
|
Stopwatch st = Stopwatch.StartNew();
|
||||||
|
|
||||||
previousData.ManipulationString = _ipcManager.PenumbraGetMetaManipulations();
|
previousData.ManipulationString = _ipcManager.PenumbraGetMetaManipulations();
|
||||||
|
|
||||||
@@ -339,6 +340,14 @@ public class CharacterDataFactory
|
|||||||
AddReplacement(item, objectKind, previousData, 1);
|
AddReplacement(item, objectKind, previousData, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var item in transientResourceManager.GetSemiTransientResources(objectKind))
|
||||||
|
{
|
||||||
|
Logger.Verbose("Found semi transient resource: " + item);
|
||||||
|
AddReplacement(item, objectKind, previousData, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
transientResourceManager.PersistTransientResources(charaPointer, objectKind);
|
||||||
|
|
||||||
st.Stop();
|
st.Stop();
|
||||||
Logger.Verbose("Building " + objectKind + " Data took " + st.Elapsed);
|
Logger.Verbose("Building " + objectKind + " Data took " + st.Elapsed);
|
||||||
return previousData;
|
return previousData;
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ using Dalamud.Logging;
|
|||||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||||
using MareSynchronos.API;
|
using MareSynchronos.API;
|
||||||
using MareSynchronos.FileCacheDB;
|
using MareSynchronos.FileCacheDB;
|
||||||
using MareSynchronos.Interop;
|
|
||||||
using MareSynchronos.Models;
|
using MareSynchronos.Models;
|
||||||
using MareSynchronos.Utils;
|
using MareSynchronos.Utils;
|
||||||
using MareSynchronos.WebAPI;
|
using MareSynchronos.WebAPI;
|
||||||
@@ -250,6 +249,7 @@ public class CachedPlayer
|
|||||||
if (minionOrMount != null)
|
if (minionOrMount != null)
|
||||||
{
|
{
|
||||||
Logger.Debug($"Request Redraw for Minion/Mount");
|
Logger.Debug($"Request Redraw for Minion/Mount");
|
||||||
|
_dalamudUtil.WaitWhileCharacterIsDrawing((IntPtr)minionOrMount);
|
||||||
if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData))
|
if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData))
|
||||||
{
|
{
|
||||||
_ipcManager.GlamourerApplyAll(glamourerData, obj: (IntPtr)minionOrMount);
|
_ipcManager.GlamourerApplyAll(glamourerData, obj: (IntPtr)minionOrMount);
|
||||||
@@ -262,17 +262,29 @@ public class CachedPlayer
|
|||||||
}
|
}
|
||||||
else if (objectKind == ObjectKind.Pet)
|
else if (objectKind == ObjectKind.Pet)
|
||||||
{
|
{
|
||||||
|
int tick = 16;
|
||||||
var pet = _dalamudUtil.GetPet(PlayerCharacter.Address);
|
var pet = _dalamudUtil.GetPet(PlayerCharacter.Address);
|
||||||
if (pet != IntPtr.Zero)
|
if (pet != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
Logger.Debug("Request Redraw for Pet");
|
var totalWait = 0;
|
||||||
|
var newPet = IntPtr.Zero;
|
||||||
|
const int maxWait = 3000;
|
||||||
|
Logger.Debug($"Request Redraw for Pet, waiting {maxWait}ms");
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Thread.Sleep(tick);
|
||||||
|
totalWait += tick;
|
||||||
|
newPet = _dalamudUtil.GetPet(PlayerCharacter.Address);
|
||||||
|
} while (newPet == pet && totalWait < maxWait);
|
||||||
|
|
||||||
if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData))
|
if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData))
|
||||||
{
|
{
|
||||||
_ipcManager.GlamourerApplyAll(glamourerData, pet);
|
_ipcManager.GlamourerApplyAll(glamourerData, newPet);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_ipcManager.PenumbraRedraw(pet);
|
_ipcManager.PenumbraRedraw(newPet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,6 +294,7 @@ public class CachedPlayer
|
|||||||
if (companion != IntPtr.Zero)
|
if (companion != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
Logger.Debug("Request Redraw for Companion");
|
Logger.Debug("Request Redraw for Companion");
|
||||||
|
_dalamudUtil.WaitWhileCharacterIsDrawing(companion);
|
||||||
if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData))
|
if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData))
|
||||||
{
|
{
|
||||||
_ipcManager.GlamourerApplyAll(glamourerData, companion);
|
_ipcManager.GlamourerApplyAll(glamourerData, companion);
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ namespace MareSynchronos.Managers
|
|||||||
var gameObj = _dalamudUtil.CreateGameObject(obj);
|
var gameObj = _dalamudUtil.CreateGameObject(obj);
|
||||||
if (gameObj != null)
|
if (gameObj != null)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose("Glamourer applying for " + gameObj);
|
||||||
_glamourerApplyAll!.InvokeAction(customization, gameObj);
|
_glamourerApplyAll!.InvokeAction(customization, gameObj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -205,6 +206,7 @@ namespace MareSynchronos.Managers
|
|||||||
var gameObj = _dalamudUtil.CreateGameObject(obj);
|
var gameObj = _dalamudUtil.CreateGameObject(obj);
|
||||||
if (gameObj != null)
|
if (gameObj != null)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose("Redrawing " + gameObj);
|
||||||
_penumbraRedrawObject!.InvokeAction(gameObj, 0);
|
_penumbraRedrawObject!.InvokeAction(gameObj, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,11 +61,11 @@ namespace MareSynchronos.Managers
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandleTransientResourceLoad(IntPtr drawObj)
|
public void HandleTransientResourceLoad(IntPtr gameObj)
|
||||||
{
|
{
|
||||||
foreach (var obj in playerRelatedObjects)
|
foreach (var obj in playerRelatedObjects)
|
||||||
{
|
{
|
||||||
if (obj.Address == drawObj && !obj.HasUnprocessedUpdate)
|
if (obj.Address == gameObj && !obj.HasUnprocessedUpdate)
|
||||||
{
|
{
|
||||||
obj.HasUnprocessedUpdate = true;
|
obj.HasUnprocessedUpdate = true;
|
||||||
OnPlayerOrAttachedObjectsChanged();
|
OnPlayerOrAttachedObjectsChanged();
|
||||||
@@ -91,7 +91,7 @@ namespace MareSynchronos.Managers
|
|||||||
|
|
||||||
private unsafe void DalamudUtilOnFrameworkUpdate()
|
private unsafe void DalamudUtilOnFrameworkUpdate()
|
||||||
{
|
{
|
||||||
//if (!_dalamudUtil.IsPlayerPresent || !_ipcManager.Initialized) return;
|
if (!_dalamudUtil.IsPlayerPresent || !_ipcManager.Initialized) return;
|
||||||
|
|
||||||
//if (DateTime.Now < _lastPlayerObjectCheck.AddSeconds(0.25)) return;
|
//if (DateTime.Now < _lastPlayerObjectCheck.AddSeconds(0.25)) return;
|
||||||
|
|
||||||
@@ -154,6 +154,7 @@ namespace MareSynchronos.Managers
|
|||||||
if (address == item.Address)
|
if (address == item.Address)
|
||||||
{
|
{
|
||||||
Logger.Debug("Penumbra redraw Event for " + item.ObjectKind);
|
Logger.Debug("Penumbra redraw Event for " + item.ObjectKind);
|
||||||
|
_transientResourceManager.CleanSemiTransientResources(item.ObjectKind);
|
||||||
item.HasUnprocessedUpdate = true;
|
item.HasUnprocessedUpdate = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,7 +202,10 @@ namespace MareSynchronos.Managers
|
|||||||
|
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
_dalamudUtil.WaitWhileSelfIsDrawing(token);
|
foreach(var item in unprocessedObjects)
|
||||||
|
{
|
||||||
|
_dalamudUtil.WaitWhileCharacterIsDrawing(item.Address, token);
|
||||||
|
}
|
||||||
|
|
||||||
CharacterCacheDto? cacheDto = (await CreateFullCharacterCacheDto(token));
|
CharacterCacheDto? cacheDto = (await CreateFullCharacterCacheDto(token));
|
||||||
if (cacheDto == null || token.IsCancellationRequested) return;
|
if (cacheDto == null || token.IsCancellationRequested) return;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using MareSynchronos.Models;
|
using MareSynchronos.API;
|
||||||
|
using MareSynchronos.Models;
|
||||||
using MareSynchronos.Utils;
|
using MareSynchronos.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -17,6 +18,7 @@ namespace MareSynchronos.Managers
|
|||||||
public event TransientResourceLoadedEvent? TransientResourceLoaded;
|
public event TransientResourceLoadedEvent? TransientResourceLoaded;
|
||||||
|
|
||||||
private Dictionary<IntPtr, HashSet<string>> TransientResources { get; } = new();
|
private Dictionary<IntPtr, HashSet<string>> TransientResources { get; } = new();
|
||||||
|
private Dictionary<ObjectKind, HashSet<string>> SemiTransientResources { get; } = new();
|
||||||
public TransientResourceManager(IpcManager manager, DalamudUtil dalamudUtil)
|
public TransientResourceManager(IpcManager manager, DalamudUtil dalamudUtil)
|
||||||
{
|
{
|
||||||
manager.PenumbraResourceLoadEvent += Manager_PenumbraResourceLoadEvent;
|
manager.PenumbraResourceLoadEvent += Manager_PenumbraResourceLoadEvent;
|
||||||
@@ -37,6 +39,14 @@ namespace MareSynchronos.Managers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CleanSemiTransientResources(ObjectKind objectKind)
|
||||||
|
{
|
||||||
|
if (SemiTransientResources.ContainsKey(objectKind))
|
||||||
|
{
|
||||||
|
SemiTransientResources[objectKind].Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public List<string> GetTransientResources(IntPtr gameObject)
|
public List<string> GetTransientResources(IntPtr gameObject)
|
||||||
{
|
{
|
||||||
if (TransientResources.TryGetValue(gameObject, out var result))
|
if (TransientResources.TryGetValue(gameObject, out var result))
|
||||||
@@ -47,6 +57,16 @@ namespace MareSynchronos.Managers
|
|||||||
return new List<string>();
|
return new List<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<string> GetSemiTransientResources(ObjectKind objectKind)
|
||||||
|
{
|
||||||
|
if (SemiTransientResources.TryGetValue(objectKind, out var result))
|
||||||
|
{
|
||||||
|
return result.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new List<string>();
|
||||||
|
}
|
||||||
|
|
||||||
private void Manager_PenumbraResourceLoadEvent(IntPtr gameObject, string gamePath, string filePath)
|
private void Manager_PenumbraResourceLoadEvent(IntPtr gameObject, string gamePath, string filePath)
|
||||||
{
|
{
|
||||||
if (!TransientResources.ContainsKey(gameObject))
|
if (!TransientResources.ContainsKey(gameObject))
|
||||||
@@ -61,7 +81,7 @@ namespace MareSynchronos.Managers
|
|||||||
|
|
||||||
var newPath = filePath.ToLowerInvariant().Replace("\\", "/");
|
var newPath = filePath.ToLowerInvariant().Replace("\\", "/");
|
||||||
|
|
||||||
if (filePath != gamePath && !TransientResources[gameObject].Contains(newPath))
|
if (filePath != gamePath && !TransientResources[gameObject].Contains(newPath) && !SemiTransientResources.Any(r => r.Value.Contains(newPath)))
|
||||||
{
|
{
|
||||||
TransientResources[gameObject].Add(newPath);
|
TransientResources[gameObject].Add(newPath);
|
||||||
Logger.Debug($"Adding {filePath.ToLowerInvariant().Replace("\\", "/")} for {gameObject}");
|
Logger.Debug($"Adding {filePath.ToLowerInvariant().Replace("\\", "/")} for {gameObject}");
|
||||||
@@ -69,14 +89,36 @@ namespace MareSynchronos.Managers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveTransientResource(IntPtr drawObject, FileReplacement fileReplacement)
|
public void RemoveTransientResource(IntPtr gameObject, FileReplacement fileReplacement)
|
||||||
{
|
{
|
||||||
if (TransientResources.ContainsKey(drawObject))
|
if (TransientResources.ContainsKey(gameObject))
|
||||||
{
|
{
|
||||||
TransientResources[drawObject].RemoveWhere(f => fileReplacement.ResolvedPath == f);
|
TransientResources[gameObject].RemoveWhere(f => fileReplacement.ResolvedPath == f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void PersistTransientResources(IntPtr gameObject, ObjectKind objectKind)
|
||||||
|
{
|
||||||
|
if (!SemiTransientResources.ContainsKey(objectKind))
|
||||||
|
{
|
||||||
|
SemiTransientResources[objectKind] = new HashSet<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TransientResources.TryGetValue(gameObject, out var resources))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var transientResources = resources.ToList();
|
||||||
|
Logger.Debug("Persisting " + transientResources.Count + " transient resources");
|
||||||
|
foreach (var item in transientResources)
|
||||||
|
{
|
||||||
|
SemiTransientResources[objectKind].Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
TransientResources[gameObject].Clear();
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
dalamudUtil.FrameworkUpdate -= DalamudUtil_FrameworkUpdate;
|
dalamudUtil.FrameworkUpdate -= DalamudUtil_FrameworkUpdate;
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ namespace MareSynchronos.UI
|
|||||||
public CompactUi(WindowSystem windowSystem,
|
public CompactUi(WindowSystem windowSystem,
|
||||||
UiShared uiShared, Configuration configuration, ApiController apiController)
|
UiShared uiShared, Configuration configuration, ApiController apiController)
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
: base("Mare Synchronos " + new FileInfo(Assembly.GetExecutingAssembly().Location) .LastWriteTime.ToString("yyyyMMddHHmmss")+ "###MareSynchronosMainUI")
|
: base("Mare Synchronos " + new FileInfo(Assembly.GetExecutingAssembly().Location).LastWriteTime.ToString("yyyyMMddHHmmss")+ "###MareSynchronosMainUI")
|
||||||
#else
|
#else
|
||||||
: base("Mare Synchronos " + Assembly.GetExecutingAssembly().GetName().Version + "###MareSynchronosMainUI")
|
: base("Mare Synchronos " + Assembly.GetExecutingAssembly().GetName().Version + "###MareSynchronosMainUI")
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -140,23 +140,26 @@ namespace MareSynchronos.Utils
|
|||||||
|
|
||||||
public unsafe void WaitWhileCharacterIsDrawing(IntPtr characterAddress, CancellationToken? ct = null)
|
public unsafe void WaitWhileCharacterIsDrawing(IntPtr characterAddress, CancellationToken? ct = null)
|
||||||
{
|
{
|
||||||
if (!_clientState.IsLoggedIn) return;
|
if (!_clientState.IsLoggedIn || characterAddress == IntPtr.Zero) return;
|
||||||
|
|
||||||
var obj = (GameObject*)characterAddress;
|
var obj = (GameObject*)characterAddress;
|
||||||
|
const int maxWaitTime = 10000;
|
||||||
|
const int tick = 250;
|
||||||
|
int curWaitTime = 0;
|
||||||
// ReSharper disable once LoopVariableIsNeverChangedInsideLoop
|
// ReSharper disable once LoopVariableIsNeverChangedInsideLoop
|
||||||
while ((obj->RenderFlags & 0b100000000000) == 0b100000000000 && (!ct?.IsCancellationRequested ?? true)) // 0b100000000000 is "still rendering" or something
|
while ((obj->RenderFlags & 0b100000000000) == 0b100000000000 && (!ct?.IsCancellationRequested ?? true) && curWaitTime < maxWaitTime) // 0b100000000000 is "still rendering" or something
|
||||||
{
|
{
|
||||||
Logger.Verbose("Waiting for character to finish drawing");
|
Logger.Verbose("Waiting for character to finish drawing");
|
||||||
Thread.Sleep(250);
|
curWaitTime += tick;
|
||||||
|
Thread.Sleep(tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ct?.IsCancellationRequested ?? false) return;
|
if (ct?.IsCancellationRequested ?? false) return;
|
||||||
// wait quarter a second just in case
|
// wait quarter a second just in case
|
||||||
Thread.Sleep(250);
|
Thread.Sleep(tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WaitWhileSelfIsDrawing(CancellationToken? token) => WaitWhileCharacterIsDrawing(_clientState.LocalPlayer?.Address ?? new IntPtr(), token);
|
public void WaitWhileSelfIsDrawing(CancellationToken? token) => WaitWhileCharacterIsDrawing(_clientState.LocalPlayer?.Address ?? IntPtr.Zero, token);
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user