74 lines
2.9 KiB
C#
74 lines
2.9 KiB
C#
using Dalamud.Hooking;
|
|
using Dalamud.Utility.Signatures;
|
|
|
|
namespace OrangeGuidanceTomestone.MiniPenumbra;
|
|
|
|
internal unsafe class VfxReplacer : IDisposable {
|
|
private delegate byte ReadSqPackDelegate(void* resourceManager, SeFileDescriptor* pFileDesc, int priority, bool isSync);
|
|
|
|
[Signature("40 55 56 48 83 EC 28 44 0F BE 12", DetourName = nameof(ReadSqPackDetour))]
|
|
private Hook<ReadSqPackDelegate> _readSqPackHook;
|
|
|
|
[Signature("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 41 54 41 55 41 56 41 57 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 48 63 42 28")]
|
|
private delegate* unmanaged<void*, SeFileDescriptor*, int, bool, byte> _readFile;
|
|
|
|
private Plugin Plugin { get; }
|
|
|
|
internal VfxReplacer(Plugin plugin) {
|
|
this.Plugin = plugin;
|
|
this.Plugin.GameInteropProvider.InitializeFromAttributes(this);
|
|
|
|
this._readSqPackHook!.Enable();
|
|
}
|
|
|
|
public void Dispose() {
|
|
this._readSqPackHook.Dispose();
|
|
}
|
|
|
|
private byte ReadSqPackDetour(void* resourceManager, SeFileDescriptor* fileDescriptor, int priority, bool isSync) {
|
|
if (!this.Plugin.Config.RemoveGlow) {
|
|
goto Original;
|
|
}
|
|
|
|
if (fileDescriptor == null || fileDescriptor->ResourceHandle == null) {
|
|
goto Original;
|
|
}
|
|
|
|
var path = fileDescriptor->ResourceHandle->FileName.ToString();
|
|
var index = Array.IndexOf(Messages.VfxPaths, path);
|
|
if (index == -1) {
|
|
goto Original;
|
|
}
|
|
|
|
var letter = (char) ('a' + index);
|
|
var newPath = Path.Join(this.Plugin.AvfxFilePath, $"sign_{letter}.avfx");
|
|
return this.DefaultRootedResourceLoad(newPath, resourceManager, fileDescriptor, priority, isSync);
|
|
|
|
Original:
|
|
return this._readSqPackHook.Original(resourceManager, fileDescriptor, priority, isSync);
|
|
}
|
|
|
|
// Load the resource from a path on the users hard drives.
|
|
private byte DefaultRootedResourceLoad(string gamePath, void* resourceManager, SeFileDescriptor* fileDescriptor, int priority, bool isSync) {
|
|
// Specify that we are loading unpacked files from the drive.
|
|
// We need to copy the actual file path in UTF16 (Windows-Unicode) on two locations,
|
|
// but since we only allow ASCII in the game paths, this is just a matter of upcasting.
|
|
fileDescriptor->FileMode = SeFileMode.LoadUnpackedResource;
|
|
|
|
var fd = stackalloc byte[0x20 + 2 * gamePath.Length + 0x16];
|
|
fileDescriptor->FileDescriptor = fd;
|
|
var fdPtr = (char*) (fd + 0x21);
|
|
for (var i = 0; i < gamePath.Length; ++i) {
|
|
(&fileDescriptor->Utf16FileName)[i] = gamePath[i];
|
|
fdPtr[i] = gamePath[i];
|
|
}
|
|
|
|
(&fileDescriptor->Utf16FileName)[gamePath.Length] = '\0';
|
|
fdPtr[gamePath.Length] = '\0';
|
|
|
|
// Use the SE ReadFile function.
|
|
var ret = this._readFile(resourceManager, fileDescriptor, priority, isSync);
|
|
return ret;
|
|
}
|
|
}
|