Added Color Table Hook from MemShield, currently Experimental and default on as a test.
This commit is contained in:
106
MareSynchronos/Interop/ColorTableHook.cs
Normal file
106
MareSynchronos/Interop/ColorTableHook.cs
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
using Dalamud.Hooking;
|
||||||
|
using Dalamud.Plugin.Services;
|
||||||
|
using Dalamud.Utility.Signatures;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
||||||
|
using MareSynchronos.MareConfiguration;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Serilog;
|
||||||
|
using Serilog.Core;
|
||||||
|
using System.Buffers;
|
||||||
|
|
||||||
|
namespace MareSynchronos.Interop;
|
||||||
|
|
||||||
|
public unsafe sealed class ColorTableHook : IDisposable
|
||||||
|
{
|
||||||
|
// Based on https://github.com/Exter-N/MemShield/blob/main/MemShield/Plugin.cs
|
||||||
|
|
||||||
|
private readonly ILogger<ColorTableHook> _logger;
|
||||||
|
private const int ColorTableSize = 2048;
|
||||||
|
private const int ColorDyeTableSize = 128;
|
||||||
|
private readonly MareConfigService _configService;
|
||||||
|
|
||||||
|
#region signatures
|
||||||
|
#pragma warning disable CS0649
|
||||||
|
[Signature("E8 ?? ?? ?? ?? 49 89 04 3E",
|
||||||
|
DetourName = nameof(PrepareColorTableDetour))]
|
||||||
|
private Hook<MaterialResourceHandle.Delegates.PrepareColorTable> _prepareColorTable = null!;
|
||||||
|
#pragma warning restore CS0649
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public ColorTableHook(ILogger<ColorTableHook> logger, IGameInteropProvider gameInteropProvider, MareConfigService configService)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_configService = configService;
|
||||||
|
|
||||||
|
logger.LogInformation("Initializing ColorTableHook");
|
||||||
|
gameInteropProvider.InitializeFromAttributes(this);
|
||||||
|
|
||||||
|
if (_configService.Current.AttemptColorTableProtection)
|
||||||
|
{
|
||||||
|
_prepareColorTable.Enable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_configService.Current.AttemptColorTableProtection)
|
||||||
|
{
|
||||||
|
_prepareColorTable.Disable();
|
||||||
|
}
|
||||||
|
_prepareColorTable.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnableHooks()
|
||||||
|
{
|
||||||
|
_prepareColorTable.Enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DisableHooks()
|
||||||
|
{
|
||||||
|
_prepareColorTable.Disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GetDataSetExpectedSize(uint dataFlags)
|
||||||
|
=> (dataFlags & 16) != 0
|
||||||
|
? ColorTableSize + ((dataFlags & 8) != 0 ? ColorDyeTableSize : 0)
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
private Texture* PrepareColorTableDetour(MaterialResourceHandle* @this, byte stain0Id, byte stain1Id)
|
||||||
|
{
|
||||||
|
if(!_configService.Current.AttemptColorTableProtection)
|
||||||
|
{
|
||||||
|
return _prepareColorTable.Original(@this, stain0Id, stain1Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
var expectedSize = GetDataSetExpectedSize(@this->DataFlags);
|
||||||
|
if (@this->DataSetSize >= expectedSize)
|
||||||
|
return _prepareColorTable.Original(@this, stain0Id, stain1Id);
|
||||||
|
var originalDataSetPtr = @this->DataSet;
|
||||||
|
var originalDataSet = new ReadOnlySpan<byte>(originalDataSetPtr, @this->DataSetSize);
|
||||||
|
var pool = ArrayPool<byte>.Shared;
|
||||||
|
var buffer = pool.Rent(expectedSize);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var bufferSpan = buffer.AsSpan(..expectedSize);
|
||||||
|
originalDataSet.CopyTo(bufferSpan);
|
||||||
|
bufferSpan[@this->DataSetSize..].Clear();
|
||||||
|
fixed (byte* bufferPtr = buffer)
|
||||||
|
{
|
||||||
|
@this->DataSet = bufferPtr;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return _prepareColorTable.Original(@this, stain0Id, stain1Id);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
@this->DataSet = originalDataSetPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
pool.Return(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,6 +32,7 @@ public class MareConfig : IMareConfiguration
|
|||||||
public bool LogTraceLog { get; set; } = false;
|
public bool LogTraceLog { get; set; } = false;
|
||||||
public bool LogEvents { get; set; } = true;
|
public bool LogEvents { get; set; } = true;
|
||||||
public bool HoldCombatApplication { get; set; } = true;
|
public bool HoldCombatApplication { get; set; } = true;
|
||||||
|
public bool AttemptColorTableProtection { get; set; } = true;
|
||||||
public double MaxLocalCacheInGiB { get; set; } = 20;
|
public double MaxLocalCacheInGiB { get; set; } = 20;
|
||||||
public bool OpenGposeImportOnGposeStart { get; set; } = false;
|
public bool OpenGposeImportOnGposeStart { get; set; } = false;
|
||||||
public bool OpenPopupOnAdd { get; set; } = true;
|
public bool OpenPopupOnAdd { get; set; } = true;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project Sdk="Dalamud.NET.Sdk/13.0.0">
|
<Project Sdk="Dalamud.NET.Sdk/13.1.0">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AssemblyName>ClubPenguinSync</AssemblyName>
|
<AssemblyName>ClubPenguinSync</AssemblyName>
|
||||||
<Version>1.7.0.6</Version>
|
<Version>1.7.0.7</Version>
|
||||||
<PackageProjectUrl>https://github.com/Rawrington/ClubPenguinSync/</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/Rawrington/ClubPenguinSync/</PackageProjectUrl>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
collection.AddSingleton<CharaDataGposeTogetherManager>();
|
collection.AddSingleton<CharaDataGposeTogetherManager>();
|
||||||
|
|
||||||
collection.AddSingleton<VfxSpawnManager>();
|
collection.AddSingleton<VfxSpawnManager>();
|
||||||
|
collection.AddSingleton<ColorTableHook>();
|
||||||
collection.AddSingleton<BlockedCharacterHandler>();
|
collection.AddSingleton<BlockedCharacterHandler>();
|
||||||
collection.AddSingleton<IpcProvider>();
|
collection.AddSingleton<IpcProvider>();
|
||||||
collection.AddSingleton<VisibilityService>();
|
collection.AddSingleton<VisibilityService>();
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using Dalamud.Utility;
|
|||||||
using MareSynchronos.API.Data;
|
using MareSynchronos.API.Data;
|
||||||
using MareSynchronos.API.Data.Comparer;
|
using MareSynchronos.API.Data.Comparer;
|
||||||
using MareSynchronos.FileCache;
|
using MareSynchronos.FileCache;
|
||||||
|
using MareSynchronos.Interop;
|
||||||
using MareSynchronos.Interop.Ipc;
|
using MareSynchronos.Interop.Ipc;
|
||||||
using MareSynchronos.MareConfiguration;
|
using MareSynchronos.MareConfiguration;
|
||||||
using MareSynchronos.MareConfiguration.Models;
|
using MareSynchronos.MareConfiguration.Models;
|
||||||
@@ -25,6 +26,7 @@ using System.Collections.Concurrent;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace MareSynchronos.UI;
|
namespace MareSynchronos.UI;
|
||||||
@@ -50,6 +52,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
private readonly PlayerPerformanceService _playerPerformanceService;
|
private readonly PlayerPerformanceService _playerPerformanceService;
|
||||||
private readonly AccountRegistrationService _registerService;
|
private readonly AccountRegistrationService _registerService;
|
||||||
private readonly ServerConfigurationManager _serverConfigurationManager;
|
private readonly ServerConfigurationManager _serverConfigurationManager;
|
||||||
|
private readonly ColorTableHook _colorTableHook;
|
||||||
private readonly UiSharedService _uiShared;
|
private readonly UiSharedService _uiShared;
|
||||||
private bool _deleteAccountPopupModalShown = false;
|
private bool _deleteAccountPopupModalShown = false;
|
||||||
private string _lastTab = string.Empty;
|
private string _lastTab = string.Empty;
|
||||||
@@ -77,11 +80,12 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
FileCacheManager fileCacheManager,
|
FileCacheManager fileCacheManager,
|
||||||
FileCompactor fileCompactor, ApiController apiController,
|
FileCompactor fileCompactor, ApiController apiController,
|
||||||
IpcManager ipcManager, IpcProvider ipcProvider, CacheMonitor cacheMonitor,
|
IpcManager ipcManager, IpcProvider ipcProvider, CacheMonitor cacheMonitor,
|
||||||
DalamudUtilService dalamudUtilService, AccountRegistrationService registerService) : base(logger, mediator, "Club Penguin Sync Settings", performanceCollector)
|
DalamudUtilService dalamudUtilService, AccountRegistrationService registerService, ColorTableHook colorTableHook) : base(logger, mediator, "Club Penguin Sync Settings", performanceCollector)
|
||||||
{
|
{
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
_pairManager = pairManager;
|
_pairManager = pairManager;
|
||||||
_chatService = chatService;
|
_chatService = chatService;
|
||||||
|
_colorTableHook = colorTableHook;
|
||||||
_guiHookService = guiHookService;
|
_guiHookService = guiHookService;
|
||||||
_serverConfigurationManager = serverConfigurationManager;
|
_serverConfigurationManager = serverConfigurationManager;
|
||||||
_playerPerformanceConfigService = playerPerformanceConfigService;
|
_playerPerformanceConfigService = playerPerformanceConfigService;
|
||||||
@@ -640,6 +644,22 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
_configService.Save();
|
_configService.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool attemptColorTableProtection = _configService.Current.AttemptColorTableProtection;
|
||||||
|
if (ImGui.Checkbox("[EXPERIMENTAL] Attempt to fix potential ColorTable crashes.", ref attemptColorTableProtection))
|
||||||
|
{
|
||||||
|
if (attemptColorTableProtection)
|
||||||
|
{
|
||||||
|
_colorTableHook.EnableHooks();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_colorTableHook.DisableHooks();
|
||||||
|
}
|
||||||
|
//this shouldnt need the mediator as this is the ONLY source of truth.
|
||||||
|
_configService.Current.AttemptColorTableProtection = attemptColorTableProtection;
|
||||||
|
_configService.Save();
|
||||||
|
}
|
||||||
|
|
||||||
bool serializedApplications = _configService.Current.SerialApplication;
|
bool serializedApplications = _configService.Current.SerialApplication;
|
||||||
if (ImGui.Checkbox("Serialized player applications", ref serializedApplications))
|
if (ImGui.Checkbox("Serialized player applications", ref serializedApplications))
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user