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();
|
||||
}
|
||||
|
||||
Stopwatch st = Stopwatch.StartNew();
|
||||
var chara = _dalamudUtil.CreateGameObject(charaPointer)!;
|
||||
while (!_dalamudUtil.IsObjectPresent(chara))
|
||||
{
|
||||
Logger.Verbose("Character is null but it shouldn't be, waiting");
|
||||
Thread.Sleep(50);
|
||||
}
|
||||
_dalamudUtil.WaitWhileCharacterIsDrawing(charaPointer);
|
||||
//_dalamudUtil.WaitWhileCharacterIsDrawing(charaPointer);
|
||||
|
||||
Stopwatch st = Stopwatch.StartNew();
|
||||
|
||||
previousData.ManipulationString = _ipcManager.PenumbraGetMetaManipulations();
|
||||
|
||||
@@ -339,6 +340,14 @@ public class CharacterDataFactory
|
||||
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();
|
||||
Logger.Verbose("Building " + objectKind + " Data took " + st.Elapsed);
|
||||
return previousData;
|
||||
|
||||
@@ -8,7 +8,6 @@ using Dalamud.Logging;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using MareSynchronos.API;
|
||||
using MareSynchronos.FileCacheDB;
|
||||
using MareSynchronos.Interop;
|
||||
using MareSynchronos.Models;
|
||||
using MareSynchronos.Utils;
|
||||
using MareSynchronos.WebAPI;
|
||||
@@ -250,6 +249,7 @@ public class CachedPlayer
|
||||
if (minionOrMount != null)
|
||||
{
|
||||
Logger.Debug($"Request Redraw for Minion/Mount");
|
||||
_dalamudUtil.WaitWhileCharacterIsDrawing((IntPtr)minionOrMount);
|
||||
if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData))
|
||||
{
|
||||
_ipcManager.GlamourerApplyAll(glamourerData, obj: (IntPtr)minionOrMount);
|
||||
@@ -262,17 +262,29 @@ public class CachedPlayer
|
||||
}
|
||||
else if (objectKind == ObjectKind.Pet)
|
||||
{
|
||||
int tick = 16;
|
||||
var pet = _dalamudUtil.GetPet(PlayerCharacter.Address);
|
||||
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))
|
||||
{
|
||||
_ipcManager.GlamourerApplyAll(glamourerData, pet);
|
||||
_ipcManager.GlamourerApplyAll(glamourerData, newPet);
|
||||
}
|
||||
else
|
||||
{
|
||||
_ipcManager.PenumbraRedraw(pet);
|
||||
_ipcManager.PenumbraRedraw(newPet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -282,6 +294,7 @@ public class CachedPlayer
|
||||
if (companion != IntPtr.Zero)
|
||||
{
|
||||
Logger.Debug("Request Redraw for Companion");
|
||||
_dalamudUtil.WaitWhileCharacterIsDrawing(companion);
|
||||
if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData))
|
||||
{
|
||||
_ipcManager.GlamourerApplyAll(glamourerData, companion);
|
||||
|
||||
@@ -137,6 +137,7 @@ namespace MareSynchronos.Managers
|
||||
var gameObj = _dalamudUtil.CreateGameObject(obj);
|
||||
if (gameObj != null)
|
||||
{
|
||||
Logger.Verbose("Glamourer applying for " + gameObj);
|
||||
_glamourerApplyAll!.InvokeAction(customization, gameObj);
|
||||
}
|
||||
}
|
||||
@@ -205,6 +206,7 @@ namespace MareSynchronos.Managers
|
||||
var gameObj = _dalamudUtil.CreateGameObject(obj);
|
||||
if (gameObj != null)
|
||||
{
|
||||
Logger.Verbose("Redrawing " + gameObj);
|
||||
_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)
|
||||
{
|
||||
if (obj.Address == drawObj && !obj.HasUnprocessedUpdate)
|
||||
if (obj.Address == gameObj && !obj.HasUnprocessedUpdate)
|
||||
{
|
||||
obj.HasUnprocessedUpdate = true;
|
||||
OnPlayerOrAttachedObjectsChanged();
|
||||
@@ -91,7 +91,7 @@ namespace MareSynchronos.Managers
|
||||
|
||||
private unsafe void DalamudUtilOnFrameworkUpdate()
|
||||
{
|
||||
//if (!_dalamudUtil.IsPlayerPresent || !_ipcManager.Initialized) return;
|
||||
if (!_dalamudUtil.IsPlayerPresent || !_ipcManager.Initialized) return;
|
||||
|
||||
//if (DateTime.Now < _lastPlayerObjectCheck.AddSeconds(0.25)) return;
|
||||
|
||||
@@ -154,6 +154,7 @@ namespace MareSynchronos.Managers
|
||||
if (address == item.Address)
|
||||
{
|
||||
Logger.Debug("Penumbra redraw Event for " + item.ObjectKind);
|
||||
_transientResourceManager.CleanSemiTransientResources(item.ObjectKind);
|
||||
item.HasUnprocessedUpdate = true;
|
||||
}
|
||||
}
|
||||
@@ -201,7 +202,10 @@ namespace MareSynchronos.Managers
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
_dalamudUtil.WaitWhileSelfIsDrawing(token);
|
||||
foreach(var item in unprocessedObjects)
|
||||
{
|
||||
_dalamudUtil.WaitWhileCharacterIsDrawing(item.Address, token);
|
||||
}
|
||||
|
||||
CharacterCacheDto? cacheDto = (await CreateFullCharacterCacheDto(token));
|
||||
if (cacheDto == null || token.IsCancellationRequested) return;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using MareSynchronos.Models;
|
||||
using MareSynchronos.API;
|
||||
using MareSynchronos.Models;
|
||||
using MareSynchronos.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -17,6 +18,7 @@ namespace MareSynchronos.Managers
|
||||
public event TransientResourceLoadedEvent? TransientResourceLoaded;
|
||||
|
||||
private Dictionary<IntPtr, HashSet<string>> TransientResources { get; } = new();
|
||||
private Dictionary<ObjectKind, HashSet<string>> SemiTransientResources { get; } = new();
|
||||
public TransientResourceManager(IpcManager manager, DalamudUtil dalamudUtil)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (TransientResources.TryGetValue(gameObject, out var result))
|
||||
@@ -47,6 +57,16 @@ namespace MareSynchronos.Managers
|
||||
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)
|
||||
{
|
||||
if (!TransientResources.ContainsKey(gameObject))
|
||||
@@ -61,7 +81,7 @@ namespace MareSynchronos.Managers
|
||||
|
||||
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);
|
||||
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()
|
||||
{
|
||||
dalamudUtil.FrameworkUpdate -= DalamudUtil_FrameworkUpdate;
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace MareSynchronos.UI
|
||||
public CompactUi(WindowSystem windowSystem,
|
||||
UiShared uiShared, Configuration configuration, ApiController apiController)
|
||||
#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
|
||||
: base("Mare Synchronos " + Assembly.GetExecutingAssembly().GetName().Version + "###MareSynchronosMainUI")
|
||||
#endif
|
||||
|
||||
@@ -140,23 +140,26 @@ namespace MareSynchronos.Utils
|
||||
|
||||
public unsafe void WaitWhileCharacterIsDrawing(IntPtr characterAddress, CancellationToken? ct = null)
|
||||
{
|
||||
if (!_clientState.IsLoggedIn) return;
|
||||
if (!_clientState.IsLoggedIn || characterAddress == IntPtr.Zero) return;
|
||||
|
||||
var obj = (GameObject*)characterAddress;
|
||||
|
||||
const int maxWaitTime = 10000;
|
||||
const int tick = 250;
|
||||
int curWaitTime = 0;
|
||||
// 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");
|
||||
Thread.Sleep(250);
|
||||
curWaitTime += tick;
|
||||
Thread.Sleep(tick);
|
||||
}
|
||||
|
||||
if (ct?.IsCancellationRequested ?? false) return;
|
||||
// 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()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user