mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Add and rework hooks around EST entries.
This commit is contained in:
parent
1922353ba3
commit
e7c786b239
3 changed files with 65 additions and 22 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit c25ea7b19a6db37dd36e12b9a7a71f72a192ab57
|
||||
Subproject commit 94df458dfb2a704a611fa77d955808284aeb23ac
|
||||
|
|
@ -3,51 +3,58 @@ using Penumbra.GameData;
|
|||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Interop.PathResolving;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
using CharacterUtility = Penumbra.Interop.Services.CharacterUtility;
|
||||
|
||||
namespace Penumbra.Interop.Hooks.Meta;
|
||||
|
||||
public class EstHook : FastHook<EstHook.Delegate>, IDisposable
|
||||
public unsafe class EstHook : FastHook<EstHook.Delegate>, IDisposable
|
||||
{
|
||||
public delegate EstEntry Delegate(uint id, int estType, uint genderRace);
|
||||
public delegate EstEntry Delegate(ResourceHandle* estResource, uint id, uint genderRace);
|
||||
|
||||
private readonly MetaState _metaState;
|
||||
private readonly CharacterUtility _characterUtility;
|
||||
private readonly MetaState _metaState;
|
||||
|
||||
public EstHook(HookManager hooks, MetaState metaState)
|
||||
public EstHook(HookManager hooks, MetaState metaState, CharacterUtility characterUtility)
|
||||
{
|
||||
_metaState = metaState;
|
||||
Task = hooks.CreateHook<Delegate>("GetEstEntry", Sigs.GetEstEntry, Detour, metaState.Config.EnableMods && HookSettings.MetaEntryHooks);
|
||||
_metaState = metaState;
|
||||
_characterUtility = characterUtility;
|
||||
Task = hooks.CreateHook<Delegate>("FindEstEntry", Sigs.FindEstEntry, Detour,
|
||||
metaState.Config.EnableMods && HookSettings.MetaEntryHooks);
|
||||
_metaState.Config.ModsEnabled += Toggle;
|
||||
}
|
||||
|
||||
private EstEntry Detour(uint genderRace, int estType, uint id)
|
||||
private EstEntry Detour(ResourceHandle* estResource, uint genderRace, uint id)
|
||||
{
|
||||
EstEntry ret;
|
||||
if (_metaState.EstCollection.TryPeek(out var collection)
|
||||
&& collection is { Valid: true, ModCollection.MetaCache: { } cache }
|
||||
&& cache.Est.TryGetValue(Convert(genderRace, estType, id), out var entry))
|
||||
&& cache.Est.TryGetValue(Convert(estResource, genderRace, id), out var entry))
|
||||
ret = entry.Entry;
|
||||
else
|
||||
ret = Task.Result.Original(genderRace, estType, id);
|
||||
ret = Task.Result.Original(estResource, genderRace, id);
|
||||
|
||||
Penumbra.Log.Excessive($"[GetEstEntry] Invoked with {genderRace}, {estType}, {id}, returned {ret.Value}.");
|
||||
Penumbra.Log.Information($"[FindEstEntry] Invoked with 0x{(nint)estResource:X}, {genderRace}, {id}, returned {ret.Value}.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static EstIdentifier Convert(uint genderRace, int estType, uint id)
|
||||
private EstIdentifier Convert(ResourceHandle* estResource, uint genderRace, uint id)
|
||||
{
|
||||
var i = new PrimaryId((ushort)id);
|
||||
var gr = (GenderRace)genderRace;
|
||||
var type = estType switch
|
||||
{
|
||||
1 => EstType.Face,
|
||||
2 => EstType.Hair,
|
||||
3 => EstType.Head,
|
||||
4 => EstType.Body,
|
||||
_ => (EstType)0,
|
||||
};
|
||||
return new EstIdentifier(i, type, gr);
|
||||
|
||||
if (estResource == _characterUtility.Address->BodyEstResource)
|
||||
return new EstIdentifier(i, EstType.Body, gr);
|
||||
if (estResource == _characterUtility.Address->HairEstResource)
|
||||
return new EstIdentifier(i, EstType.Hair, gr);
|
||||
if (estResource == _characterUtility.Address->FaceEstResource)
|
||||
return new EstIdentifier(i, EstType.Face, gr);
|
||||
if (estResource == _characterUtility.Address->HeadEstResource)
|
||||
return new EstIdentifier(i, EstType.Head, gr);
|
||||
|
||||
return new EstIdentifier(i, 0, gr);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable
|
|||
private delegate nint NamedResolveDelegate(nint drawObject, nint pathBuffer, nint pathBufferSize, uint slotIndex, nint name);
|
||||
private delegate nint PerSlotResolveDelegate(nint drawObject, nint pathBuffer, nint pathBufferSize, uint slotIndex);
|
||||
private delegate nint SingleResolveDelegate(nint drawObject, nint pathBuffer, nint pathBufferSize);
|
||||
private delegate nint SkeletonVFuncDelegate(nint drawObject, int estType, nint unk);
|
||||
|
||||
private delegate nint TmbResolveDelegate(nint drawObject, nint pathBuffer, nint pathBufferSize, nint timelineName);
|
||||
|
||||
|
|
@ -37,6 +38,8 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable
|
|||
private readonly Hook<PerSlotResolveDelegate> _resolveSkpPathHook;
|
||||
private readonly Hook<TmbResolveDelegate> _resolveTmbPathHook;
|
||||
private readonly Hook<VfxResolveDelegate> _resolveVfxPathHook;
|
||||
private readonly Hook<SkeletonVFuncDelegate>? _vFunc81Hook;
|
||||
private readonly Hook<SkeletonVFuncDelegate>? _vFunc83Hook;
|
||||
|
||||
private readonly PathState _parent;
|
||||
|
||||
|
|
@ -49,6 +52,9 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable
|
|||
_resolveSkpPathHook = Create<PerSlotResolveDelegate>($"{name}.{nameof(ResolveSkp)}", hooks, vTable[78], type, ResolveSkp, ResolveSkpHuman);
|
||||
_resolvePhybPathHook = Create<PerSlotResolveDelegate>($"{name}.{nameof(ResolvePhyb)}", hooks, vTable[79], type, ResolvePhyb, ResolvePhybHuman);
|
||||
|
||||
_vFunc81Hook = Create<SkeletonVFuncDelegate>( $"{name}.{nameof(VFunc81)}", hooks, vTable[81], type, null, VFunc81);
|
||||
|
||||
_vFunc83Hook = Create<SkeletonVFuncDelegate>( $"{name}.{nameof(VFunc83)}", hooks, vTable[83], type, null, VFunc83);
|
||||
|
||||
_resolvePapPathHook = Create<NamedResolveDelegate>( $"{name}.{nameof(ResolvePap)}", hooks, vTable[84], type, ResolvePap, ResolvePapHuman);
|
||||
_resolveTmbPathHook = Create<TmbResolveDelegate>( $"{name}.{nameof(ResolveTmb)}", hooks, vTable[85], ResolveTmb);
|
||||
|
|
@ -58,6 +64,8 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable
|
|||
_resolveDecalPathHook = Create<PerSlotResolveDelegate>($"{name}.{nameof(ResolveDecal)}", hooks, vTable[92], ResolveDecal);
|
||||
_resolveVfxPathHook = Create<VfxResolveDelegate>( $"{name}.{nameof(ResolveVfx)}", hooks, vTable[93], type, ResolveVfx, ResolveVfxHuman);
|
||||
_resolveEidPathHook = Create<SingleResolveDelegate>( $"{name}.{nameof(ResolveEid)}", hooks, vTable[94], ResolveEid);
|
||||
|
||||
|
||||
// @formatter:on
|
||||
if (HookSettings.ResourceHooks)
|
||||
Enable();
|
||||
|
|
@ -77,6 +85,8 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable
|
|||
_resolveSkpPathHook.Enable();
|
||||
_resolveTmbPathHook.Enable();
|
||||
_resolveVfxPathHook.Enable();
|
||||
_vFunc81Hook?.Enable();
|
||||
_vFunc83Hook?.Enable();
|
||||
}
|
||||
|
||||
public void Disable()
|
||||
|
|
@ -93,6 +103,8 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable
|
|||
_resolveSkpPathHook.Disable();
|
||||
_resolveTmbPathHook.Disable();
|
||||
_resolveVfxPathHook.Disable();
|
||||
_vFunc81Hook?.Disable();
|
||||
_vFunc83Hook?.Disable();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
@ -109,6 +121,8 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable
|
|||
_resolveSkpPathHook.Dispose();
|
||||
_resolveTmbPathHook.Dispose();
|
||||
_resolveVfxPathHook.Dispose();
|
||||
_vFunc81Hook?.Dispose();
|
||||
_vFunc83Hook?.Dispose();
|
||||
}
|
||||
|
||||
private nint ResolveDecal(nint drawObject, nint pathBuffer, nint pathBufferSize, uint slotIndex)
|
||||
|
|
@ -224,14 +238,36 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable
|
|||
return ResolvePath(drawObject, pathBuffer);
|
||||
}
|
||||
|
||||
private nint VFunc81(nint drawObject, int estType, nint unk)
|
||||
{
|
||||
var collection = _parent.CollectionResolver.IdentifyCollection((DrawObject*)drawObject, true);
|
||||
_parent.MetaState.EstCollection.Push(collection);
|
||||
var ret = _vFunc81Hook!.Original(drawObject, estType, unk);
|
||||
_parent.MetaState.EstCollection.Pop();
|
||||
return ret;
|
||||
}
|
||||
|
||||
private nint VFunc83(nint drawObject, int estType, nint unk)
|
||||
{
|
||||
var collection = _parent.CollectionResolver.IdentifyCollection((DrawObject*)drawObject, true);
|
||||
_parent.MetaState.EstCollection.Push(collection);
|
||||
var ret = _vFunc83Hook!.Original(drawObject, estType, unk);
|
||||
_parent.MetaState.EstCollection.Pop();
|
||||
return ret;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private static Hook<T> Create<T>(string name, HookManager hooks, nint address, Type type, T other, T human) where T : Delegate
|
||||
[return: NotNullIfNotNull(nameof(other))]
|
||||
private static Hook<T>? Create<T>(string name, HookManager hooks, nint address, Type type, T? other, T human) where T : Delegate
|
||||
{
|
||||
var del = type switch
|
||||
{
|
||||
Type.Human => human,
|
||||
_ => other,
|
||||
};
|
||||
if (del == null)
|
||||
return null;
|
||||
|
||||
return hooks.CreateHook(name, address, del).Result;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue