Skip to content

Commit

Permalink
Add and rework hooks around EST entries.
Browse files Browse the repository at this point in the history
  • Loading branch information
Ottermandias committed Jul 17, 2024
1 parent 1922353 commit e7c786b
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 22 deletions.
2 changes: 1 addition & 1 deletion Penumbra.GameData
47 changes: 27 additions & 20 deletions Penumbra/Interop/Hooks/Meta/EstHook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,51 +3,58 @@
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()
Expand Down
38 changes: 37 additions & 1 deletion Penumbra/Interop/Hooks/Resources/ResolvePathHooksBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public enum Type
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);

Expand All @@ -37,6 +38,8 @@ public enum Type
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;

Expand All @@ -49,6 +52,9 @@ public ResolvePathHooksBase(string name, HookManager hooks, PathState parent, ni
_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);
Expand All @@ -58,6 +64,8 @@ public ResolvePathHooksBase(string name, HookManager hooks, PathState parent, ni
_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();
Expand All @@ -77,6 +85,8 @@ public void Enable()
_resolveSkpPathHook.Enable();
_resolveTmbPathHook.Enable();
_resolveVfxPathHook.Enable();
_vFunc81Hook?.Enable();
_vFunc83Hook?.Enable();
}

public void Disable()
Expand All @@ -93,6 +103,8 @@ public void Disable()
_resolveSkpPathHook.Disable();
_resolveTmbPathHook.Disable();
_resolveVfxPathHook.Disable();
_vFunc81Hook?.Disable();
_vFunc83Hook?.Disable();
}

public void Dispose()
Expand All @@ -109,6 +121,8 @@ public void Dispose()
_resolveSkpPathHook.Dispose();
_resolveTmbPathHook.Dispose();
_resolveVfxPathHook.Dispose();
_vFunc81Hook?.Dispose();
_vFunc83Hook?.Dispose();
}

private nint ResolveDecal(nint drawObject, nint pathBuffer, nint pathBufferSize, uint slotIndex)
Expand Down Expand Up @@ -224,14 +238,36 @@ private nint ResolveVfxHuman(nint drawObject, nint pathBuffer, nint pathBufferSi
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;
}

Expand Down

0 comments on commit e7c786b

Please sign in to comment.