mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-13 12:14:17 +01:00
Make meta hooks respect Enable Mod setting and fix EQP composition.
This commit is contained in:
parent
a90e253c73
commit
29f8c91306
12 changed files with 121 additions and 33 deletions
2
OtterGui
2
OtterGui
|
|
@ -1 +1 @@
|
||||||
Subproject commit caa9e9b9a5dc3928eba10b315cf6a0f6f1d84b65
|
Subproject commit 6fafc03b34971be7c0e74fd9a638d1ed642ea19a
|
||||||
|
|
@ -9,11 +9,24 @@ namespace Penumbra.Collections.Cache;
|
||||||
public sealed class EqpCache(MetaFileManager manager, ModCollection collection) : MetaCacheBase<EqpIdentifier, EqpEntry>(manager, collection)
|
public sealed class EqpCache(MetaFileManager manager, ModCollection collection) : MetaCacheBase<EqpIdentifier, EqpEntry>(manager, collection)
|
||||||
{
|
{
|
||||||
public unsafe EqpEntry GetValues(CharacterArmor* armor)
|
public unsafe EqpEntry GetValues(CharacterArmor* armor)
|
||||||
=> GetSingleValue(armor[0].Set, EquipSlot.Head)
|
{
|
||||||
| GetSingleValue(armor[1].Set, EquipSlot.Body)
|
var bodyEntry = GetSingleValue(armor[1].Set, EquipSlot.Body);
|
||||||
| GetSingleValue(armor[2].Set, EquipSlot.Hands)
|
var headEntry = bodyEntry.HasFlag(EqpEntry.BodyShowHead)
|
||||||
| GetSingleValue(armor[3].Set, EquipSlot.Legs)
|
? GetSingleValue(armor[0].Set, EquipSlot.Head)
|
||||||
| GetSingleValue(armor[4].Set, EquipSlot.Feet);
|
: GetSingleValue(armor[1].Set, EquipSlot.Head);
|
||||||
|
var handEntry = bodyEntry.HasFlag(EqpEntry.BodyShowHand)
|
||||||
|
? GetSingleValue(armor[2].Set, EquipSlot.Hands)
|
||||||
|
: GetSingleValue(armor[1].Set, EquipSlot.Hands);
|
||||||
|
var (legsEntry, legsId) = bodyEntry.HasFlag(EqpEntry.BodyShowLeg)
|
||||||
|
? (GetSingleValue(armor[3].Set, EquipSlot.Legs), 3)
|
||||||
|
: (GetSingleValue(armor[1].Set, EquipSlot.Legs), 1);
|
||||||
|
var footEntry = legsEntry.HasFlag(EqpEntry.LegsShowFoot)
|
||||||
|
? GetSingleValue(armor[4].Set, EquipSlot.Feet)
|
||||||
|
: GetSingleValue(armor[legsId].Set, EquipSlot.Feet);
|
||||||
|
|
||||||
|
var combined = bodyEntry | headEntry | handEntry | legsEntry | footEntry;
|
||||||
|
return PostProcessFeet(PostProcessHands(combined));
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
private EqpEntry GetSingleValue(PrimaryId id, EquipSlot slot)
|
private EqpEntry GetSingleValue(PrimaryId id, EquipSlot slot)
|
||||||
|
|
@ -24,4 +37,30 @@ public sealed class EqpCache(MetaFileManager manager, ModCollection collection)
|
||||||
|
|
||||||
protected override void Dispose(bool _)
|
protected override void Dispose(bool _)
|
||||||
=> Clear();
|
=> Clear();
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
private static EqpEntry PostProcessHands(EqpEntry entry)
|
||||||
|
{
|
||||||
|
if (!entry.HasFlag(EqpEntry.HandsHideForearm))
|
||||||
|
return entry;
|
||||||
|
|
||||||
|
var testFlag = entry.HasFlag(EqpEntry.HandsHideElbow)
|
||||||
|
? entry.HasFlag(EqpEntry.BodyHideGlovesL)
|
||||||
|
: entry.HasFlag(EqpEntry.BodyHideGlovesM);
|
||||||
|
return testFlag
|
||||||
|
? (entry | EqpEntry._4) & ~EqpEntry.BodyHideGlovesS
|
||||||
|
: entry & ~(EqpEntry._4 | EqpEntry.BodyHideGlovesS);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
private static EqpEntry PostProcessFeet(EqpEntry entry)
|
||||||
|
{
|
||||||
|
if (!entry.HasFlag(EqpEntry.FeetHideCalf))
|
||||||
|
return entry;
|
||||||
|
|
||||||
|
if (entry.HasFlag(EqpEntry.FeetHideKnee) || !entry.HasFlag(EqpEntry._20))
|
||||||
|
return entry & ~(EqpEntry.LegsHideBootsS | EqpEntry.LegsHideBootsM);
|
||||||
|
|
||||||
|
return (entry | EqpEntry.LegsHideBootsM) & ~EqpEntry.LegsHideBootsS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,21 @@ public class Configuration : IPluginConfiguration, ISavable, IService
|
||||||
|
|
||||||
public ChangeLogDisplayType ChangeLogDisplayType { get; set; } = ChangeLogDisplayType.New;
|
public ChangeLogDisplayType ChangeLogDisplayType { get; set; } = ChangeLogDisplayType.New;
|
||||||
|
|
||||||
public bool EnableMods { get; set; } = true;
|
public event Action<bool>? ModsEnabled;
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
private bool _enableMods = true;
|
||||||
|
|
||||||
|
public bool EnableMods
|
||||||
|
{
|
||||||
|
get => _enableMods;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_enableMods = value;
|
||||||
|
ModsEnabled?.Invoke(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public string ModDirectory { get; set; } = string.Empty;
|
public string ModDirectory { get; set; } = string.Empty;
|
||||||
public string ExportDirectory { get; set; } = string.Empty;
|
public string ExportDirectory { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ using Penumbra.Interop.PathResolving;
|
||||||
|
|
||||||
namespace Penumbra.Interop.Hooks.Meta;
|
namespace Penumbra.Interop.Hooks.Meta;
|
||||||
|
|
||||||
public unsafe class EqdpAccessoryHook : FastHook<EqdpAccessoryHook.Delegate>
|
public unsafe class EqdpAccessoryHook : FastHook<EqdpAccessoryHook.Delegate>, IDisposable
|
||||||
{
|
{
|
||||||
public delegate void Delegate(CharacterUtility* utility, EqdpEntry* entry, uint id, uint raceCode);
|
public delegate void Delegate(CharacterUtility* utility, EqdpEntry* entry, uint id, uint raceCode);
|
||||||
|
|
||||||
|
|
@ -15,7 +15,8 @@ public unsafe class EqdpAccessoryHook : FastHook<EqdpAccessoryHook.Delegate>
|
||||||
public EqdpAccessoryHook(HookManager hooks, MetaState metaState)
|
public EqdpAccessoryHook(HookManager hooks, MetaState metaState)
|
||||||
{
|
{
|
||||||
_metaState = metaState;
|
_metaState = metaState;
|
||||||
Task = hooks.CreateHook<Delegate>("GetEqdpAccessoryEntry", "E8 ?? ?? ?? ?? 41 BF ?? ?? ?? ?? 83 FB", Detour, true);
|
Task = hooks.CreateHook<Delegate>("GetEqdpAccessoryEntry", "E8 ?? ?? ?? ?? 41 BF ?? ?? ?? ?? 83 FB", Detour, metaState.Config.EnableMods);
|
||||||
|
_metaState.Config.ModsEnabled += Toggle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Detour(CharacterUtility* utility, EqdpEntry* entry, uint setId, uint raceCode)
|
private void Detour(CharacterUtility* utility, EqdpEntry* entry, uint setId, uint raceCode)
|
||||||
|
|
@ -27,4 +28,7 @@ public unsafe class EqdpAccessoryHook : FastHook<EqdpAccessoryHook.Delegate>
|
||||||
Penumbra.Log.Excessive(
|
Penumbra.Log.Excessive(
|
||||||
$"[GetEqdpAccessoryEntry] Invoked on 0x{(ulong)utility:X} with {setId}, {(GenderRace)raceCode}, returned {(ushort)*entry:B10}.");
|
$"[GetEqdpAccessoryEntry] Invoked on 0x{(ulong)utility:X} with {setId}, {(GenderRace)raceCode}, returned {(ushort)*entry:B10}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
=> _metaState.Config.ModsEnabled -= Toggle;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ using Penumbra.Interop.PathResolving;
|
||||||
|
|
||||||
namespace Penumbra.Interop.Hooks.Meta;
|
namespace Penumbra.Interop.Hooks.Meta;
|
||||||
|
|
||||||
public unsafe class EqdpEquipHook : FastHook<EqdpEquipHook.Delegate>
|
public unsafe class EqdpEquipHook : FastHook<EqdpEquipHook.Delegate>, IDisposable
|
||||||
{
|
{
|
||||||
public delegate void Delegate(CharacterUtility* utility, EqdpEntry* entry, uint id, uint raceCode);
|
public delegate void Delegate(CharacterUtility* utility, EqdpEntry* entry, uint id, uint raceCode);
|
||||||
|
|
||||||
|
|
@ -15,7 +15,8 @@ public unsafe class EqdpEquipHook : FastHook<EqdpEquipHook.Delegate>
|
||||||
public EqdpEquipHook(HookManager hooks, MetaState metaState)
|
public EqdpEquipHook(HookManager hooks, MetaState metaState)
|
||||||
{
|
{
|
||||||
_metaState = metaState;
|
_metaState = metaState;
|
||||||
Task = hooks.CreateHook<Delegate>("GetEqdpEquipEntry", "E8 ?? ?? ?? ?? 85 DB 75 ?? F6 45", Detour, true);
|
Task = hooks.CreateHook<Delegate>("GetEqdpEquipEntry", "E8 ?? ?? ?? ?? 85 DB 75 ?? F6 45", Detour, metaState.Config.EnableMods);
|
||||||
|
_metaState.Config.ModsEnabled += Toggle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Detour(CharacterUtility* utility, EqdpEntry* entry, uint setId, uint raceCode)
|
private void Detour(CharacterUtility* utility, EqdpEntry* entry, uint setId, uint raceCode)
|
||||||
|
|
@ -27,4 +28,7 @@ public unsafe class EqdpEquipHook : FastHook<EqdpEquipHook.Delegate>
|
||||||
Penumbra.Log.Excessive(
|
Penumbra.Log.Excessive(
|
||||||
$"[GetEqdpEquipEntry] Invoked on 0x{(ulong)utility:X} with {setId}, {(GenderRace)raceCode}, returned {(ushort)*entry:B10}.");
|
$"[GetEqdpEquipEntry] Invoked on 0x{(ulong)utility:X} with {setId}, {(GenderRace)raceCode}, returned {(ushort)*entry:B10}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
=> _metaState.Config.ModsEnabled -= Toggle;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ using Penumbra.Interop.PathResolving;
|
||||||
|
|
||||||
namespace Penumbra.Interop.Hooks.Meta;
|
namespace Penumbra.Interop.Hooks.Meta;
|
||||||
|
|
||||||
public unsafe class EqpHook : FastHook<EqpHook.Delegate>
|
public unsafe class EqpHook : FastHook<EqpHook.Delegate>, IDisposable
|
||||||
{
|
{
|
||||||
public delegate void Delegate(CharacterUtility* utility, EqpEntry* flags, CharacterArmor* armor);
|
public delegate void Delegate(CharacterUtility* utility, EqpEntry* flags, CharacterArmor* armor);
|
||||||
|
|
||||||
|
|
@ -14,7 +14,8 @@ public unsafe class EqpHook : FastHook<EqpHook.Delegate>
|
||||||
public EqpHook(HookManager hooks, MetaState metaState)
|
public EqpHook(HookManager hooks, MetaState metaState)
|
||||||
{
|
{
|
||||||
_metaState = metaState;
|
_metaState = metaState;
|
||||||
Task = hooks.CreateHook<Delegate>("GetEqpFlags", "E8 ?? ?? ?? ?? 0F B6 44 24 ?? C0 E8", Detour, true);
|
Task = hooks.CreateHook<Delegate>("GetEqpFlags", "E8 ?? ?? ?? ?? 0F B6 44 24 ?? C0 E8", Detour, metaState.Config.EnableMods);
|
||||||
|
_metaState.Config.ModsEnabled += Toggle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Detour(CharacterUtility* utility, EqpEntry* flags, CharacterArmor* armor)
|
private void Detour(CharacterUtility* utility, EqpEntry* flags, CharacterArmor* armor)
|
||||||
|
|
@ -31,4 +32,7 @@ public unsafe class EqpHook : FastHook<EqpHook.Delegate>
|
||||||
|
|
||||||
Penumbra.Log.Excessive($"[GetEqpFlags] Invoked on 0x{(nint)utility:X} with 0x{(ulong)armor:X}, returned 0x{(ulong)*flags:X16}.");
|
Penumbra.Log.Excessive($"[GetEqpFlags] Invoked on 0x{(nint)utility:X} with 0x{(ulong)armor:X}, returned 0x{(ulong)*flags:X16}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
=> _metaState.Config.ModsEnabled -= Toggle;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ using Penumbra.Meta.Manipulations;
|
||||||
|
|
||||||
namespace Penumbra.Interop.Hooks.Meta;
|
namespace Penumbra.Interop.Hooks.Meta;
|
||||||
|
|
||||||
public class EstHook : FastHook<EstHook.Delegate>
|
public class EstHook : FastHook<EstHook.Delegate>, IDisposable
|
||||||
{
|
{
|
||||||
public delegate EstEntry Delegate(uint id, int estType, uint genderRace);
|
public delegate EstEntry Delegate(uint id, int estType, uint genderRace);
|
||||||
|
|
||||||
|
|
@ -14,14 +14,16 @@ public class EstHook : FastHook<EstHook.Delegate>
|
||||||
|
|
||||||
public EstHook(HookManager hooks, MetaState metaState)
|
public EstHook(HookManager hooks, MetaState metaState)
|
||||||
{
|
{
|
||||||
_metaState = metaState;
|
_metaState = metaState;
|
||||||
Task = hooks.CreateHook<Delegate>("GetEstEntry", "44 8B C9 83 EA ?? 74", Detour, true);
|
Task = hooks.CreateHook<Delegate>("GetEstEntry", "44 8B C9 83 EA ?? 74", Detour, metaState.Config.EnableMods);
|
||||||
|
_metaState.Config.ModsEnabled += Toggle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private EstEntry Detour(uint genderRace, int estType, uint id)
|
private EstEntry Detour(uint genderRace, int estType, uint id)
|
||||||
{
|
{
|
||||||
EstEntry ret;
|
EstEntry ret;
|
||||||
if (_metaState.EstCollection.TryPeek(out var collection) && collection is { Valid: true, ModCollection.MetaCache: { } cache }
|
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(genderRace, estType, id), out var entry))
|
||||||
ret = entry.Entry;
|
ret = entry.Entry;
|
||||||
else
|
else
|
||||||
|
|
@ -46,4 +48,7 @@ public class EstHook : FastHook<EstHook.Delegate>
|
||||||
};
|
};
|
||||||
return new EstIdentifier(i, type, gr);
|
return new EstIdentifier(i, type, gr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
=> _metaState.Config.ModsEnabled -= Toggle;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ using Penumbra.Meta.Manipulations;
|
||||||
|
|
||||||
namespace Penumbra.Interop.Hooks.Meta;
|
namespace Penumbra.Interop.Hooks.Meta;
|
||||||
|
|
||||||
public unsafe class GmpHook : FastHook<GmpHook.Delegate>
|
public unsafe class GmpHook : FastHook<GmpHook.Delegate>, IDisposable
|
||||||
{
|
{
|
||||||
public delegate nint Delegate(nint gmpResource, uint dividedHeadId);
|
public delegate nint Delegate(nint gmpResource, uint dividedHeadId);
|
||||||
|
|
||||||
|
|
@ -16,7 +16,8 @@ public unsafe class GmpHook : FastHook<GmpHook.Delegate>
|
||||||
public GmpHook(HookManager hooks, MetaState metaState)
|
public GmpHook(HookManager hooks, MetaState metaState)
|
||||||
{
|
{
|
||||||
_metaState = metaState;
|
_metaState = metaState;
|
||||||
Task = hooks.CreateHook<Delegate>("GetGmpEntry", "E8 ?? ?? ?? ?? 48 85 C0 74 ?? 43 8D 0C", Detour, true);
|
Task = hooks.CreateHook<Delegate>("GetGmpEntry", "E8 ?? ?? ?? ?? 48 85 C0 74 ?? 43 8D 0C", Detour, metaState.Config.EnableMods);
|
||||||
|
_metaState.Config.ModsEnabled += Toggle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
|
|
@ -27,7 +28,8 @@ public unsafe class GmpHook : FastHook<GmpHook.Delegate>
|
||||||
private nint Detour(nint gmpResource, uint dividedHeadId)
|
private nint Detour(nint gmpResource, uint dividedHeadId)
|
||||||
{
|
{
|
||||||
nint ret;
|
nint ret;
|
||||||
if (_metaState.GmpCollection.TryPeek(out var collection) && collection.Collection is { Valid: true, ModCollection.MetaCache: { } cache }
|
if (_metaState.GmpCollection.TryPeek(out var collection)
|
||||||
|
&& collection.Collection is { Valid: true, ModCollection.MetaCache: { } cache }
|
||||||
&& cache.Gmp.TryGetValue(new GmpIdentifier(collection.Id), out var entry))
|
&& cache.Gmp.TryGetValue(new GmpIdentifier(collection.Id), out var entry))
|
||||||
{
|
{
|
||||||
if (entry.Entry.Enabled)
|
if (entry.Entry.Enabled)
|
||||||
|
|
@ -61,4 +63,7 @@ public unsafe class GmpHook : FastHook<GmpHook.Delegate>
|
||||||
Marshal.FreeHGlobal((nint)Pointer);
|
Marshal.FreeHGlobal((nint)Pointer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
=> _metaState.Config.ModsEnabled -= Toggle;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ using Penumbra.Meta.Manipulations;
|
||||||
|
|
||||||
namespace Penumbra.Interop.Hooks.Meta;
|
namespace Penumbra.Interop.Hooks.Meta;
|
||||||
|
|
||||||
public unsafe class RspBustHook : FastHook<RspBustHook.Delegate>
|
public unsafe class RspBustHook : FastHook<RspBustHook.Delegate>, IDisposable
|
||||||
{
|
{
|
||||||
public delegate float* Delegate(nint cmpResource, float* storage, Race race, byte gender, byte isSecondSubRace, byte bodyType,
|
public delegate float* Delegate(nint cmpResource, float* storage, Race race, byte gender, byte isSecondSubRace, byte bodyType,
|
||||||
byte bustSize);
|
byte bustSize);
|
||||||
|
|
@ -19,7 +19,8 @@ public unsafe class RspBustHook : FastHook<RspBustHook.Delegate>
|
||||||
{
|
{
|
||||||
_metaState = metaState;
|
_metaState = metaState;
|
||||||
_metaFileManager = metaFileManager;
|
_metaFileManager = metaFileManager;
|
||||||
Task = hooks.CreateHook<Delegate>("GetRspBust", "E8 ?? ?? ?? ?? F2 0F 10 44 24 ?? 8B 44 24", Detour, true);
|
Task = hooks.CreateHook<Delegate>("GetRspBust", "E8 ?? ?? ?? ?? F2 0F 10 44 24 ?? 8B 44 24", Detour, metaState.Config.EnableMods);
|
||||||
|
_metaState.Config.ModsEnabled += Toggle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private float* Detour(nint cmpResource, float* storage, Race race, byte gender, byte isSecondSubRace, byte bodyType, byte bustSize)
|
private float* Detour(nint cmpResource, float* storage, Race race, byte gender, byte isSecondSubRace, byte bodyType, byte bustSize)
|
||||||
|
|
@ -63,4 +64,7 @@ public unsafe class RspBustHook : FastHook<RspBustHook.Delegate>
|
||||||
$"[GetRspBust] Invoked on 0x{cmpResource:X} with {race}, {(Gender)(gender + 1)}, {isSecondSubRace == 1}, {bodyType}, {bustSize}, returned {storage[0]}, {storage[1]}, {storage[2]}.");
|
$"[GetRspBust] Invoked on 0x{cmpResource:X} with {race}, {(Gender)(gender + 1)}, {isSecondSubRace == 1}, {bodyType}, {bustSize}, returned {storage[0]}, {storage[1]}, {storage[2]}.");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
=> _metaState.Config.ModsEnabled -= Toggle;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
|
||||||
using OtterGui.Services;
|
using OtterGui.Services;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.Interop.PathResolving;
|
using Penumbra.Interop.PathResolving;
|
||||||
|
|
@ -8,7 +7,7 @@ using Penumbra.Meta.Manipulations;
|
||||||
|
|
||||||
namespace Penumbra.Interop.Hooks.Meta;
|
namespace Penumbra.Interop.Hooks.Meta;
|
||||||
|
|
||||||
public class RspHeightHook : FastHook<RspHeightHook.Delegate>
|
public class RspHeightHook : FastHook<RspHeightHook.Delegate>, IDisposable
|
||||||
{
|
{
|
||||||
public delegate float Delegate(nint cmpResource, Race clan, byte gender, byte isSecondSubRace, byte bodyType, byte height);
|
public delegate float Delegate(nint cmpResource, Race clan, byte gender, byte isSecondSubRace, byte bodyType, byte height);
|
||||||
|
|
||||||
|
|
@ -17,15 +16,18 @@ public class RspHeightHook : FastHook<RspHeightHook.Delegate>
|
||||||
|
|
||||||
public RspHeightHook(HookManager hooks, MetaState metaState, MetaFileManager metaFileManager)
|
public RspHeightHook(HookManager hooks, MetaState metaState, MetaFileManager metaFileManager)
|
||||||
{
|
{
|
||||||
_metaState = metaState;
|
_metaState = metaState;
|
||||||
_metaFileManager = metaFileManager;
|
_metaFileManager = metaFileManager;
|
||||||
Task = hooks.CreateHook<Delegate>("GetRspHeight", "E8 ?? ?? ?? ?? 48 8B 8E ?? ?? ?? ?? 44 8B CF", Detour, true);
|
Task = hooks.CreateHook<Delegate>("GetRspHeight", "E8 ?? ?? ?? ?? 48 8B 8E ?? ?? ?? ?? 44 8B CF", Detour, metaState.Config.EnableMods);
|
||||||
|
_metaState.Config.ModsEnabled += Toggle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe float Detour(nint cmpResource, Race race, byte gender, byte isSecondSubRace, byte bodyType, byte height)
|
private unsafe float Detour(nint cmpResource, Race race, byte gender, byte isSecondSubRace, byte bodyType, byte height)
|
||||||
{
|
{
|
||||||
float scale;
|
float scale;
|
||||||
if (bodyType < 2 && _metaState.RspCollection.TryPeek(out var collection) && collection is { Valid: true, ModCollection.MetaCache: { } cache })
|
if (bodyType < 2
|
||||||
|
&& _metaState.RspCollection.TryPeek(out var collection)
|
||||||
|
&& collection is { Valid: true, ModCollection.MetaCache: { } cache })
|
||||||
{
|
{
|
||||||
var clan = (SubRace)(((int)race - 1) * 2 + 1 + isSecondSubRace);
|
var clan = (SubRace)(((int)race - 1) * 2 + 1 + isSecondSubRace);
|
||||||
var (minIdent, maxIdent) = gender == 0
|
var (minIdent, maxIdent) = gender == 0
|
||||||
|
|
@ -66,4 +68,7 @@ public class RspHeightHook : FastHook<RspHeightHook.Delegate>
|
||||||
$"[GetRspHeight] Invoked on 0x{cmpResource:X} with {race}, {(Gender)(gender + 1)}, {isSecondSubRace == 1}, {bodyType}, {height}, returned {scale}.");
|
$"[GetRspHeight] Invoked on 0x{cmpResource:X} with {race}, {(Gender)(gender + 1)}, {isSecondSubRace == 1}, {bodyType}, {height}, returned {scale}.");
|
||||||
return scale;
|
return scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
=> _metaState.Config.ModsEnabled -= Toggle;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ using Penumbra.Meta.Manipulations;
|
||||||
|
|
||||||
namespace Penumbra.Interop.Hooks.Meta;
|
namespace Penumbra.Interop.Hooks.Meta;
|
||||||
|
|
||||||
public class RspTailHook : FastHook<RspTailHook.Delegate>
|
public class RspTailHook : FastHook<RspTailHook.Delegate>, IDisposable
|
||||||
{
|
{
|
||||||
public delegate float Delegate(nint cmpResource, Race clan, byte gender, byte isSecondSubRace, byte bodyType, byte height);
|
public delegate float Delegate(nint cmpResource, Race clan, byte gender, byte isSecondSubRace, byte bodyType, byte height);
|
||||||
|
|
||||||
|
|
@ -18,7 +18,8 @@ public class RspTailHook : FastHook<RspTailHook.Delegate>
|
||||||
{
|
{
|
||||||
_metaState = metaState;
|
_metaState = metaState;
|
||||||
_metaFileManager = metaFileManager;
|
_metaFileManager = metaFileManager;
|
||||||
Task = hooks.CreateHook<Delegate>("GetRspTail", "E8 ?? ?? ?? ?? 0F 28 F0 48 8B 05", Detour, true);
|
Task = hooks.CreateHook<Delegate>("GetRspTail", "E8 ?? ?? ?? ?? 0F 28 F0 48 8B 05", Detour, metaState.Config.EnableMods);
|
||||||
|
_metaState.Config.ModsEnabled += Toggle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe float Detour(nint cmpResource, Race race, byte gender, byte isSecondSubRace, byte bodyType, byte tailLength)
|
private unsafe float Detour(nint cmpResource, Race race, byte gender, byte isSecondSubRace, byte bodyType, byte tailLength)
|
||||||
|
|
@ -65,4 +66,7 @@ public class RspTailHook : FastHook<RspTailHook.Delegate>
|
||||||
$"[GetRspTail] Invoked on 0x{cmpResource:X} with {race}, {(Gender)(gender + 1)}, {isSecondSubRace == 1}, {bodyType}, {tailLength}, returned {scale}.");
|
$"[GetRspTail] Invoked on 0x{cmpResource:X} with {race}, {(Gender)(gender + 1)}, {isSecondSubRace == 1}, {bodyType}, {tailLength}, returned {scale}.");
|
||||||
return scale;
|
return scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
=> _metaState.Config.ModsEnabled -= Toggle;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ namespace Penumbra.Interop.PathResolving;
|
||||||
// GMP Entries seem to be only used by "48 8B ?? 53 55 57 48 83 ?? ?? 48 8B", which is SetupVisor.
|
// GMP Entries seem to be only used by "48 8B ?? 53 55 57 48 83 ?? ?? 48 8B", which is SetupVisor.
|
||||||
public sealed unsafe class MetaState : IDisposable, IService
|
public sealed unsafe class MetaState : IDisposable, IService
|
||||||
{
|
{
|
||||||
private readonly Configuration _config;
|
public readonly Configuration Config;
|
||||||
private readonly CommunicatorService _communicator;
|
private readonly CommunicatorService _communicator;
|
||||||
private readonly CollectionResolver _collectionResolver;
|
private readonly CollectionResolver _collectionResolver;
|
||||||
private readonly ResourceLoader _resources;
|
private readonly ResourceLoader _resources;
|
||||||
|
|
@ -64,7 +64,7 @@ public sealed unsafe class MetaState : IDisposable, IService
|
||||||
_resources = resources;
|
_resources = resources;
|
||||||
_createCharacterBase = createCharacterBase;
|
_createCharacterBase = createCharacterBase;
|
||||||
_characterUtility = characterUtility;
|
_characterUtility = characterUtility;
|
||||||
_config = config;
|
Config = config;
|
||||||
_createCharacterBase.Subscribe(OnCreatingCharacterBase, CreateCharacterBase.Priority.MetaState);
|
_createCharacterBase.Subscribe(OnCreatingCharacterBase, CreateCharacterBase.Priority.MetaState);
|
||||||
_createCharacterBase.Subscribe(OnCharacterBaseCreated, CreateCharacterBase.PostEvent.Priority.MetaState);
|
_createCharacterBase.Subscribe(OnCharacterBaseCreated, CreateCharacterBase.PostEvent.Priority.MetaState);
|
||||||
}
|
}
|
||||||
|
|
@ -84,7 +84,7 @@ public sealed unsafe class MetaState : IDisposable, IService
|
||||||
}
|
}
|
||||||
|
|
||||||
public DecalReverter ResolveDecal(ResolveData resolve, bool which)
|
public DecalReverter ResolveDecal(ResolveData resolve, bool which)
|
||||||
=> new(_config, _characterUtility, _resources, resolve, which);
|
=> new(Config, _characterUtility, _resources, resolve, which);
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
|
@ -99,7 +99,7 @@ public sealed unsafe class MetaState : IDisposable, IService
|
||||||
_communicator.CreatingCharacterBase.Invoke(_lastCreatedCollection.AssociatedGameObject,
|
_communicator.CreatingCharacterBase.Invoke(_lastCreatedCollection.AssociatedGameObject,
|
||||||
_lastCreatedCollection.ModCollection.Id, (nint)modelCharaId, (nint)customize, (nint)equipData);
|
_lastCreatedCollection.ModCollection.Id, (nint)modelCharaId, (nint)customize, (nint)equipData);
|
||||||
|
|
||||||
var decal = new DecalReverter(_config, _characterUtility, _resources, _lastCreatedCollection,
|
var decal = new DecalReverter(Config, _characterUtility, _resources, _lastCreatedCollection,
|
||||||
UsesDecal(*(uint*)modelCharaId, (nint)customize));
|
UsesDecal(*(uint*)modelCharaId, (nint)customize));
|
||||||
RspCollection.Push(_lastCreatedCollection);
|
RspCollection.Push(_lastCreatedCollection);
|
||||||
_characterBaseCreateMetaChanges.Dispose(); // Should always be empty.
|
_characterBaseCreateMetaChanges.Dispose(); // Should always be empty.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue