various fixes and improvements for drawing checks and data sending
This commit is contained in:
@@ -185,9 +185,9 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase
|
|||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
Logger.LogDebug("Penumbra Mod Settings changed, verifying SemiTransientResources");
|
Logger.LogDebug("Penumbra Mod Settings changed, verifying SemiTransientResources");
|
||||||
foreach (var item in SemiTransientResources)
|
foreach (var item in _playerRelatedPointers)
|
||||||
{
|
{
|
||||||
Mediator.Publish(new TransientResourceChangedMessage(_dalamudUtil.GetPlayerPointer()));
|
Mediator.Publish(new TransientResourceChangedMessage(item.Address));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -170,24 +170,30 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
|
|||||||
public async Task CustomizePlusRevertAsync(IntPtr character)
|
public async Task CustomizePlusRevertAsync(IntPtr character)
|
||||||
{
|
{
|
||||||
if (!CheckCustomizePlusApi()) return;
|
if (!CheckCustomizePlusApi()) return;
|
||||||
var gameObj = await _dalamudUtil.CreateGameObjectAsync(character).ConfigureAwait(false);
|
await _dalamudUtil.RunOnFrameworkThread(() =>
|
||||||
if (gameObj is Character c)
|
|
||||||
{
|
{
|
||||||
Logger.LogTrace("CustomizePlus reverting for {chara}", c.Address.ToString("X"));
|
var gameObj = _dalamudUtil.CreateGameObject(character);
|
||||||
await _dalamudUtil.RunOnFrameworkThread(() => _customizePlusRevert!.InvokeAction(c)).ConfigureAwait(false);
|
if (gameObj is Character c)
|
||||||
}
|
{
|
||||||
|
Logger.LogTrace("CustomizePlus reverting for {chara}", c.Address.ToString("X"));
|
||||||
|
_customizePlusRevert!.InvokeAction(c);
|
||||||
|
}
|
||||||
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task CustomizePlusSetBodyScaleAsync(IntPtr character, string scale)
|
public async Task CustomizePlusSetBodyScaleAsync(IntPtr character, string scale)
|
||||||
{
|
{
|
||||||
if (!CheckCustomizePlusApi() || string.IsNullOrEmpty(scale)) return;
|
if (!CheckCustomizePlusApi() || string.IsNullOrEmpty(scale)) return;
|
||||||
var gameObj = await _dalamudUtil.CreateGameObjectAsync(character).ConfigureAwait(false);
|
await _dalamudUtil.RunOnFrameworkThread(() =>
|
||||||
if (gameObj is Character c)
|
|
||||||
{
|
{
|
||||||
string decodedScale = Encoding.UTF8.GetString(Convert.FromBase64String(scale));
|
var gameObj = _dalamudUtil.CreateGameObject(character);
|
||||||
Logger.LogTrace("CustomizePlus applying for {chara}", c.Address.ToString("X"));
|
if (gameObj is Character c)
|
||||||
await _dalamudUtil.RunOnFrameworkThread(() => _customizePlusSetBodyScaleToCharacter!.InvokeAction(decodedScale, c)).ConfigureAwait(false);
|
{
|
||||||
}
|
string decodedScale = Encoding.UTF8.GetString(Convert.FromBase64String(scale));
|
||||||
|
Logger.LogTrace("CustomizePlus applying for {chara}", c.Address.ToString("X"));
|
||||||
|
_customizePlusSetBodyScaleToCharacter!.InvokeAction(decodedScale, c);
|
||||||
|
}
|
||||||
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> GetCustomizePlusScaleAsync()
|
public async Task<string> GetCustomizePlusScaleAsync()
|
||||||
@@ -198,10 +204,10 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
|
|||||||
return Convert.ToBase64String(Encoding.UTF8.GetBytes(scale));
|
return Convert.ToBase64String(Encoding.UTF8.GetBytes(scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
public float GetHeelsOffset()
|
public async Task<float> GetHeelsOffsetAsync()
|
||||||
{
|
{
|
||||||
if (!CheckHeelsApi()) return 0.0f;
|
if (!CheckHeelsApi()) return 0.0f;
|
||||||
return _heelsGetOffset.InvokeFunc();
|
return await _dalamudUtil.RunOnFrameworkThread(_heelsGetOffset.InvokeFunc).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task GlamourerApplyAllAsync(ILogger logger, GameObjectHandler handler, string? customization, Guid applicationId, CancellationToken token, bool fireAndForget = false)
|
public async Task GlamourerApplyAllAsync(ILogger logger, GameObjectHandler handler, string? customization, Guid applicationId, CancellationToken token, bool fireAndForget = false)
|
||||||
@@ -210,15 +216,12 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _redrawSemaphore.WaitAsync(token).ConfigureAwait(false);
|
await _redrawSemaphore.WaitAsync(token).ConfigureAwait(false);
|
||||||
var gameObj = await _dalamudUtil.CreateGameObjectAsync(handler.Address).ConfigureAwait(false);
|
|
||||||
if (gameObj is Character c)
|
await PenumbraRedrawInternalAsync(logger, handler, applicationId, (chara) =>
|
||||||
{
|
{
|
||||||
await PenumbraRedrawAsync(logger, handler, applicationId, () =>
|
logger.LogDebug("[{appid}] Calling on IPC: GlamourerApplyAll", applicationId);
|
||||||
{
|
_glamourerApplyAll!.InvokeAction(customization, chara);
|
||||||
logger.LogDebug("[{appid}] Calling on IPC: GlamourerApplyAll", applicationId);
|
}).ConfigureAwait(false);
|
||||||
_glamourerApplyAll!.InvokeAction(customization, c);
|
|
||||||
}).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -232,20 +235,16 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _redrawSemaphore.WaitAsync(token).ConfigureAwait(false);
|
await _redrawSemaphore.WaitAsync(token).ConfigureAwait(false);
|
||||||
var gameObj = await _dalamudUtil.CreateGameObjectAsync(handler.Address).ConfigureAwait(false);
|
await PenumbraRedrawInternalAsync(logger, handler, applicationid, (chara) =>
|
||||||
if (gameObj is Character c)
|
|
||||||
{
|
{
|
||||||
await PenumbraRedrawAsync(logger, handler, applicationid, () =>
|
logger.LogDebug("[{appid}] Calling on IPC: GlamourerApplyOnlyCustomization", applicationid);
|
||||||
{
|
_glamourerApplyOnlyCustomization!.InvokeAction(customization, chara);
|
||||||
logger.LogDebug("[{appid}] Calling on IPC: GlamourerApplyOnlyCustomization", applicationid);
|
}).ConfigureAwait(false);
|
||||||
_glamourerApplyOnlyCustomization!.InvokeAction(customization, c);
|
await PenumbraRedrawInternalAsync(logger, handler, applicationid, (chara) =>
|
||||||
}).ConfigureAwait(false);
|
{
|
||||||
await PenumbraRedrawAsync(logger, handler, applicationid, () =>
|
logger.LogDebug("[{appid}] Calling on IPC: GlamourerApplyOnlyEquipment", applicationid);
|
||||||
{
|
_glamourerApplyOnlyEquipment!.InvokeAction(equipment, chara);
|
||||||
logger.LogDebug("[{appid}] Calling on IPC: GlamourerApplyOnlyEquipment", applicationid);
|
}).ConfigureAwait(false);
|
||||||
_glamourerApplyOnlyEquipment!.InvokeAction(equipment, c);
|
|
||||||
}).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -258,17 +257,20 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
|
|||||||
if (!CheckGlamourerApi()) return string.Empty;
|
if (!CheckGlamourerApi()) return string.Empty;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var gameObj = await _dalamudUtil.CreateGameObjectAsync(character).ConfigureAwait(false);
|
return await _dalamudUtil.RunOnFrameworkThread(() =>
|
||||||
if (gameObj is Character c)
|
|
||||||
{
|
{
|
||||||
var glamourerString = await _dalamudUtil.RunOnFrameworkThread(() => _glamourerGetAllCustomization!.InvokeFunc(c)).ConfigureAwait(false);
|
var gameObj = _dalamudUtil.CreateGameObject(character);
|
||||||
byte[] bytes = Convert.FromBase64String(glamourerString);
|
if (gameObj is Character c)
|
||||||
// ignore transparency
|
{
|
||||||
bytes[88] = 128;
|
var glamourerString = _glamourerGetAllCustomization!.InvokeFunc(c);
|
||||||
bytes[89] = 63;
|
byte[] bytes = Convert.FromBase64String(glamourerString);
|
||||||
return Convert.ToBase64String(bytes);
|
// ignore transparency
|
||||||
}
|
bytes[88] = 128;
|
||||||
return string.Empty;
|
bytes[89] = 63;
|
||||||
|
return Convert.ToBase64String(bytes);
|
||||||
|
}
|
||||||
|
return string.Empty;
|
||||||
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -279,34 +281,43 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
|
|||||||
public async Task HeelsRestoreOffsetForPlayerAsync(IntPtr character)
|
public async Task HeelsRestoreOffsetForPlayerAsync(IntPtr character)
|
||||||
{
|
{
|
||||||
if (!CheckHeelsApi()) return;
|
if (!CheckHeelsApi()) return;
|
||||||
var gameObj = await _dalamudUtil.CreateGameObjectAsync(character).ConfigureAwait(false);
|
await _dalamudUtil.RunOnFrameworkThread(() =>
|
||||||
if (gameObj != null)
|
|
||||||
{
|
{
|
||||||
Logger.LogTrace("Restoring Heels data to {chara}", character.ToString("X"));
|
var gameObj = _dalamudUtil.CreateGameObject(character);
|
||||||
await _dalamudUtil.RunOnFrameworkThread(() => _heelsUnregisterPlayer.InvokeAction(gameObj)).ConfigureAwait(false);
|
if (gameObj != null)
|
||||||
}
|
{
|
||||||
|
Logger.LogTrace("Restoring Heels data to {chara}", character.ToString("X"));
|
||||||
|
_heelsUnregisterPlayer.InvokeAction(gameObj);
|
||||||
|
}
|
||||||
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task HeelsSetOffsetForPlayerAsync(IntPtr character, float offset)
|
public async Task HeelsSetOffsetForPlayerAsync(IntPtr character, float offset)
|
||||||
{
|
{
|
||||||
if (!CheckHeelsApi()) return;
|
if (!CheckHeelsApi()) return;
|
||||||
var gameObj = await _dalamudUtil.CreateGameObjectAsync(character).ConfigureAwait(false);
|
await _dalamudUtil.RunOnFrameworkThread(() =>
|
||||||
if (gameObj != null)
|
|
||||||
{
|
{
|
||||||
Logger.LogTrace("Applying Heels data to {chara}", character.ToString("X"));
|
var gameObj = _dalamudUtil.CreateGameObject(character);
|
||||||
await _dalamudUtil.RunOnFrameworkThread(() => _heelsRegisterPlayer.InvokeAction(gameObj, offset)).ConfigureAwait(false);
|
if (gameObj != null)
|
||||||
}
|
{
|
||||||
|
Logger.LogTrace("Applying Heels data to {chara}", character.ToString("X"));
|
||||||
|
_heelsRegisterPlayer.InvokeAction(gameObj, offset);
|
||||||
|
}
|
||||||
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task HonorificClearTitleAsync(nint character)
|
public async Task HonorificClearTitleAsync(nint character)
|
||||||
{
|
{
|
||||||
if (!CheckHonorificApi()) return;
|
if (!CheckHonorificApi()) return;
|
||||||
var gameObj = await _dalamudUtil.CreateGameObjectAsync(character).ConfigureAwait(false);
|
await _dalamudUtil.RunOnFrameworkThread(() =>
|
||||||
if (gameObj is PlayerCharacter c)
|
|
||||||
{
|
{
|
||||||
Logger.LogTrace("Honorific removing for {addr}", c.Address.ToString("X"));
|
var gameObj = _dalamudUtil.CreateGameObject(character);
|
||||||
await _dalamudUtil.RunOnFrameworkThread(() => _honorificClearCharacterTitle!.InvokeAction(c)).ConfigureAwait(false);
|
if (gameObj is PlayerCharacter c)
|
||||||
}
|
{
|
||||||
|
Logger.LogTrace("Honorific removing for {addr}", c.Address.ToString("X"));
|
||||||
|
_honorificClearCharacterTitle!.InvokeAction(c);
|
||||||
|
}
|
||||||
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string HonorificGetTitle()
|
public string HonorificGetTitle()
|
||||||
@@ -320,10 +331,10 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
if (!CheckHonorificApi()) return;
|
if (!CheckHonorificApi()) return;
|
||||||
Logger.LogTrace("Applying Honorific data to {chara}", character.ToString("X"));
|
Logger.LogTrace("Applying Honorific data to {chara}", character.ToString("X"));
|
||||||
var gameObj = await _dalamudUtil.CreateGameObjectAsync(character).ConfigureAwait(false);
|
await _dalamudUtil.RunOnFrameworkThread(() =>
|
||||||
if (gameObj is PlayerCharacter pc)
|
|
||||||
{
|
{
|
||||||
await _dalamudUtil.RunOnFrameworkThread(() =>
|
var gameObj = _dalamudUtil.CreateGameObject(character);
|
||||||
|
if (gameObj is PlayerCharacter pc)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(honorificData))
|
if (string.IsNullOrEmpty(honorificData))
|
||||||
{
|
{
|
||||||
@@ -333,8 +344,8 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
_honorificSetCharacterTitle!.InvokeAction(pc, honorificData[1..], honorificData[0] == '1');
|
_honorificSetCharacterTitle!.InvokeAction(pc, honorificData[1..], honorificData[0] == '1');
|
||||||
}
|
}
|
||||||
}).ConfigureAwait(false);
|
}
|
||||||
}
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> PalettePlusBuildPaletteAsync()
|
public async Task<string> PalettePlusBuildPaletteAsync()
|
||||||
@@ -348,22 +359,25 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
|
|||||||
public async Task PalettePlusRemovePaletteAsync(IntPtr character)
|
public async Task PalettePlusRemovePaletteAsync(IntPtr character)
|
||||||
{
|
{
|
||||||
if (!CheckPalettePlusApi()) return;
|
if (!CheckPalettePlusApi()) return;
|
||||||
var gameObj = await _dalamudUtil.CreateGameObjectAsync(character).ConfigureAwait(false);
|
await _dalamudUtil.RunOnFrameworkThread(() =>
|
||||||
if (gameObj is Character c)
|
|
||||||
{
|
{
|
||||||
Logger.LogTrace("PalettePlus removing for {addr}", c.Address.ToString("X"));
|
var gameObj = _dalamudUtil.CreateGameObject(character);
|
||||||
await _dalamudUtil.RunOnFrameworkThread(() => _palettePlusRemoveCharaPalette!.InvokeAction(c)).ConfigureAwait(false);
|
if (gameObj is Character c)
|
||||||
}
|
{
|
||||||
|
Logger.LogTrace("PalettePlus removing for {addr}", c.Address.ToString("X"));
|
||||||
|
_palettePlusRemoveCharaPalette!.InvokeAction(c);
|
||||||
|
}
|
||||||
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PalettePlusSetPaletteAsync(IntPtr character, string palette)
|
public async Task PalettePlusSetPaletteAsync(IntPtr character, string palette)
|
||||||
{
|
{
|
||||||
if (!CheckPalettePlusApi()) return;
|
if (!CheckPalettePlusApi()) return;
|
||||||
string decodedPalette = Encoding.UTF8.GetString(Convert.FromBase64String(palette));
|
string decodedPalette = Encoding.UTF8.GetString(Convert.FromBase64String(palette));
|
||||||
var gameObj = await _dalamudUtil.CreateGameObjectAsync(character).ConfigureAwait(false);
|
await _dalamudUtil.RunOnFrameworkThread(() =>
|
||||||
if (gameObj is Character c)
|
|
||||||
{
|
{
|
||||||
await _dalamudUtil.RunOnFrameworkThread(() =>
|
var gameObj = _dalamudUtil.CreateGameObject(character);
|
||||||
|
if (gameObj is Character c)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(decodedPalette))
|
if (string.IsNullOrEmpty(decodedPalette))
|
||||||
{
|
{
|
||||||
@@ -375,8 +389,8 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
|
|||||||
Logger.LogTrace("PalettePlus applying for {addr}", c.Address.ToString("X"));
|
Logger.LogTrace("PalettePlus applying for {addr}", c.Address.ToString("X"));
|
||||||
_palettePlusSetCharaPalette!.InvokeAction(c, decodedPalette);
|
_palettePlusSetCharaPalette!.InvokeAction(c, decodedPalette);
|
||||||
}
|
}
|
||||||
}).ConfigureAwait(false);
|
}
|
||||||
}
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string PenumbraGetMetaManipulations()
|
public string PenumbraGetMetaManipulations()
|
||||||
@@ -385,21 +399,17 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
|
|||||||
return _penumbraGetMetaManipulations.Invoke();
|
return _penumbraGetMetaManipulations.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PenumbraRedrawAsync(ILogger logger, GameObjectHandler handler, Guid applicationId, CancellationToken token, bool fireAndForget = false)
|
public async Task PenumbraRedrawAsync(ILogger logger, GameObjectHandler handler, Guid applicationId, CancellationToken token)
|
||||||
{
|
{
|
||||||
if (!CheckPenumbraApi() || _dalamudUtil.IsZoning) return;
|
if (!CheckPenumbraApi() || _dalamudUtil.IsZoning) return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _redrawSemaphore.WaitAsync(token).ConfigureAwait(false);
|
await _redrawSemaphore.WaitAsync(token).ConfigureAwait(false);
|
||||||
var gameObj = await _dalamudUtil.CreateGameObjectAsync(handler.Address).ConfigureAwait(false);
|
await PenumbraRedrawInternalAsync(logger, handler, applicationId, (chara) =>
|
||||||
if (gameObj is Character c)
|
|
||||||
{
|
{
|
||||||
await PenumbraRedrawAsync(logger, handler, applicationId, () =>
|
logger.LogDebug("[{appid}] Calling on IPC: PenumbraRedraw", applicationId);
|
||||||
{
|
_penumbraRedrawObject!.Invoke(chara, RedrawType.Redraw);
|
||||||
logger.LogDebug("[{appid}] Calling on IPC: PenumbraRedraw", applicationId);
|
}).ConfigureAwait(false);
|
||||||
_penumbraRedrawObject!.Invoke(c, RedrawType.Redraw);
|
|
||||||
}).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -442,6 +452,7 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
|
|||||||
logger.LogTrace("[{applicationId}] Change: {from} => {to}", applicationId, mod.Key, mod.Value);
|
logger.LogTrace("[{applicationId}] Change: {from} => {to}", applicationId, mod.Key, mod.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.LogTrace("[{applicationId}] Manip: {data}", applicationId, manipulationData);
|
||||||
var ret2 = _penumbraAddTemporaryMod.Invoke("MareChara", collName, modPaths, manipulationData, 0);
|
var ret2 = _penumbraAddTemporaryMod.Invoke("MareChara", collName, modPaths, manipulationData, 0);
|
||||||
logger.LogTrace("[{applicationId}] Setting temp mods for {collName}, Success: {ret2}", applicationId, collName, ret2);
|
logger.LogTrace("[{applicationId}] Setting temp mods for {collName}, Success: {ret2}", applicationId, collName, ret2);
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
@@ -650,29 +661,27 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
|
|||||||
_penumbraRedraw!.Invoke("self", RedrawType.Redraw);
|
_penumbraRedraw!.Invoke("self", RedrawType.Redraw);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task PenumbraRedrawAsync(ILogger logger, GameObjectHandler obj, Guid applicationId, Action action)
|
private async Task PenumbraRedrawInternalAsync(ILogger logger, GameObjectHandler handler, Guid applicationId, Action<Character> action)
|
||||||
{
|
{
|
||||||
Mediator.Publish(new PenumbraStartRedrawMessage(obj.Address));
|
Mediator.Publish(new PenumbraStartRedrawMessage(handler.Address));
|
||||||
|
|
||||||
_penumbraRedrawRequests[obj.Address] = true;
|
_penumbraRedrawRequests[handler.Address] = true;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
CancellationTokenSource cancelToken = new CancellationTokenSource();
|
CancellationTokenSource cancelToken = new CancellationTokenSource();
|
||||||
cancelToken.CancelAfter(TimeSpan.FromSeconds(15));
|
cancelToken.CancelAfter(TimeSpan.FromSeconds(15));
|
||||||
await obj.ActOnFrameworkAfterEnsureNoDrawAsync(action, cancelToken.Token);
|
await handler.ActOnFrameworkAfterEnsureNoDrawAsync(action, cancelToken.Token).ConfigureAwait(false);
|
||||||
|
|
||||||
await Task.Delay(TimeSpan.FromSeconds(1), _disposalCts.Token).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (!_disposalCts.Token.IsCancellationRequested)
|
if (!_disposalCts.Token.IsCancellationRequested)
|
||||||
await _dalamudUtil.WaitWhileCharacterIsDrawing(logger, obj, applicationId, 30000, _disposalCts.Token).ConfigureAwait(false);
|
await _dalamudUtil.WaitWhileCharacterIsDrawing(logger, handler, applicationId, 30000, _disposalCts.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_penumbraRedrawRequests[obj.Address] = false;
|
_penumbraRedrawRequests[handler.Address] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mediator.Publish(new PenumbraEndRedrawMessage(obj.Address));
|
Mediator.Publish(new PenumbraEndRedrawMessage(handler.Address));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PeriodicApiStateCheck()
|
private void PeriodicApiStateCheck()
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors></Authors>
|
<Authors></Authors>
|
||||||
<Company></Company>
|
<Company></Company>
|
||||||
<Version>0.8.32</Version>
|
<Version>0.8.33</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>
|
||||||
|
|||||||
@@ -375,7 +375,7 @@ public class PlayerDataFactory
|
|||||||
|
|
||||||
// gather up data from ipc
|
// gather up data from ipc
|
||||||
previousData.ManipulationString = _ipcManager.PenumbraGetMetaManipulations();
|
previousData.ManipulationString = _ipcManager.PenumbraGetMetaManipulations();
|
||||||
previousData.HeelsOffset = _ipcManager.GetHeelsOffset();
|
Task<float> getHeelsOffset = _ipcManager.GetHeelsOffsetAsync();
|
||||||
Task<string> getGlamourerData = _ipcManager.GlamourerGetCharacterCustomizationAsync(playerRelatedObject.Address);
|
Task<string> getGlamourerData = _ipcManager.GlamourerGetCharacterCustomizationAsync(playerRelatedObject.Address);
|
||||||
Task<string> getCustomizeData = _ipcManager.GetCustomizePlusScaleAsync();
|
Task<string> getCustomizeData = _ipcManager.GetCustomizePlusScaleAsync();
|
||||||
Task<string> getPalettePlusData = _ipcManager.PalettePlusBuildPaletteAsync();
|
Task<string> getPalettePlusData = _ipcManager.PalettePlusBuildPaletteAsync();
|
||||||
@@ -387,6 +387,8 @@ public class PlayerDataFactory
|
|||||||
_logger.LogDebug("Palette is now: {data}", previousData.PalettePlusPalette);
|
_logger.LogDebug("Palette is now: {data}", previousData.PalettePlusPalette);
|
||||||
previousData.HonorificData = _ipcManager.HonorificGetTitle();
|
previousData.HonorificData = _ipcManager.HonorificGetTitle();
|
||||||
_logger.LogDebug("Honorific is now: {data}", previousData.HonorificData);
|
_logger.LogDebug("Honorific is now: {data}", previousData.HonorificData);
|
||||||
|
previousData.HeelsOffset = await getHeelsOffset.ConfigureAwait(false);
|
||||||
|
_logger.LogDebug("Heels is now: {heels}", previousData.HeelsOffset);
|
||||||
|
|
||||||
st.Stop();
|
st.Stop();
|
||||||
_logger.LogInformation("Building character data for {obj} took {time}ms", objectKind, TimeSpan.FromTicks(st.ElapsedTicks).TotalMilliseconds);
|
_logger.LogInformation("Building character data for {obj} took {time}ms", objectKind, TimeSpan.FromTicks(st.ElapsedTicks).TotalMilliseconds);
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
|
||||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
|
||||||
using MareSynchronos.Services;
|
using MareSynchronos.Services;
|
||||||
using MareSynchronos.Services.Mediator;
|
using MareSynchronos.Services.Mediator;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@@ -61,6 +59,7 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase
|
|||||||
Mediator.Subscribe<CutsceneEndMessage>(this, (_) =>
|
Mediator.Subscribe<CutsceneEndMessage>(this, (_) =>
|
||||||
{
|
{
|
||||||
_haltProcessing = false;
|
_haltProcessing = false;
|
||||||
|
ZoneSwitchEnd();
|
||||||
});
|
});
|
||||||
Mediator.Subscribe<PenumbraStartRedrawMessage>(this, (msg) =>
|
Mediator.Subscribe<PenumbraStartRedrawMessage>(this, (msg) =>
|
||||||
{
|
{
|
||||||
@@ -93,12 +92,16 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase
|
|||||||
private IntPtr DrawObjectAddress { get; set; }
|
private IntPtr DrawObjectAddress { get; set; }
|
||||||
private byte[] EquipSlotData { get; set; } = new byte[40];
|
private byte[] EquipSlotData { get; set; } = new byte[40];
|
||||||
|
|
||||||
public async Task ActOnFrameworkAfterEnsureNoDrawAsync(Action act, CancellationToken token)
|
public async Task ActOnFrameworkAfterEnsureNoDrawAsync(Action<Dalamud.Game.ClientState.Objects.Types.Character> act, CancellationToken token)
|
||||||
{
|
{
|
||||||
while (await _dalamudUtil.RunOnFrameworkThread(() =>
|
while (await _dalamudUtil.RunOnFrameworkThread(() =>
|
||||||
{
|
{
|
||||||
if (IsBeingDrawn()) return true;
|
if (IsBeingDrawn()) return true;
|
||||||
act();
|
var gameObj = _dalamudUtil.CreateGameObject(Address);
|
||||||
|
if (gameObj is Dalamud.Game.ClientState.Objects.Types.Character chara)
|
||||||
|
{
|
||||||
|
act.Invoke(chara);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}).ConfigureAwait(false))
|
}).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
@@ -117,6 +120,12 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase
|
|||||||
return _dalamudUtil.CreateGameObject(Address);
|
return _dalamudUtil.CreateGameObject(Address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Invalidate()
|
||||||
|
{
|
||||||
|
Address = IntPtr.Zero;
|
||||||
|
DrawObjectAddress = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<bool> IsBeingDrawnRunOnFrameworkAsync()
|
public async Task<bool> IsBeingDrawnRunOnFrameworkAsync()
|
||||||
{
|
{
|
||||||
return await _dalamudUtil.RunOnFrameworkThread(IsBeingDrawn).ConfigureAwait(false);
|
return await _dalamudUtil.RunOnFrameworkThread(IsBeingDrawn).ConfigureAwait(false);
|
||||||
@@ -146,7 +155,7 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase
|
|||||||
Address = _getAddress();
|
Address = _getAddress();
|
||||||
if (Address != IntPtr.Zero)
|
if (Address != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
var drawObjAddr = (IntPtr)((GameObject*)Address)->DrawObject;
|
var drawObjAddr = (IntPtr)((FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)Address)->DrawObject;
|
||||||
DrawObjectAddress = drawObjAddr;
|
DrawObjectAddress = drawObjAddr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -165,7 +174,7 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase
|
|||||||
_clearCts?.Cancel();
|
_clearCts?.Cancel();
|
||||||
_clearCts = null;
|
_clearCts = null;
|
||||||
}
|
}
|
||||||
var chara = (Character*)Address;
|
var chara = (FFXIVClientStructs.FFXIV.Client.Game.Character.Character*)Address;
|
||||||
var name = new ByteString(chara->GameObject.Name).ToString();
|
var name = new ByteString(chara->GameObject.Name).ToString();
|
||||||
bool nameChange = !string.Equals(name, Name, StringComparison.Ordinal);
|
bool nameChange = !string.Equals(name, Name, StringComparison.Ordinal);
|
||||||
Name = name;
|
Name = name;
|
||||||
@@ -259,11 +268,17 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase
|
|||||||
private unsafe IntPtr GetDrawObj(nint curPtr)
|
private unsafe IntPtr GetDrawObj(nint curPtr)
|
||||||
{
|
{
|
||||||
Logger.LogTrace("[{this}] IsBeingDrawnRunOnFramework, Getting new DrawObject", this);
|
Logger.LogTrace("[{this}] IsBeingDrawnRunOnFramework, Getting new DrawObject", this);
|
||||||
return (IntPtr)((GameObject*)curPtr)->DrawObject;
|
return (IntPtr)((FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)curPtr)->DrawObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsBeingDrawn()
|
private bool IsBeingDrawn()
|
||||||
{
|
{
|
||||||
|
if (_dalamudUtil.IsAnythingDrawing)
|
||||||
|
{
|
||||||
|
Logger.LogTrace("[{this}] IsBeingDrawnRunOnFramework, Global draw block", this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
var curPtr = _getAddress();
|
var curPtr = _getAddress();
|
||||||
Logger.LogTrace("[{this}] IsBeingDrawnRunOnFramework, CurPtr: {ptr}", this, curPtr.ToString("X"));
|
Logger.LogTrace("[{this}] IsBeingDrawnRunOnFramework, CurPtr: {ptr}", this, curPtr.ToString("X"));
|
||||||
|
|
||||||
@@ -289,7 +304,7 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase
|
|||||||
var drawObjZero = drawObj == IntPtr.Zero;
|
var drawObjZero = drawObj == IntPtr.Zero;
|
||||||
Logger.LogTrace("[{this}] IsBeingDrawnRunOnFramework, Condition IsDrawObjZero: {cond}", this, drawObjZero);
|
Logger.LogTrace("[{this}] IsBeingDrawnRunOnFramework, Condition IsDrawObjZero: {cond}", this, drawObjZero);
|
||||||
if (drawObjZero) return true;
|
if (drawObjZero) return true;
|
||||||
var renderFlags = (((GameObject*)curPtr)->RenderFlags) != 0x0;
|
var renderFlags = (((FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)curPtr)->RenderFlags) != 0x0;
|
||||||
Logger.LogTrace("[{this}] IsBeingDrawnRunOnFramework, Condition RenderFlags: {cond}", this, renderFlags);
|
Logger.LogTrace("[{this}] IsBeingDrawnRunOnFramework, Condition RenderFlags: {cond}", this, renderFlags);
|
||||||
if (renderFlags) return true;
|
if (renderFlags) return true;
|
||||||
var modelInSlotLoaded = (((CharacterBase*)drawObj)->HasModelInSlotLoaded != 0);
|
var modelInSlotLoaded = (((CharacterBase*)drawObj)->HasModelInSlotLoaded != 0);
|
||||||
@@ -303,7 +318,7 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
return drawObj == IntPtr.Zero
|
return drawObj == IntPtr.Zero
|
||||||
|| ((GameObject*)curPtr)->RenderFlags != 0x0;
|
|| ((FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)curPtr)->RenderFlags != 0x0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ZoneSwitchEnd()
|
private void ZoneSwitchEnd()
|
||||||
|
|||||||
@@ -14,10 +14,8 @@ using MareSynchronos.Utils;
|
|||||||
using MareSynchronos.WebAPI.Files;
|
using MareSynchronos.WebAPI.Files;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using static System.Net.Mime.MediaTypeNames;
|
|
||||||
using ObjectKind = MareSynchronos.API.Data.Enum.ObjectKind;
|
using ObjectKind = MareSynchronos.API.Data.Enum.ObjectKind;
|
||||||
|
|
||||||
namespace MareSynchronos.PlayerData.Pairs;
|
namespace MareSynchronos.PlayerData.Pairs;
|
||||||
@@ -55,6 +53,12 @@ public sealed class CachedPlayer : DisposableMediatorSubscriberBase
|
|||||||
_lifetime = lifetime;
|
_lifetime = lifetime;
|
||||||
_fileDbManager = fileDbManager;
|
_fileDbManager = fileDbManager;
|
||||||
Mediator.Subscribe<FrameworkUpdateMessage>(this, (_) => FrameworkUpdate());
|
Mediator.Subscribe<FrameworkUpdateMessage>(this, (_) => FrameworkUpdate());
|
||||||
|
Mediator.Subscribe<ZoneSwitchStartMessage>(this, (_) =>
|
||||||
|
{
|
||||||
|
_charaHandler?.Invalidate();
|
||||||
|
IsVisible = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
_pluginWarnings ??= new()
|
_pluginWarnings ??= new()
|
||||||
{
|
{
|
||||||
ShownCustomizePlusWarning = mareConfigService.Current.DisableOptionalPluginWarnings,
|
ShownCustomizePlusWarning = mareConfigService.Current.DisableOptionalPluginWarnings,
|
||||||
@@ -445,16 +449,14 @@ public sealed class CachedPlayer : DisposableMediatorSubscriberBase
|
|||||||
|
|
||||||
if (updateModdedPaths && (moddedPaths.Any() || !string.IsNullOrEmpty(charaData.ManipulationData)))
|
if (updateModdedPaths && (moddedPaths.Any() || !string.IsNullOrEmpty(charaData.ManipulationData)))
|
||||||
{
|
{
|
||||||
await _charaHandler!.ActOnFrameworkAfterEnsureNoDrawAsync(() => _ipcManager
|
await _charaHandler!.ActOnFrameworkAfterEnsureNoDrawAsync((_) => _ipcManager
|
||||||
.PenumbraRemoveTemporaryCollectionAsync(Logger, _applicationId, PlayerName!)
|
.PenumbraRemoveTemporaryCollectionAsync(Logger, _applicationId, PlayerName!)
|
||||||
.ConfigureAwait(true).GetAwaiter().GetResult(), token).ConfigureAwait(false);
|
.ConfigureAwait(true).GetAwaiter().GetResult(), token).ConfigureAwait(false);
|
||||||
token.ThrowIfCancellationRequested();
|
token.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
await _charaHandler!.ActOnFrameworkAfterEnsureNoDrawAsync(() =>
|
await _charaHandler!.ActOnFrameworkAfterEnsureNoDrawAsync((chara) =>
|
||||||
{
|
{
|
||||||
var gameObj = _charaHandler!.GetGameObject();
|
var objTableIndex = chara.ObjectTableIndex();
|
||||||
if (gameObj == null) return;
|
|
||||||
var objTableIndex = gameObj.ObjectTableIndex();
|
|
||||||
_ipcManager.PenumbraSetTemporaryModsAsync(Logger, _applicationId, PlayerName!, objTableIndex, moddedPaths, charaData.ManipulationData)
|
_ipcManager.PenumbraSetTemporaryModsAsync(Logger, _applicationId, PlayerName!, objTableIndex, moddedPaths, charaData.ManipulationData)
|
||||||
.ConfigureAwait(true).GetAwaiter().GetResult();
|
.ConfigureAwait(true).GetAwaiter().GetResult();
|
||||||
}, token).ConfigureAwait(false);
|
}, token).ConfigureAwait(false);
|
||||||
@@ -510,6 +512,7 @@ public sealed class CachedPlayer : DisposableMediatorSubscriberBase
|
|||||||
_framesSinceNotVisible++;
|
_framesSinceNotVisible++;
|
||||||
if (_framesSinceNotVisible > 30)
|
if (_framesSinceNotVisible > 30)
|
||||||
{
|
{
|
||||||
|
_framesSinceNotVisible = 30;
|
||||||
IsVisible = false;
|
IsVisible = false;
|
||||||
Logger.LogTrace("{this} visibility changed, now: {visi}", this, IsVisible);
|
Logger.LogTrace("{this} visibility changed, now: {visi}", this, IsVisible);
|
||||||
}
|
}
|
||||||
@@ -627,7 +630,7 @@ public sealed class CachedPlayer : DisposableMediatorSubscriberBase
|
|||||||
if (minionOrMount != IntPtr.Zero)
|
if (minionOrMount != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
using GameObjectHandler tempHandler = await _gameObjectHandlerFactory.Create(ObjectKind.MinionOrMount, () => minionOrMount, false).ConfigureAwait(false);
|
using GameObjectHandler tempHandler = await _gameObjectHandlerFactory.Create(ObjectKind.MinionOrMount, () => minionOrMount, false).ConfigureAwait(false);
|
||||||
await _ipcManager.PenumbraRedrawAsync(Logger, tempHandler, applicationId, cancelToken.Token, fireAndForget: false).ConfigureAwait(false);
|
await _ipcManager.PenumbraRedrawAsync(Logger, tempHandler, applicationId, cancelToken.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (objectKind == ObjectKind.Pet)
|
else if (objectKind == ObjectKind.Pet)
|
||||||
@@ -636,7 +639,7 @@ public sealed class CachedPlayer : DisposableMediatorSubscriberBase
|
|||||||
if (pet != IntPtr.Zero)
|
if (pet != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
using GameObjectHandler tempHandler = await _gameObjectHandlerFactory.Create(ObjectKind.Pet, () => pet, false).ConfigureAwait(false);
|
using GameObjectHandler tempHandler = await _gameObjectHandlerFactory.Create(ObjectKind.Pet, () => pet, false).ConfigureAwait(false);
|
||||||
await _ipcManager.PenumbraRedrawAsync(Logger, tempHandler, applicationId, cancelToken.Token, fireAndForget: false).ConfigureAwait(false);
|
await _ipcManager.PenumbraRedrawAsync(Logger, tempHandler, applicationId, cancelToken.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (objectKind == ObjectKind.Companion)
|
else if (objectKind == ObjectKind.Companion)
|
||||||
@@ -645,7 +648,7 @@ public sealed class CachedPlayer : DisposableMediatorSubscriberBase
|
|||||||
if (companion != IntPtr.Zero)
|
if (companion != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
using GameObjectHandler tempHandler = await _gameObjectHandlerFactory.Create(ObjectKind.Pet, () => companion, false).ConfigureAwait(false);
|
using GameObjectHandler tempHandler = await _gameObjectHandlerFactory.Create(ObjectKind.Pet, () => companion, false).ConfigureAwait(false);
|
||||||
await _ipcManager.PenumbraRedrawAsync(Logger, tempHandler, applicationId, cancelToken.Token, fireAndForget: false).ConfigureAwait(false);
|
await _ipcManager.PenumbraRedrawAsync(Logger, tempHandler, applicationId, cancelToken.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ public class OnlinePlayerManager : DisposableMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
Mediator.Subscribe<CachedPlayerVisibleMessage>(this, (msg) => _newVisiblePlayers.Add(msg.Player));
|
Mediator.Subscribe<CachedPlayerVisibleMessage>(this, (msg) => _newVisiblePlayers.Add(msg.Player));
|
||||||
|
Mediator.Subscribe<ConnectedMessage>(this, (_) => PushCharacterData(_pairManager.GetVisibleUsers()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FrameworkOnUpdate()
|
private void FrameworkOnUpdate()
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ public sealed class CacheCreationService : DisposableMediatorSubscriberBase
|
|||||||
private readonly Dictionary<ObjectKind, GameObjectHandler> _playerRelatedObjects = new();
|
private readonly Dictionary<ObjectKind, GameObjectHandler> _playerRelatedObjects = new();
|
||||||
private Task? _cacheCreationTask;
|
private Task? _cacheCreationTask;
|
||||||
private CancellationTokenSource _honorificCts = new();
|
private CancellationTokenSource _honorificCts = new();
|
||||||
|
private bool _isZoning = false;
|
||||||
private CancellationTokenSource _palettePlusCts = new();
|
private CancellationTokenSource _palettePlusCts = new();
|
||||||
|
|
||||||
public CacheCreationService(ILogger<CacheCreationService> logger, MareMediator mediator, GameObjectHandlerFactory gameObjectHandlerFactory,
|
public CacheCreationService(ILogger<CacheCreationService> logger, MareMediator mediator, GameObjectHandlerFactory gameObjectHandlerFactory,
|
||||||
@@ -27,7 +28,7 @@ public sealed class CacheCreationService : DisposableMediatorSubscriberBase
|
|||||||
|
|
||||||
Mediator.Subscribe<CreateCacheForObjectMessage>(this, (msg) =>
|
Mediator.Subscribe<CreateCacheForObjectMessage>(this, (msg) =>
|
||||||
{
|
{
|
||||||
Logger.LogDebug("Received CreateCacheForObject for {handler}, updating player", msg.ObjectToCreateFor);
|
Logger.LogDebug("Received CreateCacheForObject for {handler}, updating", msg.ObjectToCreateFor);
|
||||||
_cacheCreateLock.Wait();
|
_cacheCreateLock.Wait();
|
||||||
_cachesToCreate[msg.ObjectToCreateFor.ObjectKind] = msg.ObjectToCreateFor;
|
_cachesToCreate[msg.ObjectToCreateFor.ObjectKind] = msg.ObjectToCreateFor;
|
||||||
_cacheCreateLock.Release();
|
_cacheCreateLock.Release();
|
||||||
@@ -37,25 +38,32 @@ public sealed class CacheCreationService : DisposableMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
|
Logger.LogTrace("Clearing cache for {obj}", msg.ObjectToCreateFor);
|
||||||
_playerData.FileReplacements.Remove(msg.ObjectToCreateFor.ObjectKind);
|
_playerData.FileReplacements.Remove(msg.ObjectToCreateFor.ObjectKind);
|
||||||
_playerData.GlamourerString.Remove(msg.ObjectToCreateFor.ObjectKind);
|
_playerData.GlamourerString.Remove(msg.ObjectToCreateFor.ObjectKind);
|
||||||
Mediator.Publish(new CharacterDataCreatedMessage(_playerData.ToAPI()));
|
Mediator.Publish(new CharacterDataCreatedMessage(_playerData.ToAPI()));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Mediator.Subscribe<ZoneSwitchStartMessage>(this, (msg) => _isZoning = true);
|
||||||
|
Mediator.Subscribe<ZoneSwitchEndMessage>(this, (msg) => _isZoning = false);
|
||||||
|
|
||||||
Mediator.Subscribe<DelayedFrameworkUpdateMessage>(this, (msg) => ProcessCacheCreation());
|
Mediator.Subscribe<DelayedFrameworkUpdateMessage>(this, (msg) => ProcessCacheCreation());
|
||||||
Mediator.Subscribe<CustomizePlusMessage>(this, async (_) =>
|
Mediator.Subscribe<CustomizePlusMessage>(this, async (_) =>
|
||||||
{
|
{
|
||||||
|
if (_isZoning) return;
|
||||||
Logger.LogDebug("Received CustomizePlus change, updating player");
|
Logger.LogDebug("Received CustomizePlus change, updating player");
|
||||||
await AddPlayerCacheToCreate().ConfigureAwait(false);
|
await AddPlayerCacheToCreate().ConfigureAwait(false);
|
||||||
});
|
});
|
||||||
Mediator.Subscribe<HeelsOffsetMessage>(this, async (_) =>
|
Mediator.Subscribe<HeelsOffsetMessage>(this, async (_) =>
|
||||||
{
|
{
|
||||||
|
if (_isZoning) return;
|
||||||
Logger.LogDebug("Received Heels Offset change, updating player");
|
Logger.LogDebug("Received Heels Offset change, updating player");
|
||||||
await AddPlayerCacheToCreate().ConfigureAwait(false);
|
await AddPlayerCacheToCreate().ConfigureAwait(false);
|
||||||
});
|
});
|
||||||
Mediator.Subscribe<PalettePlusMessage>(this, (msg) =>
|
Mediator.Subscribe<PalettePlusMessage>(this, (msg) =>
|
||||||
{
|
{
|
||||||
|
if (_isZoning) return;
|
||||||
if (msg.Character.Address == _playerRelatedObjects[ObjectKind.Player].Address)
|
if (msg.Character.Address == _playerRelatedObjects[ObjectKind.Player].Address)
|
||||||
{
|
{
|
||||||
Logger.LogDebug("Received PalettePlus change, updating player");
|
Logger.LogDebug("Received PalettePlus change, updating player");
|
||||||
@@ -64,6 +72,7 @@ public sealed class CacheCreationService : DisposableMediatorSubscriberBase
|
|||||||
});
|
});
|
||||||
Mediator.Subscribe<HonorificMessage>(this, (msg) =>
|
Mediator.Subscribe<HonorificMessage>(this, (msg) =>
|
||||||
{
|
{
|
||||||
|
if (_isZoning) return;
|
||||||
if (!string.Equals(msg.NewHonorificTitle, _playerData.HonorificData, StringComparison.Ordinal))
|
if (!string.Equals(msg.NewHonorificTitle, _playerData.HonorificData, StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
Logger.LogDebug("Received Honorific change, updating player");
|
Logger.LogDebug("Received Honorific change, updating player");
|
||||||
@@ -76,7 +85,7 @@ public sealed class CacheCreationService : DisposableMediatorSubscriberBase
|
|||||||
await AddPlayerCacheToCreate().ConfigureAwait(false);
|
await AddPlayerCacheToCreate().ConfigureAwait(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
_playerRelatedObjects[ObjectKind.Player] = gameObjectHandlerFactory.Create(ObjectKind.Player, () => dalamudUtil.GetPlayerPointer(), true)
|
_playerRelatedObjects[ObjectKind.Player] = gameObjectHandlerFactory.Create(ObjectKind.Player, dalamudUtil.GetPlayerPointer, true)
|
||||||
.GetAwaiter().GetResult();
|
.GetAwaiter().GetResult();
|
||||||
_playerRelatedObjects[ObjectKind.MinionOrMount] = gameObjectHandlerFactory.Create(ObjectKind.MinionOrMount, () => dalamudUtil.GetMinionOrMount(), true)
|
_playerRelatedObjects[ObjectKind.MinionOrMount] = gameObjectHandlerFactory.Create(ObjectKind.MinionOrMount, () => dalamudUtil.GetMinionOrMount(), true)
|
||||||
.GetAwaiter().GetResult();
|
.GetAwaiter().GetResult();
|
||||||
@@ -131,6 +140,8 @@ public sealed class CacheCreationService : DisposableMediatorSubscriberBase
|
|||||||
|
|
||||||
private void ProcessCacheCreation()
|
private void ProcessCacheCreation()
|
||||||
{
|
{
|
||||||
|
if (_isZoning) return;
|
||||||
|
|
||||||
if (_cachesToCreate.Any() && (_cacheCreationTask?.IsCompleted ?? true))
|
if (_cachesToCreate.Any() && (_cacheCreationTask?.IsCompleted ?? true))
|
||||||
{
|
{
|
||||||
_cacheCreateLock.Wait();
|
_cacheCreateLock.Wait();
|
||||||
|
|||||||
@@ -6,12 +6,14 @@ using Dalamud.Game.ClientState.Objects.SubKinds;
|
|||||||
using Dalamud.Game.Gui;
|
using Dalamud.Game.Gui;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Control;
|
using FFXIVClientStructs.FFXIV.Client.Game.Control;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||||
using MareSynchronos.PlayerData.Handlers;
|
using MareSynchronos.PlayerData.Handlers;
|
||||||
using MareSynchronos.Services.Mediator;
|
using MareSynchronos.Services.Mediator;
|
||||||
using MareSynchronos.Utils;
|
using MareSynchronos.Utils;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using GameObject = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject;
|
using GameObject = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject;
|
||||||
|
|
||||||
namespace MareSynchronos.Services;
|
namespace MareSynchronos.Services;
|
||||||
@@ -53,6 +55,7 @@ public class DalamudUtilService : IHostedService
|
|||||||
|
|
||||||
public unsafe GameObject* GposeTarget => TargetSystem.Instance()->GPoseTarget;
|
public unsafe GameObject* GposeTarget => TargetSystem.Instance()->GPoseTarget;
|
||||||
public unsafe Dalamud.Game.ClientState.Objects.Types.GameObject? GposeTargetGameObject => GposeTarget == null ? null : _objectTable[GposeTarget->ObjectIndex];
|
public unsafe Dalamud.Game.ClientState.Objects.Types.GameObject? GposeTargetGameObject => GposeTarget == null ? null : _objectTable[GposeTarget->ObjectIndex];
|
||||||
|
public bool IsAnythingDrawing { get; private set; } = false;
|
||||||
public bool IsInCutscene { get; private set; } = false;
|
public bool IsInCutscene { get; private set; } = false;
|
||||||
public bool IsInGpose { get; private set; } = false;
|
public bool IsInGpose { get; private set; } = false;
|
||||||
public bool IsLoggedIn { get; private set; }
|
public bool IsLoggedIn { get; private set; }
|
||||||
@@ -171,6 +174,11 @@ public class DalamudUtilService : IHostedService
|
|||||||
return _clientState.LocalPlayer?.Address ?? IntPtr.Zero;
|
return _clientState.LocalPlayer?.Address ?? IntPtr.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IntPtr> GetPlayerPointerAsync()
|
||||||
|
{
|
||||||
|
return await RunOnFrameworkThread(GetPlayerPointer).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
public uint GetWorldId()
|
public uint GetWorldId()
|
||||||
{
|
{
|
||||||
EnsureIsOnFramework();
|
EnsureIsOnFramework();
|
||||||
@@ -198,35 +206,43 @@ public class DalamudUtilService : IHostedService
|
|||||||
return await RunOnFrameworkThread(() => IsObjectPresent(obj)).ConfigureAwait(false);
|
return await RunOnFrameworkThread(() => IsObjectPresent(obj)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RunOnFrameworkThread(Action act)
|
public async Task RunOnFrameworkThread(Action act, [CallerMemberName] string callerMember = "", [CallerFilePath] string callerFilePath = "", [CallerLineNumber] int callerLineNumber = 0)
|
||||||
{
|
{
|
||||||
if (!_framework.IsInFrameworkUpdateThread)
|
var fileName = Path.GetFileNameWithoutExtension(callerFilePath);
|
||||||
|
await _performanceCollector.LogPerformance(this, "RunOnFramework:Act/" + fileName + ">" + callerMember + ":" + callerLineNumber, async () =>
|
||||||
{
|
{
|
||||||
await _framework.RunOnFrameworkThread(act).ContinueWith((_) => Task.CompletedTask).ConfigureAwait(false);
|
if (!_framework.IsInFrameworkUpdateThread)
|
||||||
while (_framework.IsInFrameworkUpdateThread) // yield the thread again, should technically never be triggered
|
|
||||||
{
|
{
|
||||||
_logger.LogTrace("Still on framework");
|
await _framework.RunOnFrameworkThread(act).ContinueWith((_) => Task.CompletedTask).ConfigureAwait(false);
|
||||||
await Task.Delay(1).ConfigureAwait(false);
|
while (_framework.IsInFrameworkUpdateThread) // yield the thread again, should technically never be triggered
|
||||||
|
{
|
||||||
|
_logger.LogTrace("Still on framework");
|
||||||
|
await Task.Delay(1).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
act();
|
||||||
act();
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<T> RunOnFrameworkThread<T>(Func<T> func)
|
public async Task<T> RunOnFrameworkThread<T>(Func<T> func, [CallerMemberName] string callerMember = "", [CallerFilePath] string callerFilePath = "", [CallerLineNumber] int callerLineNumber = 0)
|
||||||
{
|
{
|
||||||
if (!_framework.IsInFrameworkUpdateThread)
|
var fileName = Path.GetFileNameWithoutExtension(callerFilePath);
|
||||||
|
return await _performanceCollector.LogPerformance(this, "RunOnFramework:Func<" + typeof(T) + ">/" + fileName + ">" + callerMember + ":" + callerLineNumber, async () =>
|
||||||
{
|
{
|
||||||
var result = await _framework.RunOnFrameworkThread(func).ContinueWith((task) => task.Result).ConfigureAwait(false);
|
if (!_framework.IsInFrameworkUpdateThread)
|
||||||
while (_framework.IsInFrameworkUpdateThread) // yield the thread again, should technically never be triggered
|
|
||||||
{
|
{
|
||||||
_logger.LogTrace("Still on framework");
|
var result = await _framework.RunOnFrameworkThread(func).ContinueWith((task) => task.Result).ConfigureAwait(false);
|
||||||
await Task.Delay(1).ConfigureAwait(false);
|
while (_framework.IsInFrameworkUpdateThread) // yield the thread again, should technically never be triggered
|
||||||
|
{
|
||||||
|
_logger.LogTrace("Still on framework");
|
||||||
|
await Task.Delay(1).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return func.Invoke();
|
return func.Invoke();
|
||||||
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
public Task StartAsync(CancellationToken cancellationToken)
|
||||||
@@ -318,9 +334,35 @@ public class DalamudUtilService : IHostedService
|
|||||||
{
|
{
|
||||||
if (_clientState.LocalPlayer?.IsDead ?? false) return;
|
if (_clientState.LocalPlayer?.IsDead ?? false) return;
|
||||||
|
|
||||||
|
IsAnythingDrawing = false;
|
||||||
_playerCharas = _performanceCollector.LogPerformance(this, "ObjTableToCharas",
|
_playerCharas = _performanceCollector.LogPerformance(this, "ObjTableToCharas",
|
||||||
() => _objectTable.OfType<PlayerCharacter>().Where(o => o.ObjectIndex < 240)
|
() => _objectTable.OfType<PlayerCharacter>().Where(o => o.ObjectIndex < 240)
|
||||||
.ToDictionary(p => p.GetHash256(), p => (p.Name.ToString(), p.Address), StringComparer.Ordinal));
|
.ToDictionary(p => p.GetHash256(), p =>
|
||||||
|
{
|
||||||
|
if (!IsAnythingDrawing)
|
||||||
|
{
|
||||||
|
var gameObj = (GameObject*)p.Address;
|
||||||
|
bool isDrawing = gameObj->RenderFlags == 0b100000000000;
|
||||||
|
if (!isDrawing)
|
||||||
|
{
|
||||||
|
var drawObj = gameObj->DrawObject;
|
||||||
|
if ((nint)drawObj != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
isDrawing = ((CharacterBase*)drawObj)->HasModelInSlotLoaded != 0;
|
||||||
|
if (!isDrawing)
|
||||||
|
{
|
||||||
|
isDrawing = ((CharacterBase*)drawObj)->HasModelFilesInSlotLoaded != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDrawing)
|
||||||
|
{
|
||||||
|
IsAnythingDrawing = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (p.Name.ToString(), p.Address);
|
||||||
|
}, StringComparer.Ordinal));
|
||||||
|
|
||||||
if (GposeTarget != null && !IsInGpose)
|
if (GposeTarget != null && !IsInGpose)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -168,7 +168,8 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM
|
|||||||
|
|
||||||
await _mareHub.StartAsync(token).ConfigureAwait(false);
|
await _mareHub.StartAsync(token).ConfigureAwait(false);
|
||||||
|
|
||||||
await InitializeData().ConfigureAwait(false);
|
InitializeApiHooks();
|
||||||
|
await LoadIninitialPairs().ConfigureAwait(false);
|
||||||
|
|
||||||
_connectionDto = await GetConnectionDto().ConfigureAwait(false);
|
_connectionDto = await GetConnectionDto().ConfigureAwait(false);
|
||||||
|
|
||||||
@@ -198,6 +199,8 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM
|
|||||||
$"Please keep your Mare Synchronos client up-to-date.",
|
$"Please keep your Mare Synchronos client up-to-date.",
|
||||||
Dalamud.Interface.Internal.Notifications.NotificationType.Error));
|
Dalamud.Interface.Internal.Notifications.NotificationType.Error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await LoadOnlinePairs().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (HttpRequestException ex)
|
catch (HttpRequestException ex)
|
||||||
{
|
{
|
||||||
@@ -283,7 +286,7 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM
|
|||||||
ServerState = ServerState.Offline;
|
ServerState = ServerState.Offline;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task InitializeData()
|
private void InitializeApiHooks()
|
||||||
{
|
{
|
||||||
if (_mareHub == null) return;
|
if (_mareHub == null) return;
|
||||||
|
|
||||||
@@ -311,6 +314,16 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM
|
|||||||
OnGroupSendFullInfo((dto) => Client_GroupSendFullInfo(dto));
|
OnGroupSendFullInfo((dto) => Client_GroupSendFullInfo(dto));
|
||||||
OnGroupSendInfo((dto) => Client_GroupSendInfo(dto));
|
OnGroupSendInfo((dto) => Client_GroupSendInfo(dto));
|
||||||
|
|
||||||
|
_healthCheckTokenSource?.Cancel();
|
||||||
|
_healthCheckTokenSource?.Dispose();
|
||||||
|
_healthCheckTokenSource = new CancellationTokenSource();
|
||||||
|
_ = ClientHealthCheck(_healthCheckTokenSource.Token);
|
||||||
|
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadIninitialPairs()
|
||||||
|
{
|
||||||
foreach (var userPair in await UserGetPairedClients().ConfigureAwait(false))
|
foreach (var userPair in await UserGetPairedClients().ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
Logger.LogDebug("Individual Pair: {userPair}", userPair);
|
Logger.LogDebug("Individual Pair: {userPair}", userPair);
|
||||||
@@ -330,18 +343,15 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM
|
|||||||
_pairManager.AddGroupPair(user);
|
_pairManager.AddGroupPair(user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadOnlinePairs()
|
||||||
|
{
|
||||||
foreach (var entry in await UserGetOnlinePairs().ConfigureAwait(false))
|
foreach (var entry in await UserGetOnlinePairs().ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
|
Logger.LogDebug("Pair online: {pair}", entry);
|
||||||
_pairManager.MarkPairOnline(entry, sendNotif: false);
|
_pairManager.MarkPairOnline(entry, sendNotif: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
_healthCheckTokenSource?.Cancel();
|
|
||||||
_healthCheckTokenSource?.Dispose();
|
|
||||||
_healthCheckTokenSource = new CancellationTokenSource();
|
|
||||||
_ = ClientHealthCheck(_healthCheckTokenSource.Token);
|
|
||||||
|
|
||||||
_initialized = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MareHubOnClosed(Exception? arg)
|
private void MareHubOnClosed(Exception? arg)
|
||||||
@@ -364,13 +374,15 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM
|
|||||||
ServerState = ServerState.Connecting;
|
ServerState = ServerState.Connecting;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await InitializeData().ConfigureAwait(false);
|
InitializeApiHooks();
|
||||||
|
await LoadIninitialPairs().ConfigureAwait(false);
|
||||||
_connectionDto = await GetConnectionDto().ConfigureAwait(false);
|
_connectionDto = await GetConnectionDto().ConfigureAwait(false);
|
||||||
if (_connectionDto.ServerVersion != IMareHub.ApiVersion)
|
if (_connectionDto.ServerVersion != IMareHub.ApiVersion)
|
||||||
{
|
{
|
||||||
await StopConnection(ServerState.VersionMisMatch).ConfigureAwait(false);
|
await StopConnection(ServerState.VersionMisMatch).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
await LoadOnlinePairs().ConfigureAwait(false);
|
||||||
ServerState = ServerState.Connected;
|
ServerState = ServerState.Connected;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
Reference in New Issue
Block a user