0.4.2: fix heels integration, potentially fix crashes, delay handling of transient resource loads, change transients to concurrent dictionary
This commit is contained in:
@@ -3,8 +3,6 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Dalamud.Game;
|
|
||||||
using Dalamud.Utility;
|
using Dalamud.Utility;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||||
@@ -40,7 +38,7 @@ public class CharacterDataFactory
|
|||||||
return playerPointer == IntPtr.Zero || ((Character*)playerPointer)->GameObject.GetDrawObject() == null;
|
return playerPointer == IntPtr.Zero || ((Character*)playerPointer)->GameObject.GetDrawObject() == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CharacterData BuildCharacterData(CharacterData previousData, ObjectKind objectKind, IntPtr playerPointer, CancellationToken token)
|
public CharacterData BuildCharacterData(CharacterData previousData, PlayerRelatedObject playerRelatedObject, CancellationToken token)
|
||||||
{
|
{
|
||||||
if (!_ipcManager.Initialized)
|
if (!_ipcManager.Initialized)
|
||||||
{
|
{
|
||||||
@@ -50,20 +48,20 @@ public class CharacterDataFactory
|
|||||||
bool pointerIsZero = true;
|
bool pointerIsZero = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
pointerIsZero = CheckForPointer(playerPointer);
|
pointerIsZero = CheckForPointer(playerRelatedObject.Address);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.Warn("Could not create data for " + objectKind);
|
Logger.Warn("Could not create data for " + playerRelatedObject.ObjectKind);
|
||||||
Logger.Warn(ex.Message);
|
Logger.Warn(ex.Message);
|
||||||
Logger.Warn(ex.StackTrace ?? string.Empty);
|
Logger.Warn(ex.StackTrace ?? string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pointerIsZero)
|
if (pointerIsZero)
|
||||||
{
|
{
|
||||||
Logger.Verbose("Pointer was zero for " + objectKind);
|
Logger.Verbose("Pointer was zero for " + playerRelatedObject.ObjectKind);
|
||||||
previousData.FileReplacements.Remove(objectKind);
|
previousData.FileReplacements.Remove(playerRelatedObject.ObjectKind);
|
||||||
previousData.GlamourerString.Remove(objectKind);
|
previousData.GlamourerString.Remove(playerRelatedObject.ObjectKind);
|
||||||
return previousData;
|
return previousData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +70,7 @@ public class CharacterDataFactory
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return CreateCharacterData(previousData, objectKind, playerPointer, token);
|
return CreateCharacterData(previousData, playerRelatedObject, token);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
@@ -80,7 +78,7 @@ public class CharacterDataFactory
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Warn("Failed to create " + objectKind + " data");
|
Logger.Warn("Failed to create " + playerRelatedObject.ObjectKind + " data");
|
||||||
Logger.Warn(e.Message);
|
Logger.Warn(e.Message);
|
||||||
Logger.Warn(e.StackTrace ?? string.Empty);
|
Logger.Warn(e.StackTrace ?? string.Empty);
|
||||||
}
|
}
|
||||||
@@ -232,66 +230,75 @@ public class CharacterDataFactory
|
|||||||
cache.AddFileReplacement(objectKind, texDx11Replacement);
|
cache.AddFileReplacement(objectKind, texDx11Replacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe CharacterData CreateCharacterData(CharacterData previousData, ObjectKind objectKind, IntPtr charaPointer, CancellationToken token)
|
private unsafe CharacterData CreateCharacterData(CharacterData previousData, PlayerRelatedObject playerRelatedObject, CancellationToken token)
|
||||||
{
|
{
|
||||||
if (previousData.FileReplacements.ContainsKey(objectKind))
|
var objectKind = playerRelatedObject.ObjectKind;
|
||||||
{
|
var charaPointer = playerRelatedObject.Address;
|
||||||
previousData.FileReplacements[objectKind].Clear();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
previousData.FileReplacements.Add(objectKind, new());
|
|
||||||
}
|
|
||||||
|
|
||||||
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(objectKind.ToString(), charaPointer);
|
|
||||||
|
|
||||||
Stopwatch st = Stopwatch.StartNew();
|
Stopwatch st = Stopwatch.StartNew();
|
||||||
|
|
||||||
previousData.ManipulationString = _ipcManager.PenumbraGetMetaManipulations();
|
if (playerRelatedObject.HasUnprocessedUpdate)
|
||||||
|
|
||||||
previousData.GlamourerString[objectKind] = _ipcManager.GlamourerGetCharacterCustomization(charaPointer);
|
|
||||||
|
|
||||||
var human = (Human*)((Character*)charaPointer)->GameObject.GetDrawObject();
|
|
||||||
for (var mdlIdx = 0; mdlIdx < human->CharacterBase.SlotCount; ++mdlIdx)
|
|
||||||
{
|
{
|
||||||
var mdl = (RenderModel*)human->CharacterBase.ModelArray[mdlIdx];
|
Logger.Debug("Handling unprocessed update for " + objectKind);
|
||||||
if (mdl == null || mdl->ResourceHandle == null || mdl->ResourceHandle->Category != ResourceCategory.Chara)
|
|
||||||
|
if (previousData.FileReplacements.ContainsKey(objectKind))
|
||||||
{
|
{
|
||||||
continue;
|
previousData.FileReplacements[objectKind].Clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
previousData.FileReplacements.Add(objectKind, new());
|
||||||
}
|
}
|
||||||
|
|
||||||
token.ThrowIfCancellationRequested();
|
var chara = _dalamudUtil.CreateGameObject(charaPointer)!;
|
||||||
|
while (!_dalamudUtil.IsObjectPresent(chara))
|
||||||
|
{
|
||||||
|
Logger.Verbose("Character is null but it shouldn't be, waiting");
|
||||||
|
Thread.Sleep(50);
|
||||||
|
}
|
||||||
|
|
||||||
AddReplacementsFromRenderModel(mdl, objectKind, previousData, 0);
|
_dalamudUtil.WaitWhileCharacterIsDrawing(objectKind.ToString(), charaPointer);
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var item in previousData.FileReplacements[objectKind])
|
var human = (Human*)((Character*)charaPointer)->GameObject.GetDrawObject();
|
||||||
{
|
for (var mdlIdx = 0; mdlIdx < human->CharacterBase.SlotCount; ++mdlIdx)
|
||||||
transientResourceManager.RemoveTransientResource(charaPointer, item);
|
{
|
||||||
}
|
var mdl = (RenderModel*)human->CharacterBase.ModelArray[mdlIdx];
|
||||||
|
if (mdl == null || mdl->ResourceHandle == null || mdl->ResourceHandle->Category != ResourceCategory.Chara)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (objectKind == ObjectKind.Player)
|
token.ThrowIfCancellationRequested();
|
||||||
{
|
|
||||||
AddPlayerSpecificReplacements(previousData, objectKind, charaPointer, human);
|
AddReplacementsFromRenderModel(mdl, objectKind, previousData, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (objectKind == ObjectKind.Pet)
|
|
||||||
{
|
|
||||||
foreach (var item in previousData.FileReplacements[objectKind])
|
foreach (var item in previousData.FileReplacements[objectKind])
|
||||||
{
|
{
|
||||||
transientResourceManager.AddSemiTransientResource(objectKind, item);
|
transientResourceManager.RemoveTransientResource(charaPointer, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
previousData.FileReplacements[objectKind].Clear();
|
if (objectKind == ObjectKind.Player)
|
||||||
|
{
|
||||||
|
AddPlayerSpecificReplacements(previousData, objectKind, charaPointer, human);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (objectKind == ObjectKind.Pet)
|
||||||
|
{
|
||||||
|
foreach (var item in previousData.FileReplacements[objectKind])
|
||||||
|
{
|
||||||
|
transientResourceManager.AddSemiTransientResource(objectKind, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
previousData.FileReplacements[objectKind].Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
previousData.ManipulationString = _ipcManager.PenumbraGetMetaManipulations();
|
||||||
|
previousData.GlamourerString[objectKind] = _ipcManager.GlamourerGetCharacterCustomization(charaPointer);
|
||||||
|
previousData.HeelsOffset = _ipcManager.GetHeelsOffset();
|
||||||
|
|
||||||
|
Logger.Debug("Handling transient update for " + objectKind);
|
||||||
ManageSemiTransientData(previousData, objectKind, charaPointer);
|
ManageSemiTransientData(previousData, objectKind, charaPointer);
|
||||||
|
|
||||||
st.Stop();
|
st.Stop();
|
||||||
@@ -387,8 +394,6 @@ public class CharacterDataFactory
|
|||||||
{
|
{
|
||||||
transientResourceManager.RemoveTransientResource(charaPointer, item);
|
transientResourceManager.RemoveTransientResource(charaPointer, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
previousData.HeelsOffset = _ipcManager.GetHeelsOffset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddReplacementSkeleton(ushort raceSexId, ObjectKind objectKind, CharacterData cache)
|
private void AddReplacementSkeleton(ushort raceSexId, ObjectKind objectKind, CharacterData cache)
|
||||||
|
|||||||
@@ -117,6 +117,17 @@ public class CachedPlayer
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (objectKind == ObjectKind.Player)
|
||||||
|
{
|
||||||
|
bool heelsOffsetDifferent = _cachedData.HeelsOffset != characterData.HeelsOffset;
|
||||||
|
if (heelsOffsetDifferent)
|
||||||
|
{
|
||||||
|
Logger.Debug("Updating " + objectKind);
|
||||||
|
charaDataToUpdate.Add(objectKind);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_cachedData = characterData;
|
_cachedData = characterData;
|
||||||
@@ -324,6 +335,7 @@ public class CachedPlayer
|
|||||||
{
|
{
|
||||||
_ipcManager.GlamourerApplyOnlyCustomization(_originalGlamourerData, PlayerCharacter);
|
_ipcManager.GlamourerApplyOnlyCustomization(_originalGlamourerData, PlayerCharacter);
|
||||||
_ipcManager.GlamourerApplyOnlyEquipment(_lastGlamourerData, PlayerCharacter);
|
_ipcManager.GlamourerApplyOnlyEquipment(_lastGlamourerData, PlayerCharacter);
|
||||||
|
_ipcManager.HeelsRestoreOffsetForPlayer(PlayerCharacter);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -207,16 +207,30 @@ namespace MareSynchronos.Managers
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void HeelsRestoreOffsetForPlayer(IntPtr character)
|
||||||
|
{
|
||||||
|
if (!CheckHeelsApi()) return;
|
||||||
|
actionQueue.Enqueue(() =>
|
||||||
|
{
|
||||||
|
var gameObj = _dalamudUtil.CreateGameObject(character);
|
||||||
|
if (gameObj != null)
|
||||||
|
{
|
||||||
|
Logger.Verbose("Restoring Heels data to " + character.ToString("X"));
|
||||||
|
_heelsUnregisterPlayer.InvokeAction(gameObj);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void GlamourerApplyAll(string? customization, IntPtr obj)
|
public void GlamourerApplyAll(string? customization, IntPtr obj)
|
||||||
{
|
{
|
||||||
if (!CheckGlamourerApi() || string.IsNullOrEmpty(customization)) return;
|
if (!CheckGlamourerApi() || string.IsNullOrEmpty(customization)) return;
|
||||||
actionQueue.Enqueue(() =>
|
actionQueue.Enqueue(() =>
|
||||||
{
|
{
|
||||||
var gameObj = _dalamudUtil.CreateGameObject(obj);
|
var gameObj = _dalamudUtil.CreateGameObject(obj);
|
||||||
if (gameObj != null)
|
if (gameObj is Character c)
|
||||||
{
|
{
|
||||||
Logger.Verbose("Glamourer applying for " + gameObj);
|
Logger.Verbose("Glamourer applying for " + c.Address.ToString("X"));
|
||||||
_glamourerApplyAll!.InvokeAction(customization, gameObj);
|
_glamourerApplyAll!.InvokeAction(customization, c);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -227,10 +241,10 @@ namespace MareSynchronos.Managers
|
|||||||
actionQueue.Enqueue(() =>
|
actionQueue.Enqueue(() =>
|
||||||
{
|
{
|
||||||
var gameObj = _dalamudUtil.CreateGameObject(character);
|
var gameObj = _dalamudUtil.CreateGameObject(character);
|
||||||
if (gameObj != null)
|
if (gameObj is Character c)
|
||||||
{
|
{
|
||||||
Logger.Verbose("Glamourer apply only equipment to " + character.ToString("X"));
|
Logger.Verbose("Glamourer apply only equipment to " + c.Address.ToString("X"));
|
||||||
_glamourerApplyOnlyEquipment!.InvokeAction(customization, gameObj);
|
_glamourerApplyOnlyEquipment!.InvokeAction(customization, c);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -241,10 +255,10 @@ namespace MareSynchronos.Managers
|
|||||||
actionQueue.Enqueue(() =>
|
actionQueue.Enqueue(() =>
|
||||||
{
|
{
|
||||||
var gameObj = _dalamudUtil.CreateGameObject(character);
|
var gameObj = _dalamudUtil.CreateGameObject(character);
|
||||||
if (gameObj != null)
|
if (gameObj is Character c)
|
||||||
{
|
{
|
||||||
Logger.Verbose("Glamourer apply only customization to " + character.ToString("X"));
|
Logger.Verbose("Glamourer apply only customization to " + c.Address.ToString("X"));
|
||||||
_glamourerApplyOnlyCustomization!.InvokeAction(customization, gameObj);
|
_glamourerApplyOnlyCustomization!.InvokeAction(customization, c);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -255,9 +269,9 @@ namespace MareSynchronos.Managers
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var gameObj = _dalamudUtil.CreateGameObject(character);
|
var gameObj = _dalamudUtil.CreateGameObject(character);
|
||||||
if (gameObj != null)
|
if (gameObj is Character c)
|
||||||
{
|
{
|
||||||
var glamourerString = _glamourerGetAllCustomization!.InvokeFunc(gameObj);
|
var glamourerString = _glamourerGetAllCustomization!.InvokeFunc(c);
|
||||||
byte[] bytes = Convert.FromBase64String(glamourerString);
|
byte[] bytes = Convert.FromBase64String(glamourerString);
|
||||||
// ignore transparency
|
// ignore transparency
|
||||||
bytes[88] = 128;
|
bytes[88] = 128;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ namespace MareSynchronos.Managers
|
|||||||
private readonly Dictionary<ObjectKind, Func<bool>> objectKindsToUpdate = new();
|
private readonly Dictionary<ObjectKind, Func<bool>> objectKindsToUpdate = new();
|
||||||
|
|
||||||
private CancellationTokenSource? _playerChangedCts = new();
|
private CancellationTokenSource? _playerChangedCts = new();
|
||||||
|
private CancellationTokenSource _transientUpdateCts = new();
|
||||||
|
|
||||||
private List<PlayerRelatedObject> playerRelatedObjects = new List<PlayerRelatedObject>();
|
private List<PlayerRelatedObject> playerRelatedObjects = new List<PlayerRelatedObject>();
|
||||||
|
|
||||||
@@ -69,8 +70,19 @@ namespace MareSynchronos.Managers
|
|||||||
{
|
{
|
||||||
if (obj.Address == gameObj && !obj.HasUnprocessedUpdate)
|
if (obj.Address == gameObj && !obj.HasUnprocessedUpdate)
|
||||||
{
|
{
|
||||||
obj.HasUnprocessedUpdate = true;
|
_transientUpdateCts.Cancel();
|
||||||
OnPlayerOrAttachedObjectsChanged();
|
_transientUpdateCts = new CancellationTokenSource();
|
||||||
|
var token = _transientUpdateCts.Token;
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
Logger.Debug("Delaying transient resource load update");
|
||||||
|
await Task.Delay(750, token);
|
||||||
|
if (obj.HasUnprocessedUpdate || token.IsCancellationRequested) return;
|
||||||
|
Logger.Debug("Firing transient resource load update");
|
||||||
|
obj.HasTransientsUpdate = true;
|
||||||
|
OnPlayerOrAttachedObjectsChanged();
|
||||||
|
}, token);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -82,7 +94,7 @@ namespace MareSynchronos.Managers
|
|||||||
if (LastCreatedCharacterData != null && LastCreatedCharacterData.HeelsOffset != change && !player.IsProcessing)
|
if (LastCreatedCharacterData != null && LastCreatedCharacterData.HeelsOffset != change && !player.IsProcessing)
|
||||||
{
|
{
|
||||||
Logger.Debug("Heels offset changed to " + change);
|
Logger.Debug("Heels offset changed to " + change);
|
||||||
playerRelatedObjects.First(f => f.ObjectKind == ObjectKind.Player).HasUnprocessedUpdate = true;
|
playerRelatedObjects.First(f => f.ObjectKind == ObjectKind.Player).HasTransientsUpdate = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,14 +141,15 @@ namespace MareSynchronos.Managers
|
|||||||
|
|
||||||
private async Task<CharacterCacheDto?> CreateFullCharacterCacheDto(CancellationToken token)
|
private async Task<CharacterCacheDto?> CreateFullCharacterCacheDto(CancellationToken token)
|
||||||
{
|
{
|
||||||
foreach (var unprocessedObject in playerRelatedObjects.Where(c => c.HasUnprocessedUpdate).ToList())
|
foreach (var unprocessedObject in playerRelatedObjects.Where(c => c.HasUnprocessedUpdate || c.HasTransientsUpdate).ToList())
|
||||||
{
|
{
|
||||||
Logger.Verbose("Building Cache for " + unprocessedObject.ObjectKind);
|
Logger.Verbose("Building Cache for " + unprocessedObject.ObjectKind);
|
||||||
PermanentDataCache = _characterDataFactory.BuildCharacterData(PermanentDataCache, unprocessedObject.ObjectKind, unprocessedObject.Address, token);
|
PermanentDataCache = _characterDataFactory.BuildCharacterData(PermanentDataCache, unprocessedObject, token);
|
||||||
if (!token.IsCancellationRequested)
|
if (!token.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
unprocessedObject.HasUnprocessedUpdate = false;
|
unprocessedObject.HasUnprocessedUpdate = false;
|
||||||
unprocessedObject.IsProcessing = false;
|
unprocessedObject.IsProcessing = false;
|
||||||
|
unprocessedObject.HasTransientsUpdate = false;
|
||||||
}
|
}
|
||||||
token.ThrowIfCancellationRequested();
|
token.ThrowIfCancellationRequested();
|
||||||
}
|
}
|
||||||
@@ -165,7 +178,6 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,7 +190,7 @@ namespace MareSynchronos.Managers
|
|||||||
|
|
||||||
private void OnPlayerOrAttachedObjectsChanged()
|
private void OnPlayerOrAttachedObjectsChanged()
|
||||||
{
|
{
|
||||||
var unprocessedObjects = playerRelatedObjects.Where(c => c.HasUnprocessedUpdate).ToList();
|
var unprocessedObjects = playerRelatedObjects.Where(c => c.HasUnprocessedUpdate || c.HasTransientsUpdate).ToList();
|
||||||
foreach (var unprocessedObject in unprocessedObjects)
|
foreach (var unprocessedObject in unprocessedObjects)
|
||||||
{
|
{
|
||||||
unprocessedObject.IsProcessing = true;
|
unprocessedObject.IsProcessing = true;
|
||||||
|
|||||||
@@ -2,8 +2,11 @@
|
|||||||
using MareSynchronos.Models;
|
using MareSynchronos.Models;
|
||||||
using MareSynchronos.Utils;
|
using MareSynchronos.Utils;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace MareSynchronos.Managers
|
namespace MareSynchronos.Managers
|
||||||
{
|
{
|
||||||
@@ -16,8 +19,9 @@ namespace MareSynchronos.Managers
|
|||||||
|
|
||||||
public event TransientResourceLoadedEvent? TransientResourceLoaded;
|
public event TransientResourceLoadedEvent? TransientResourceLoaded;
|
||||||
|
|
||||||
private Dictionary<IntPtr, HashSet<string>> TransientResources { get; } = new();
|
private ConcurrentDictionary<IntPtr, HashSet<string>> TransientResources { get; } = new();
|
||||||
private Dictionary<ObjectKind, HashSet<FileReplacement>> SemiTransientResources { get; } = new();
|
private ConcurrentDictionary<ObjectKind, HashSet<FileReplacement>> SemiTransientResources { get; } = new();
|
||||||
|
private CancellationTokenSource transientInvokeDelayCts = new CancellationTokenSource();
|
||||||
public TransientResourceManager(IpcManager manager, DalamudUtil dalamudUtil)
|
public TransientResourceManager(IpcManager manager, DalamudUtil dalamudUtil)
|
||||||
{
|
{
|
||||||
manager.PenumbraResourceLoadEvent += Manager_PenumbraResourceLoadEvent;
|
manager.PenumbraResourceLoadEvent += Manager_PenumbraResourceLoadEvent;
|
||||||
@@ -42,7 +46,7 @@ namespace MareSynchronos.Managers
|
|||||||
if (!dalamudUtil.IsGameObjectPresent(item.Key))
|
if (!dalamudUtil.IsGameObjectPresent(item.Key))
|
||||||
{
|
{
|
||||||
Logger.Debug("Object not present anymore: " + item.Key.ToString("X"));
|
Logger.Debug("Object not present anymore: " + item.Key.ToString("X"));
|
||||||
TransientResources.Remove(item.Key);
|
TransientResources.TryRemove(item.Key, out _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,13 +142,23 @@ namespace MareSynchronos.Managers
|
|||||||
SemiTransientResources[objectKind].RemoveWhere(f => f.GamePaths.First().ToLowerInvariant() == item.ToLowerInvariant());
|
SemiTransientResources[objectKind].RemoveWhere(f => f.GamePaths.First().ToLowerInvariant() == item.ToLowerInvariant());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SemiTransientResources[objectKind].Any(f => f.GamePaths.First().ToLowerInvariant() == item.ToLowerInvariant()))
|
try
|
||||||
{
|
{
|
||||||
Logger.Debug("Persisting " + item.ToLowerInvariant());
|
if (!SemiTransientResources[objectKind].Any(f => f.GamePaths.First().ToLowerInvariant() == item.ToLowerInvariant()))
|
||||||
var fileReplacement = createFileReplacement(item.ToLowerInvariant(), true);
|
{
|
||||||
if (!fileReplacement.HasFileReplacement)
|
Logger.Debug("Persisting " + item.ToLowerInvariant());
|
||||||
fileReplacement = createFileReplacement(item.ToLowerInvariant(), false);
|
|
||||||
SemiTransientResources[objectKind].Add(fileReplacement);
|
var fileReplacement = createFileReplacement(item.ToLowerInvariant(), true);
|
||||||
|
if (!fileReplacement.HasFileReplacement)
|
||||||
|
fileReplacement = createFileReplacement(item.ToLowerInvariant(), false);
|
||||||
|
SemiTransientResources[objectKind].Add(fileReplacement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Warn("Issue during transient file persistence");
|
||||||
|
Logger.Warn(ex.Message);
|
||||||
|
Logger.Warn(ex.StackTrace.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors></Authors>
|
<Authors></Authors>
|
||||||
<Company></Company>
|
<Company></Company>
|
||||||
<Version>0.4.1</Version>
|
<Version>0.4.2</Version>
|
||||||
<Description></Description>
|
<Description></Description>
|
||||||
<Copyright></Copyright>
|
<Copyright></Copyright>
|
||||||
<PackageProjectUrl>https://github.com/Penumbra-Sync/client</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/Penumbra-Sync/client</PackageProjectUrl>
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ namespace MareSynchronos.Models
|
|||||||
|
|
||||||
public void SetResolvedPath(string path)
|
public void SetResolvedPath(string path)
|
||||||
{
|
{
|
||||||
ResolvedPath = path.ToLowerInvariant().Replace('/', '\\').Replace(_penumbraDirectory, "").Replace('\\', '/');
|
ResolvedPath = path.ToLowerInvariant();//.Replace('/', '\\').Replace(_penumbraDirectory, "").Replace('\\', '/');
|
||||||
if (!HasFileReplacement || IsFileSwap) return;
|
if (!HasFileReplacement || IsFileSwap) return;
|
||||||
|
|
||||||
_ = Task.Run(() =>
|
_ = Task.Run(() =>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using Penumbra.GameData.ByteString;
|
|||||||
|
|
||||||
namespace MareSynchronos.Models
|
namespace MareSynchronos.Models
|
||||||
{
|
{
|
||||||
internal class PlayerRelatedObject
|
public class PlayerRelatedObject
|
||||||
{
|
{
|
||||||
private readonly Func<IntPtr> getAddress;
|
private readonly Func<IntPtr> getAddress;
|
||||||
|
|
||||||
@@ -46,6 +46,7 @@ namespace MareSynchronos.Models
|
|||||||
public byte? HatState { get; set; }
|
public byte? HatState { get; set; }
|
||||||
public byte? VisorWeaponState { get; set; }
|
public byte? VisorWeaponState { get; set; }
|
||||||
|
|
||||||
|
public bool HasTransientsUpdate { get; set; } = false;
|
||||||
public bool HasUnprocessedUpdate { get; set; } = false;
|
public bool HasUnprocessedUpdate { get; set; } = false;
|
||||||
public bool DoNotSendUpdate { get; set; } = false;
|
public bool DoNotSendUpdate { get; set; } = false;
|
||||||
public bool IsProcessing { get; set; } = false;
|
public bool IsProcessing { get; set; } = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user