diff --git a/Penumbra/Interop/Hooks/Animation/ApricotListenerSoundPlay.cs b/Penumbra/Interop/Hooks/Animation/ApricotListenerSoundPlay.cs index 96a51027..44eb7ebb 100644 --- a/Penumbra/Interop/Hooks/Animation/ApricotListenerSoundPlay.cs +++ b/Penumbra/Interop/Hooks/Animation/ApricotListenerSoundPlay.cs @@ -24,7 +24,7 @@ public sealed unsafe class ApricotListenerSoundPlayCaller : FastHook("Apricot Listener Sound Play Caller", Sigs.ApricotListenerSoundPlayCaller, Detour, - true); //HookSettings.VfxIdentificationHooks); + !HookOverrides.Instance.Animation.ApricotListenerSoundPlayCaller); } public delegate nint Delegate(nint a1, nint a2, float a3); diff --git a/Penumbra/Interop/Hooks/Animation/CharacterBaseLoadAnimation.cs b/Penumbra/Interop/Hooks/Animation/CharacterBaseLoadAnimation.cs index f99d8ca4..22609afc 100644 --- a/Penumbra/Interop/Hooks/Animation/CharacterBaseLoadAnimation.cs +++ b/Penumbra/Interop/Hooks/Animation/CharacterBaseLoadAnimation.cs @@ -26,7 +26,8 @@ public sealed unsafe class CharacterBaseLoadAnimation : FastHook("CharacterBase Load Animation", Sigs.CharacterBaseLoadAnimation, Detour, HookSettings.VfxIdentificationHooks); + Task = hooks.CreateHook("CharacterBase Load Animation", Sigs.CharacterBaseLoadAnimation, Detour, + !HookOverrides.Instance.Animation.CharacterBaseLoadAnimation); } public delegate void Delegate(DrawObject* drawBase); diff --git a/Penumbra/Interop/Hooks/Animation/Dismount.cs b/Penumbra/Interop/Hooks/Animation/Dismount.cs index 034011e7..17151083 100644 --- a/Penumbra/Interop/Hooks/Animation/Dismount.cs +++ b/Penumbra/Interop/Hooks/Animation/Dismount.cs @@ -16,7 +16,7 @@ public sealed unsafe class Dismount : FastHook { _state = state; _collectionResolver = collectionResolver; - Task = hooks.CreateHook("Dismount", Sigs.Dismount, Detour, HookSettings.VfxIdentificationHooks); + Task = hooks.CreateHook("Dismount", Sigs.Dismount, Detour, !HookOverrides.Instance.Animation.Dismount); } public delegate void Delegate(MountContainer* a1, nint a2); diff --git a/Penumbra/Interop/Hooks/Animation/LoadAreaVfx.cs b/Penumbra/Interop/Hooks/Animation/LoadAreaVfx.cs index 48dc0078..29afd4ea 100644 --- a/Penumbra/Interop/Hooks/Animation/LoadAreaVfx.cs +++ b/Penumbra/Interop/Hooks/Animation/LoadAreaVfx.cs @@ -17,10 +17,10 @@ public sealed unsafe class LoadAreaVfx : FastHook public LoadAreaVfx(HookManager hooks, GameState state, CollectionResolver collectionResolver, CrashHandlerService crashHandler) { - _state = state; + _state = state; _collectionResolver = collectionResolver; - _crashHandler = crashHandler; - Task = hooks.CreateHook("Load Area VFX", Sigs.LoadAreaVfx, Detour, HookSettings.VfxIdentificationHooks); + _crashHandler = crashHandler; + Task = hooks.CreateHook("Load Area VFX", Sigs.LoadAreaVfx, Detour, !HookOverrides.Instance.Animation.LoadAreaVfx); } public delegate nint Delegate(uint vfxId, float* pos, GameObject* caster, float unk1, float unk2, byte unk3); diff --git a/Penumbra/Interop/Hooks/Animation/LoadCharacterSound.cs b/Penumbra/Interop/Hooks/Animation/LoadCharacterSound.cs index 8d1096d2..91b70ede 100644 --- a/Penumbra/Interop/Hooks/Animation/LoadCharacterSound.cs +++ b/Penumbra/Interop/Hooks/Animation/LoadCharacterSound.cs @@ -20,7 +20,7 @@ public sealed unsafe class LoadCharacterSound : FastHook("Load Character Sound", (nint)VfxContainer.MemberFunctionPointers.LoadCharacterSound, Detour, - HookSettings.VfxIdentificationHooks); + !HookOverrides.Instance.Animation.LoadCharacterSound); } public delegate nint Delegate(VfxContainer* container, int unk1, int unk2, nint unk3, ulong unk4, int unk5, int unk6, ulong unk7); diff --git a/Penumbra/Interop/Hooks/Animation/LoadCharacterVfx.cs b/Penumbra/Interop/Hooks/Animation/LoadCharacterVfx.cs index af801345..9a57ca12 100644 --- a/Penumbra/Interop/Hooks/Animation/LoadCharacterVfx.cs +++ b/Penumbra/Interop/Hooks/Animation/LoadCharacterVfx.cs @@ -26,7 +26,7 @@ public sealed unsafe class LoadCharacterVfx : FastHook("Load Character VFX", Sigs.LoadCharacterVfx, Detour, HookSettings.VfxIdentificationHooks); + Task = hooks.CreateHook("Load Character VFX", Sigs.LoadCharacterVfx, Detour, !HookOverrides.Instance.Animation.LoadCharacterVfx); } public delegate nint Delegate(byte* vfxPath, VfxParams* vfxParams, byte unk1, byte unk2, float unk3, int unk4); diff --git a/Penumbra/Interop/Hooks/Animation/LoadTimelineResources.cs b/Penumbra/Interop/Hooks/Animation/LoadTimelineResources.cs index 8bb14db6..cdd82b95 100644 --- a/Penumbra/Interop/Hooks/Animation/LoadTimelineResources.cs +++ b/Penumbra/Interop/Hooks/Animation/LoadTimelineResources.cs @@ -31,7 +31,7 @@ public sealed unsafe class LoadTimelineResources : FastHook("Load Timeline Resources", Sigs.LoadTimelineResources, Detour, HookSettings.VfxIdentificationHooks); + Task = hooks.CreateHook("Load Timeline Resources", Sigs.LoadTimelineResources, Detour, !HookOverrides.Instance.Animation.LoadTimelineResources); } public delegate ulong Delegate(SchedulerTimeline* timeline); diff --git a/Penumbra/Interop/Hooks/Animation/PlayFootstep.cs b/Penumbra/Interop/Hooks/Animation/PlayFootstep.cs index e4a8c83c..858357c8 100644 --- a/Penumbra/Interop/Hooks/Animation/PlayFootstep.cs +++ b/Penumbra/Interop/Hooks/Animation/PlayFootstep.cs @@ -14,7 +14,7 @@ public sealed unsafe class PlayFootstep : FastHook { _state = state; _collectionResolver = collectionResolver; - Task = hooks.CreateHook("Play Footstep", Sigs.FootStepSound, Detour, HookSettings.VfxIdentificationHooks); + Task = hooks.CreateHook("Play Footstep", Sigs.FootStepSound, Detour, !HookOverrides.Instance.Animation.PlayFootstep); } public delegate void Delegate(GameObject* gameObject, int id, int unk); diff --git a/Penumbra/Interop/Hooks/Animation/ScheduleClipUpdate.cs b/Penumbra/Interop/Hooks/Animation/ScheduleClipUpdate.cs index 645b3565..dfbc615a 100644 --- a/Penumbra/Interop/Hooks/Animation/ScheduleClipUpdate.cs +++ b/Penumbra/Interop/Hooks/Animation/ScheduleClipUpdate.cs @@ -23,7 +23,7 @@ public sealed unsafe class ScheduleClipUpdate : FastHook("Schedule Clip Update", Sigs.ScheduleClipUpdate, Detour, HookSettings.VfxIdentificationHooks); + Task = hooks.CreateHook("Schedule Clip Update", Sigs.ScheduleClipUpdate, Detour, !HookOverrides.Instance.Animation.ScheduleClipUpdate); } public delegate void Delegate(ClipScheduler* x); diff --git a/Penumbra/Interop/Hooks/Animation/SomeActionLoad.cs b/Penumbra/Interop/Hooks/Animation/SomeActionLoad.cs index 1f3c0e3b..e1751261 100644 --- a/Penumbra/Interop/Hooks/Animation/SomeActionLoad.cs +++ b/Penumbra/Interop/Hooks/Animation/SomeActionLoad.cs @@ -20,7 +20,7 @@ public sealed unsafe class SomeActionLoad : FastHook _state = state; _collectionResolver = collectionResolver; _crashHandler = crashHandler; - Task = hooks.CreateHook("Some Action Load", Sigs.LoadSomeAction, Detour, HookSettings.VfxIdentificationHooks); + Task = hooks.CreateHook("Some Action Load", Sigs.LoadSomeAction, Detour, !HookOverrides.Instance.Animation.SomeActionLoad); } public delegate void Delegate(TimelineContainer* timelineManager); diff --git a/Penumbra/Interop/Hooks/Animation/SomeMountAnimation.cs b/Penumbra/Interop/Hooks/Animation/SomeMountAnimation.cs index f2b48afe..75f1240a 100644 --- a/Penumbra/Interop/Hooks/Animation/SomeMountAnimation.cs +++ b/Penumbra/Interop/Hooks/Animation/SomeMountAnimation.cs @@ -15,7 +15,7 @@ public sealed unsafe class SomeMountAnimation : FastHook("Some Mount Animation", Sigs.UnkMountAnimation, Detour, HookSettings.VfxIdentificationHooks); + Task = hooks.CreateHook("Some Mount Animation", Sigs.UnkMountAnimation, Detour, !HookOverrides.Instance.Animation.SomeMountAnimation); } public delegate void Delegate(DrawObject* drawObject, uint unk1, byte unk2, uint unk3); diff --git a/Penumbra/Interop/Hooks/Animation/SomePapLoad.cs b/Penumbra/Interop/Hooks/Animation/SomePapLoad.cs index 8f952df5..7339c397 100644 --- a/Penumbra/Interop/Hooks/Animation/SomePapLoad.cs +++ b/Penumbra/Interop/Hooks/Animation/SomePapLoad.cs @@ -22,7 +22,7 @@ public sealed unsafe class SomePapLoad : FastHook _collectionResolver = collectionResolver; _objects = objects; _crashHandler = crashHandler; - Task = hooks.CreateHook("Some PAP Load", Sigs.LoadSomePap, Detour, HookSettings.VfxIdentificationHooks); + Task = hooks.CreateHook("Some PAP Load", Sigs.LoadSomePap, Detour, !HookOverrides.Instance.Animation.SomePapLoad); } public delegate void Delegate(nint a1, int a2, nint a3, int a4); diff --git a/Penumbra/Interop/Hooks/Animation/SomeParasolAnimation.cs b/Penumbra/Interop/Hooks/Animation/SomeParasolAnimation.cs index 165bd5eb..9df8d4eb 100644 --- a/Penumbra/Interop/Hooks/Animation/SomeParasolAnimation.cs +++ b/Penumbra/Interop/Hooks/Animation/SomeParasolAnimation.cs @@ -15,7 +15,7 @@ public sealed unsafe class SomeParasolAnimation : FastHook("Some Parasol Animation", Sigs.UnkParasolAnimation, Detour, HookSettings.VfxIdentificationHooks); + Task = hooks.CreateHook("Some Parasol Animation", Sigs.UnkParasolAnimation, Detour, !HookOverrides.Instance.Animation.SomeParasolAnimation); } public delegate void Delegate(DrawObject* drawObject, int unk1); diff --git a/Penumbra/Interop/Hooks/HookSettings.cs b/Penumbra/Interop/Hooks/HookSettings.cs index 9c60096f..a4f4201f 100644 --- a/Penumbra/Interop/Hooks/HookSettings.cs +++ b/Penumbra/Interop/Hooks/HookSettings.cs @@ -1,14 +1,140 @@ +using Dalamud.Plugin; +using Newtonsoft.Json; + namespace Penumbra.Interop.Hooks; -public static class HookSettings +public class HookOverrides { - public const bool AllHooks = true; + public static HookOverrides Instance = new(); - public const bool ObjectHooks = true && AllHooks; - public const bool ReplacementHooks = true && AllHooks; - public const bool ResourceHooks = true && AllHooks; - public const bool MetaEntryHooks = true && AllHooks; - public const bool MetaParentHooks = true && AllHooks; - public const bool VfxIdentificationHooks = true && AllHooks; - public const bool PostProcessingHooks = true && AllHooks; + public AnimationHooks Animation; + public MetaHooks Meta; + public ObjectHooks Objects; + public PostProcessingHooks PostProcessing; + public ResourceLoadingHooks ResourceLoading; + public ResourceHooks Resources; + + public HookOverrides Clone() + => new() + { + Animation = Animation, + Meta = Meta, + Objects = Objects, + PostProcessing = PostProcessing, + ResourceLoading = ResourceLoading, + Resources = Resources, + }; + + public struct AnimationHooks + { + public bool ApricotListenerSoundPlayCaller; + public bool CharacterBaseLoadAnimation; + public bool Dismount; + public bool LoadAreaVfx; + public bool LoadCharacterSound; + public bool LoadCharacterVfx; + public bool LoadTimelineResources; + public bool PlayFootstep; + public bool ScheduleClipUpdate; + public bool SomeActionLoad; + public bool SomeMountAnimation; + public bool SomePapLoad; + public bool SomeParasolAnimation; + } + + public struct MetaHooks + { + public bool CalculateHeight; + public bool ChangeCustomize; + public bool EqdpAccessoryHook; + public bool EqdpEquipHook; + public bool EqpHook; + public bool EstHook; + public bool GmpHook; + public bool ModelLoadComplete; + public bool RspBustHook; + public bool RspHeightHook; + public bool RspSetupCharacter; + public bool RspTailHook; + public bool SetupVisor; + public bool UpdateModel; + public bool UpdateRender; + } + + public struct ObjectHooks + { + public bool CharacterBaseDestructor; + public bool CharacterDestructor; + public bool CopyCharacter; + public bool CreateCharacterBase; + public bool EnableDraw; + public bool WeaponReload; + } + + public struct PostProcessingHooks + { + public bool HumanSetupScaling; + public bool HumanCreateDeformer; + public bool HumanOnRenderMaterial; + public bool ModelRendererOnRenderMaterial; + } + + public struct ResourceLoadingHooks + { + public bool CreateFileWHook; + public bool PapHooks; + public bool ReadSqPack; + public bool IncRef; + public bool DecRef; + public bool GetResourceSync; + public bool GetResourceAsync; + public bool CheckFileState; + public bool TexResourceHandleOnLoad; + public bool LoadMdlFileExtern; + } + + public struct ResourceHooks + { + public bool ApricotResourceLoad; + public bool LoadMtrlShpk; + public bool LoadMtrlTex; + public bool ResolvePathHooks; + public bool ResourceHandleDestructor; + } + + public const string FileName = "HookOverrides.json"; + + public static HookOverrides LoadFile(IDalamudPluginInterface pi) + { + var path = Path.Combine(pi.GetPluginConfigDirectory(), FileName); + if (!File.Exists(path)) + return new HookOverrides(); + + try + { + var text = File.ReadAllText(path); + var ret = JsonConvert.DeserializeObject(text); + Penumbra.Log.Warning("A hook override file was loaded, some hooks may be disabled and Penumbra might not be working as expected."); + return ret; + } + catch (Exception ex) + { + Penumbra.Log.Error($"A hook override file was found at {path}, but could not be loaded:\n{ex}"); + return new HookOverrides(); + } + } + + public void Write(IDalamudPluginInterface pi) + { + var path = Path.Combine(pi.GetPluginConfigDirectory(), FileName); + try + { + var text = JsonConvert.SerializeObject(this, Formatting.Indented); + File.WriteAllText(path, text); + } + catch (Exception ex) + { + Penumbra.Log.Error($"Could not write hook override file to {path}:\n{ex}"); + } + } } diff --git a/Penumbra/Interop/Hooks/Meta/CalculateHeight.cs b/Penumbra/Interop/Hooks/Meta/CalculateHeight.cs index aab64871..e71d07dd 100644 --- a/Penumbra/Interop/Hooks/Meta/CalculateHeight.cs +++ b/Penumbra/Interop/Hooks/Meta/CalculateHeight.cs @@ -14,7 +14,7 @@ public sealed unsafe class CalculateHeight : FastHook { _collectionResolver = collectionResolver; _metaState = metaState; - Task = hooks.CreateHook("Calculate Height", (nint)Character.MemberFunctionPointers.CalculateHeight, Detour, HookSettings.MetaParentHooks); + Task = hooks.CreateHook("Calculate Height", (nint)Character.MemberFunctionPointers.CalculateHeight, Detour, !HookOverrides.Instance.Meta.CalculateHeight); } public delegate ulong Delegate(Character* character); diff --git a/Penumbra/Interop/Hooks/Meta/ChangeCustomize.cs b/Penumbra/Interop/Hooks/Meta/ChangeCustomize.cs index f69e98e7..368845b4 100644 --- a/Penumbra/Interop/Hooks/Meta/ChangeCustomize.cs +++ b/Penumbra/Interop/Hooks/Meta/ChangeCustomize.cs @@ -16,7 +16,7 @@ public sealed unsafe class ChangeCustomize : FastHook { _collectionResolver = collectionResolver; _metaState = metaState; - Task = hooks.CreateHook("Change Customize", Sigs.ChangeCustomize, Detour, HookSettings.MetaParentHooks); + Task = hooks.CreateHook("Change Customize", Sigs.ChangeCustomize, Detour, !HookOverrides.Instance.Meta.ChangeCustomize); } public delegate bool Delegate(Human* human, CustomizeArray* data, byte skipEquipment); diff --git a/Penumbra/Interop/Hooks/Meta/EqdpAccessoryHook.cs b/Penumbra/Interop/Hooks/Meta/EqdpAccessoryHook.cs index 63cca53f..43328600 100644 --- a/Penumbra/Interop/Hooks/Meta/EqdpAccessoryHook.cs +++ b/Penumbra/Interop/Hooks/Meta/EqdpAccessoryHook.cs @@ -16,8 +16,10 @@ public unsafe class EqdpAccessoryHook : FastHook, ID public EqdpAccessoryHook(HookManager hooks, MetaState metaState) { _metaState = metaState; - Task = hooks.CreateHook("GetEqdpAccessoryEntry", Sigs.GetEqdpAccessoryEntry, Detour, metaState.Config.EnableMods && HookSettings.MetaEntryHooks); - _metaState.Config.ModsEnabled += Toggle; + Task = hooks.CreateHook("GetEqdpAccessoryEntry", Sigs.GetEqdpAccessoryEntry, Detour, + metaState.Config.EnableMods && !HookOverrides.Instance.Meta.EqdpAccessoryHook); + if (!HookOverrides.Instance.Meta.EqdpAccessoryHook) + _metaState.Config.ModsEnabled += Toggle; } private void Detour(CharacterUtility* utility, EqdpEntry* entry, uint setId, uint raceCode) diff --git a/Penumbra/Interop/Hooks/Meta/EqdpEquipHook.cs b/Penumbra/Interop/Hooks/Meta/EqdpEquipHook.cs index 5d5d2f84..fa0d5a29 100644 --- a/Penumbra/Interop/Hooks/Meta/EqdpEquipHook.cs +++ b/Penumbra/Interop/Hooks/Meta/EqdpEquipHook.cs @@ -16,8 +16,9 @@ public unsafe class EqdpEquipHook : FastHook, IDisposabl public EqdpEquipHook(HookManager hooks, MetaState metaState) { _metaState = metaState; - Task = hooks.CreateHook("GetEqdpEquipEntry", Sigs.GetEqdpEquipEntry, Detour, metaState.Config.EnableMods && HookSettings.MetaEntryHooks); - _metaState.Config.ModsEnabled += Toggle; + Task = hooks.CreateHook("GetEqdpEquipEntry", Sigs.GetEqdpEquipEntry, Detour, metaState.Config.EnableMods && !HookOverrides.Instance.Meta.EqdpEquipHook); + if (!HookOverrides.Instance.Meta.EqdpEquipHook) + _metaState.Config.ModsEnabled += Toggle; } private void Detour(CharacterUtility* utility, EqdpEntry* entry, uint setId, uint raceCode) diff --git a/Penumbra/Interop/Hooks/Meta/EqpHook.cs b/Penumbra/Interop/Hooks/Meta/EqpHook.cs index f47db795..f35b922b 100644 --- a/Penumbra/Interop/Hooks/Meta/EqpHook.cs +++ b/Penumbra/Interop/Hooks/Meta/EqpHook.cs @@ -15,8 +15,10 @@ public unsafe class EqpHook : FastHook, IDisposable public EqpHook(HookManager hooks, MetaState metaState) { _metaState = metaState; - Task = hooks.CreateHook("GetEqpFlags", Sigs.GetEqpEntry, Detour, metaState.Config.EnableMods && HookSettings.MetaEntryHooks); - _metaState.Config.ModsEnabled += Toggle; + Task = hooks.CreateHook("GetEqpFlags", Sigs.GetEqpEntry, Detour, + metaState.Config.EnableMods && !HookOverrides.Instance.Meta.EqpHook); + if (!HookOverrides.Instance.Meta.EqpHook) + _metaState.Config.ModsEnabled += Toggle; } private void Detour(CharacterUtility* utility, EqpEntry* flags, CharacterArmor* armor) diff --git a/Penumbra/Interop/Hooks/Meta/EstHook.cs b/Penumbra/Interop/Hooks/Meta/EstHook.cs index 825b1244..8284eb69 100644 --- a/Penumbra/Interop/Hooks/Meta/EstHook.cs +++ b/Penumbra/Interop/Hooks/Meta/EstHook.cs @@ -21,8 +21,9 @@ public unsafe class EstHook : FastHook, IDisposable _metaState = metaState; _characterUtility = characterUtility; Task = hooks.CreateHook("FindEstEntry", Sigs.FindEstEntry, Detour, - metaState.Config.EnableMods && HookSettings.MetaEntryHooks); - _metaState.Config.ModsEnabled += Toggle; + metaState.Config.EnableMods && !HookOverrides.Instance.Meta.EstHook); + if (!HookOverrides.Instance.Meta.EstHook) + _metaState.Config.ModsEnabled += Toggle; } private EstEntry Detour(ResourceHandle* estResource, uint genderRace, uint id) diff --git a/Penumbra/Interop/Hooks/Meta/GmpHook.cs b/Penumbra/Interop/Hooks/Meta/GmpHook.cs index 12b221d9..d656ebdb 100644 --- a/Penumbra/Interop/Hooks/Meta/GmpHook.cs +++ b/Penumbra/Interop/Hooks/Meta/GmpHook.cs @@ -17,8 +17,10 @@ public unsafe class GmpHook : FastHook, IDisposable public GmpHook(HookManager hooks, MetaState metaState) { _metaState = metaState; - Task = hooks.CreateHook("GetGmpEntry", Sigs.GetGmpEntry, Detour, metaState.Config.EnableMods && HookSettings.MetaEntryHooks); - _metaState.Config.ModsEnabled += Toggle; + Task = hooks.CreateHook("GetGmpEntry", Sigs.GetGmpEntry, Detour, + metaState.Config.EnableMods && !HookOverrides.Instance.Meta.GmpHook); + if (!HookOverrides.Instance.Meta.GmpHook) + _metaState.Config.ModsEnabled += Toggle; } private ulong Detour(CharacterUtility* characterUtility, ulong* outputEntry, ushort setId) diff --git a/Penumbra/Interop/Hooks/Meta/ModelLoadComplete.cs b/Penumbra/Interop/Hooks/Meta/ModelLoadComplete.cs index c1803745..4b9b05b1 100644 --- a/Penumbra/Interop/Hooks/Meta/ModelLoadComplete.cs +++ b/Penumbra/Interop/Hooks/Meta/ModelLoadComplete.cs @@ -13,7 +13,7 @@ public sealed unsafe class ModelLoadComplete : FastHook("Model Load Complete", vtables.HumanVTable[59], Detour, HookSettings.MetaParentHooks); + Task = hooks.CreateHook("Model Load Complete", vtables.HumanVTable[59], Detour, !HookOverrides.Instance.Meta.ModelLoadComplete); } public delegate void Delegate(DrawObject* drawObject); diff --git a/Penumbra/Interop/Hooks/Meta/RspBustHook.cs b/Penumbra/Interop/Hooks/Meta/RspBustHook.cs index e08dc393..c49556bf 100644 --- a/Penumbra/Interop/Hooks/Meta/RspBustHook.cs +++ b/Penumbra/Interop/Hooks/Meta/RspBustHook.cs @@ -19,8 +19,10 @@ public unsafe class RspBustHook : FastHook, IDisposable { _metaState = metaState; _metaFileManager = metaFileManager; - Task = hooks.CreateHook("GetRspBust", Sigs.GetRspBust, Detour, metaState.Config.EnableMods && HookSettings.MetaEntryHooks); - _metaState.Config.ModsEnabled += Toggle; + Task = hooks.CreateHook("GetRspBust", Sigs.GetRspBust, Detour, + metaState.Config.EnableMods && !HookOverrides.Instance.Meta.RspBustHook); + if (!HookOverrides.Instance.Meta.RspBustHook) + _metaState.Config.ModsEnabled += Toggle; } private float* Detour(nint cmpResource, float* storage, SubRace clan, byte gender, byte bodyType, byte bustSize) @@ -34,7 +36,9 @@ public unsafe class RspBustHook : FastHook, IDisposable } var ret = storage; - 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 bustScale = bustSize / 100f; var ptr = CmpFile.GetDefaults(_metaFileManager, clan, RspAttribute.BustMinX); diff --git a/Penumbra/Interop/Hooks/Meta/RspHeightHook.cs b/Penumbra/Interop/Hooks/Meta/RspHeightHook.cs index 20e3c939..49180d6e 100644 --- a/Penumbra/Interop/Hooks/Meta/RspHeightHook.cs +++ b/Penumbra/Interop/Hooks/Meta/RspHeightHook.cs @@ -17,10 +17,12 @@ public class RspHeightHook : FastHook, IDisposable public RspHeightHook(HookManager hooks, MetaState metaState, MetaFileManager metaFileManager) { - _metaState = metaState; + _metaState = metaState; _metaFileManager = metaFileManager; - Task = hooks.CreateHook("GetRspHeight", Sigs.GetRspHeight, Detour, metaState.Config.EnableMods && HookSettings.MetaEntryHooks); - _metaState.Config.ModsEnabled += Toggle; + Task = hooks.CreateHook("GetRspHeight", Sigs.GetRspHeight, Detour, + metaState.Config.EnableMods && !HookOverrides.Instance.Meta.RspHeightHook); + if (!HookOverrides.Instance.Meta.RspHeightHook) + _metaState.Config.ModsEnabled += Toggle; } private unsafe float Detour(nint cmpResource, SubRace clan, byte gender, byte bodyType, byte height) @@ -33,6 +35,7 @@ public class RspHeightHook : FastHook, IDisposable // Special cases. if (height == 0xFF) return 1.0f; + if (height > 100) height = 0; diff --git a/Penumbra/Interop/Hooks/Meta/RspSetupCharacter.cs b/Penumbra/Interop/Hooks/Meta/RspSetupCharacter.cs index 8bcc7593..952a2e29 100644 --- a/Penumbra/Interop/Hooks/Meta/RspSetupCharacter.cs +++ b/Penumbra/Interop/Hooks/Meta/RspSetupCharacter.cs @@ -15,7 +15,7 @@ public sealed unsafe class RspSetupCharacter : FastHook("RSP Setup Character", Sigs.RspSetupCharacter, Detour, HookSettings.MetaParentHooks); + Task = hooks.CreateHook("RSP Setup Character", Sigs.RspSetupCharacter, Detour, !HookOverrides.Instance.Meta.RspSetupCharacter); } public delegate void Delegate(DrawObject* drawObject, nint unk2, float unk3, nint unk4, byte unk5); diff --git a/Penumbra/Interop/Hooks/Meta/RspTailHook.cs b/Penumbra/Interop/Hooks/Meta/RspTailHook.cs index 86d21c6f..b434efa6 100644 --- a/Penumbra/Interop/Hooks/Meta/RspTailHook.cs +++ b/Penumbra/Interop/Hooks/Meta/RspTailHook.cs @@ -19,14 +19,18 @@ public class RspTailHook : FastHook, IDisposable { _metaState = metaState; _metaFileManager = metaFileManager; - Task = hooks.CreateHook("GetRspTail", Sigs.GetRspTail, Detour, metaState.Config.EnableMods && HookSettings.MetaEntryHooks); - _metaState.Config.ModsEnabled += Toggle; + Task = hooks.CreateHook("GetRspTail", Sigs.GetRspTail, Detour, + metaState.Config.EnableMods && !HookOverrides.Instance.Meta.RspTailHook); + if (!HookOverrides.Instance.Meta.RspTailHook) + _metaState.Config.ModsEnabled += Toggle; } private unsafe float Detour(nint cmpResource, Race race, byte gender, byte isSecondSubRace, byte bodyType, byte tailLength) { 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 (minIdent, maxIdent) = gender == 0 diff --git a/Penumbra/Interop/Hooks/Meta/SetupVisor.cs b/Penumbra/Interop/Hooks/Meta/SetupVisor.cs index 83c0e0c4..063a9462 100644 --- a/Penumbra/Interop/Hooks/Meta/SetupVisor.cs +++ b/Penumbra/Interop/Hooks/Meta/SetupVisor.cs @@ -19,7 +19,7 @@ public sealed unsafe class SetupVisor : FastHook { _collectionResolver = collectionResolver; _metaState = metaState; - Task = hooks.CreateHook("Setup Visor", Sigs.SetupVisor, Detour, HookSettings.MetaParentHooks); + Task = hooks.CreateHook("Setup Visor", Sigs.SetupVisor, Detour, !HookOverrides.Instance.Meta.SetupVisor); } public delegate byte Delegate(DrawObject* drawObject, ushort modelId, byte visorState); diff --git a/Penumbra/Interop/Hooks/Meta/UpdateModel.cs b/Penumbra/Interop/Hooks/Meta/UpdateModel.cs index a088a0f2..72beea0e 100644 --- a/Penumbra/Interop/Hooks/Meta/UpdateModel.cs +++ b/Penumbra/Interop/Hooks/Meta/UpdateModel.cs @@ -15,7 +15,7 @@ public sealed unsafe class UpdateModel : FastHook { _collectionResolver = collectionResolver; _metaState = metaState; - Task = hooks.CreateHook("Update Model", Sigs.UpdateModel, Detour, HookSettings.MetaParentHooks); + Task = hooks.CreateHook("Update Model", Sigs.UpdateModel, Detour, !HookOverrides.Instance.Meta.UpdateModel); } public delegate void Delegate(DrawObject* drawObject); diff --git a/Penumbra/Interop/Hooks/Meta/UpdateRender.cs b/Penumbra/Interop/Hooks/Meta/UpdateRender.cs index 95cc0e15..ef0068b6 100644 --- a/Penumbra/Interop/Hooks/Meta/UpdateRender.cs +++ b/Penumbra/Interop/Hooks/Meta/UpdateRender.cs @@ -13,8 +13,8 @@ public sealed unsafe class UpdateRender : FastHook public UpdateRender(HookManager hooks, CollectionResolver collectionResolver, MetaState metaState, CharacterBaseVTables vTables) { _collectionResolver = collectionResolver; - _metaState = metaState; - Task = hooks.CreateHook("Human.UpdateRender", vTables.HumanVTable[4], Detour, HookSettings.MetaParentHooks); + _metaState = metaState; + Task = hooks.CreateHook("Human.UpdateRender", vTables.HumanVTable[4], Detour, !HookOverrides.Instance.Meta.UpdateRender); } public delegate void Delegate(DrawObject* drawObject); diff --git a/Penumbra/Interop/Hooks/Objects/CharacterBaseDestructor.cs b/Penumbra/Interop/Hooks/Objects/CharacterBaseDestructor.cs index c67bb9f3..7636718e 100644 --- a/Penumbra/Interop/Hooks/Objects/CharacterBaseDestructor.cs +++ b/Penumbra/Interop/Hooks/Objects/CharacterBaseDestructor.cs @@ -19,7 +19,7 @@ public sealed unsafe class CharacterBaseDestructor : EventWrapperPtr _task = hooks.CreateHook(Name, Address, Detour, HookSettings.ObjectHooks); + => _task = hooks.CreateHook(Name, Address, Detour, !HookOverrides.Instance.Objects.CharacterBaseDestructor); private readonly Task> _task; diff --git a/Penumbra/Interop/Hooks/Objects/CharacterDestructor.cs b/Penumbra/Interop/Hooks/Objects/CharacterDestructor.cs index 618d0bd7..ffe2f72d 100644 --- a/Penumbra/Interop/Hooks/Objects/CharacterDestructor.cs +++ b/Penumbra/Interop/Hooks/Objects/CharacterDestructor.cs @@ -19,7 +19,7 @@ public sealed unsafe class CharacterDestructor : EventWrapperPtr _task = hooks.CreateHook(Name, Sigs.CharacterDestructor, Detour, HookSettings.ObjectHooks); + => _task = hooks.CreateHook(Name, Sigs.CharacterDestructor, Detour, !HookOverrides.Instance.Objects.CharacterDestructor); private readonly Task> _task; diff --git a/Penumbra/Interop/Hooks/Objects/CopyCharacter.cs b/Penumbra/Interop/Hooks/Objects/CopyCharacter.cs index d81043c8..bc18a7ad 100644 --- a/Penumbra/Interop/Hooks/Objects/CopyCharacter.cs +++ b/Penumbra/Interop/Hooks/Objects/CopyCharacter.cs @@ -15,7 +15,7 @@ public sealed unsafe class CopyCharacter : EventWrapperPtr _task = hooks.CreateHook(Name, Address, Detour, HookSettings.ObjectHooks); + => _task = hooks.CreateHook(Name, Address, Detour, !HookOverrides.Instance.Objects.CopyCharacter); private readonly Task> _task; diff --git a/Penumbra/Interop/Hooks/Objects/CreateCharacterBase.cs b/Penumbra/Interop/Hooks/Objects/CreateCharacterBase.cs index f00a9984..e29876ac 100644 --- a/Penumbra/Interop/Hooks/Objects/CreateCharacterBase.cs +++ b/Penumbra/Interop/Hooks/Objects/CreateCharacterBase.cs @@ -16,7 +16,7 @@ public sealed unsafe class CreateCharacterBase : EventWrapperPtr _task = hooks.CreateHook(Name, Address, Detour, HookSettings.ObjectHooks); + => _task = hooks.CreateHook(Name, Address, Detour, !HookOverrides.Instance.Objects.CreateCharacterBase); private readonly Task> _task; diff --git a/Penumbra/Interop/Hooks/Objects/EnableDraw.cs b/Penumbra/Interop/Hooks/Objects/EnableDraw.cs index 8b701fe5..68bb28af 100644 --- a/Penumbra/Interop/Hooks/Objects/EnableDraw.cs +++ b/Penumbra/Interop/Hooks/Objects/EnableDraw.cs @@ -17,7 +17,7 @@ public sealed unsafe class EnableDraw : IHookService public EnableDraw(HookManager hooks, GameState state) { _state = state; - _task = hooks.CreateHook("Enable Draw", Sigs.EnableDraw, Detour, HookSettings.ObjectHooks); + _task = hooks.CreateHook("Enable Draw", Sigs.EnableDraw, Detour, !HookOverrides.Instance.Objects.EnableDraw); } private delegate void Delegate(GameObject* gameObject); diff --git a/Penumbra/Interop/Hooks/Objects/WeaponReload.cs b/Penumbra/Interop/Hooks/Objects/WeaponReload.cs index da31840f..b09103f6 100644 --- a/Penumbra/Interop/Hooks/Objects/WeaponReload.cs +++ b/Penumbra/Interop/Hooks/Objects/WeaponReload.cs @@ -16,7 +16,7 @@ public sealed unsafe class WeaponReload : EventWrapperPtr _task = hooks.CreateHook(Name, Address, Detour, HookSettings.ObjectHooks); + => _task = hooks.CreateHook(Name, Address, Detour, !HookOverrides.Instance.Objects.WeaponReload); private readonly Task> _task; diff --git a/Penumbra/Interop/Hooks/PostProcessing/PreBoneDeformerReplacer.cs b/Penumbra/Interop/Hooks/PostProcessing/PreBoneDeformerReplacer.cs index 834a7d28..1aa09d7f 100644 --- a/Penumbra/Interop/Hooks/PostProcessing/PreBoneDeformerReplacer.cs +++ b/Penumbra/Interop/Hooks/PostProcessing/PreBoneDeformerReplacer.cs @@ -38,9 +38,9 @@ public sealed unsafe class PreBoneDeformerReplacer : IDisposable, IRequiredServi _resourceLoader = resourceLoader; _framework = framework; _humanSetupScalingHook = hooks.CreateHook("HumanSetupScaling", vTables.HumanVTable[58], SetupScaling, - HookSettings.PostProcessingHooks).Result; + !HookOverrides.Instance.PostProcessing.HumanSetupScaling).Result; _humanCreateDeformerHook = hooks.CreateHook("HumanCreateDeformer", vTables.HumanVTable[101], - CreateDeformer, HookSettings.PostProcessingHooks).Result; + CreateDeformer, !HookOverrides.Instance.PostProcessing.HumanCreateDeformer).Result; } public void Dispose() diff --git a/Penumbra/Interop/Hooks/PostProcessing/ShaderReplacementFixer.cs b/Penumbra/Interop/Hooks/PostProcessing/ShaderReplacementFixer.cs index b87d33ef..53b69741 100644 --- a/Penumbra/Interop/Hooks/PostProcessing/ShaderReplacementFixer.cs +++ b/Penumbra/Interop/Hooks/PostProcessing/ShaderReplacementFixer.cs @@ -90,20 +90,26 @@ public sealed unsafe class ShaderReplacementFixer : IDisposable, IRequiredServic _modelRenderer = modelRenderer; _communicator = communicator; - _skinState = new( + _skinState = new ModdedShaderPackageState( () => (ShaderPackageResourceHandle**)&_utility.Address->SkinShpkResource, () => (ShaderPackageResourceHandle*)_utility.DefaultSkinShpkResource); - _irisState = new(() => _modelRenderer.IrisShaderPackage, () => _modelRenderer.DefaultIrisShaderPackage); - _characterGlassState = new(() => _modelRenderer.CharacterGlassShaderPackage, () => _modelRenderer.DefaultCharacterGlassShaderPackage); - _characterTransparencyState = new(() => _modelRenderer.CharacterTransparencyShaderPackage, () => _modelRenderer.DefaultCharacterTransparencyShaderPackage); - _characterTattooState = new(() => _modelRenderer.CharacterTattooShaderPackage, () => _modelRenderer.DefaultCharacterTattooShaderPackage); - _characterOcclusionState = new(() => _modelRenderer.CharacterOcclusionShaderPackage, () => _modelRenderer.DefaultCharacterOcclusionShaderPackage); - _hairMaskState = new(() => _modelRenderer.HairMaskShaderPackage, () => _modelRenderer.DefaultHairMaskShaderPackage); + _irisState = new ModdedShaderPackageState(() => _modelRenderer.IrisShaderPackage, () => _modelRenderer.DefaultIrisShaderPackage); + _characterGlassState = new ModdedShaderPackageState(() => _modelRenderer.CharacterGlassShaderPackage, + () => _modelRenderer.DefaultCharacterGlassShaderPackage); + _characterTransparencyState = new ModdedShaderPackageState(() => _modelRenderer.CharacterTransparencyShaderPackage, + () => _modelRenderer.DefaultCharacterTransparencyShaderPackage); + _characterTattooState = new ModdedShaderPackageState(() => _modelRenderer.CharacterTattooShaderPackage, + () => _modelRenderer.DefaultCharacterTattooShaderPackage); + _characterOcclusionState = new ModdedShaderPackageState(() => _modelRenderer.CharacterOcclusionShaderPackage, + () => _modelRenderer.DefaultCharacterOcclusionShaderPackage); + _hairMaskState = + new ModdedShaderPackageState(() => _modelRenderer.HairMaskShaderPackage, () => _modelRenderer.DefaultHairMaskShaderPackage); _humanOnRenderMaterialHook = hooks.CreateHook("Human.OnRenderMaterial", vTables.HumanVTable[64], - OnRenderHumanMaterial, HookSettings.PostProcessingHooks).Result; + OnRenderHumanMaterial, !HookOverrides.Instance.PostProcessing.HumanOnRenderMaterial).Result; _modelRendererOnRenderMaterialHook = hooks.CreateHook("ModelRenderer.OnRenderMaterial", - Sigs.ModelRendererOnRenderMaterial, ModelRendererOnRenderMaterialDetour, HookSettings.PostProcessingHooks).Result; + Sigs.ModelRendererOnRenderMaterial, ModelRendererOnRenderMaterialDetour, + !HookOverrides.Instance.PostProcessing.ModelRendererOnRenderMaterial).Result; _communicator.MtrlShpkLoaded.Subscribe(OnMtrlShpkLoaded, MtrlShpkLoaded.Priority.ShaderReplacementFixer); _resourceHandleDestructor.Subscribe(OnResourceHandleDestructor, ResourceHandleDestructor.Priority.ShaderReplacementFixer); } @@ -123,7 +129,8 @@ public sealed unsafe class ShaderReplacementFixer : IDisposable, IRequiredServic _skinState.ClearMaterials(); } - public (ulong Skin, ulong Iris, ulong CharacterGlass, ulong CharacterTransparency, ulong CharacterTattoo, ulong CharacterOcclusion, ulong HairMask) GetAndResetSlowPathCallDeltas() + public (ulong Skin, ulong Iris, ulong CharacterGlass, ulong CharacterTransparency, ulong CharacterTattoo, ulong CharacterOcclusion, ulong + HairMask) GetAndResetSlowPathCallDeltas() => (_skinState.GetAndResetSlowPathCallDelta(), _irisState.GetAndResetSlowPathCallDelta(), _characterGlassState.GetAndResetSlowPathCallDelta(), @@ -208,7 +215,12 @@ public sealed unsafe class ShaderReplacementFixer : IDisposable, IRequiredServic [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] private uint GetTotalMaterialCountForModelRenderer() - => _irisState.MaterialCount + _characterGlassState.MaterialCount + _characterTransparencyState.MaterialCount + _characterTattooState.MaterialCount + _characterOcclusionState.MaterialCount + _hairMaskState.MaterialCount; + => _irisState.MaterialCount + + _characterGlassState.MaterialCount + + _characterTransparencyState.MaterialCount + + _characterTattooState.MaterialCount + + _characterOcclusionState.MaterialCount + + _hairMaskState.MaterialCount; private nint OnRenderHumanMaterial(CharacterBase* human, CSModelRenderer.OnRenderMaterialParams* param) { diff --git a/Penumbra/Interop/Hooks/ResourceLoading/CreateFileWHook.cs b/Penumbra/Interop/Hooks/ResourceLoading/CreateFileWHook.cs index 8d0ac8cb..a9a5f41d 100644 --- a/Penumbra/Interop/Hooks/ResourceLoading/CreateFileWHook.cs +++ b/Penumbra/Interop/Hooks/ResourceLoading/CreateFileWHook.cs @@ -19,7 +19,7 @@ public unsafe class CreateFileWHook : IDisposable, IRequiredService public CreateFileWHook(IGameInteropProvider interop) { _createFileWHook = interop.HookFromImport(null, "KERNEL32.dll", "CreateFileW", 0, CreateFileWDetour); - if (HookSettings.ReplacementHooks) + if (!HookOverrides.Instance.ResourceLoading.CreateFileWHook) _createFileWHook.Enable(); } diff --git a/Penumbra/Interop/Hooks/ResourceLoading/FileReadService.cs b/Penumbra/Interop/Hooks/ResourceLoading/FileReadService.cs index 199525fb..d8801b81 100644 --- a/Penumbra/Interop/Hooks/ResourceLoading/FileReadService.cs +++ b/Penumbra/Interop/Hooks/ResourceLoading/FileReadService.cs @@ -15,7 +15,7 @@ public unsafe class FileReadService : IDisposable, IRequiredService _resourceManager = resourceManager; _performance = performance; interop.InitializeFromAttributes(this); - if (HookSettings.ReplacementHooks) + if (!HookOverrides.Instance.ResourceLoading.ReadSqPack) _readSqPackHook.Enable(); } diff --git a/Penumbra/Interop/Hooks/ResourceLoading/MappedCodeReader.cs b/Penumbra/Interop/Hooks/ResourceLoading/MappedCodeReader.cs index 81712cca..de0014d2 100644 --- a/Penumbra/Interop/Hooks/ResourceLoading/MappedCodeReader.cs +++ b/Penumbra/Interop/Hooks/ResourceLoading/MappedCodeReader.cs @@ -4,10 +4,11 @@ namespace Penumbra.Interop.Hooks.ResourceLoading; public class MappedCodeReader(UnmanagedMemoryAccessor data, long offset) : CodeReader { - public override int ReadByte() { - if (offset >= data.Capacity) - return -1; + public override int ReadByte() + { + if (offset >= data.Capacity) + return -1; - return data.ReadByte(offset++); - } + return data.ReadByte(offset++); + } } diff --git a/Penumbra/Interop/Hooks/ResourceLoading/PapHandler.cs b/Penumbra/Interop/Hooks/ResourceLoading/PapHandler.cs index ea12a480..5ba8c975 100644 --- a/Penumbra/Interop/Hooks/ResourceLoading/PapHandler.cs +++ b/Penumbra/Interop/Hooks/ResourceLoading/PapHandler.cs @@ -8,6 +8,9 @@ public sealed class PapHandler(PapRewriter.PapResourceHandlerPrototype papResour public void Enable() { + if (HookOverrides.Instance.ResourceLoading.PapHooks) + return; + ReadOnlySpan<(string Sig, string Name)> signatures = [ (Sigs.LoadAlwaysResidentMotionPacks, nameof(Sigs.LoadAlwaysResidentMotionPacks)), diff --git a/Penumbra/Interop/Hooks/ResourceLoading/PeSigScanner.cs b/Penumbra/Interop/Hooks/ResourceLoading/PeSigScanner.cs index f5dd2d45..4be0da00 100644 --- a/Penumbra/Interop/Hooks/ResourceLoading/PeSigScanner.cs +++ b/Penumbra/Interop/Hooks/ResourceLoading/PeSigScanner.cs @@ -14,7 +14,6 @@ public unsafe class PeSigScanner : IDisposable private readonly nint _moduleBaseAddress; private readonly uint _textSectionVirtualAddress; - public PeSigScanner() { var mainModule = Process.GetCurrentProcess().MainModule!; diff --git a/Penumbra/Interop/Hooks/ResourceLoading/ResourceService.cs b/Penumbra/Interop/Hooks/ResourceLoading/ResourceService.cs index 8b99dc37..f75b0623 100644 --- a/Penumbra/Interop/Hooks/ResourceLoading/ResourceService.cs +++ b/Penumbra/Interop/Hooks/ResourceLoading/ResourceService.cs @@ -30,13 +30,14 @@ public unsafe class ResourceService : IDisposable, IRequiredService _decRefHook = interop.HookFromAddress( (nint)CSResourceHandle.MemberFunctionPointers.DecRef, ResourceHandleDecRefDetour); - if (HookSettings.ReplacementHooks) - { + if (HookOverrides.Instance.ResourceLoading.GetResourceSync) _getResourceSyncHook.Enable(); + if (HookOverrides.Instance.ResourceLoading.GetResourceAsync) _getResourceAsyncHook.Enable(); + if (HookOverrides.Instance.ResourceLoading.IncRef) _incRefHook.Enable(); + if (HookOverrides.Instance.ResourceLoading.DecRef) _decRefHook.Enable(); - } } public ResourceHandle* GetResource(ResourceCategory category, ResourceType type, CiByteString path) diff --git a/Penumbra/Interop/Hooks/ResourceLoading/TexMdlService.cs b/Penumbra/Interop/Hooks/ResourceLoading/TexMdlService.cs index 80ba5cb9..fc3289bd 100644 --- a/Penumbra/Interop/Hooks/ResourceLoading/TexMdlService.cs +++ b/Penumbra/Interop/Hooks/ResourceLoading/TexMdlService.cs @@ -46,12 +46,12 @@ public unsafe class TexMdlService : IDisposable, IRequiredService { interop.InitializeFromAttributes(this); _lodService = new LodService(interop); - if (HookSettings.ReplacementHooks) - { + if (HookOverrides.Instance.ResourceLoading.CheckFileState) _checkFileStateHook.Enable(); + if (HookOverrides.Instance.ResourceLoading.LoadMdlFileExtern) _loadMdlFileExternHook.Enable(); + if (HookOverrides.Instance.ResourceLoading.TexResourceHandleOnLoad) _textureOnLoadHook.Enable(); - } } /// Add CRC64 if the given file is a model or texture file and has an associated path. diff --git a/Penumbra/Interop/Hooks/Resources/ApricotResourceLoad.cs b/Penumbra/Interop/Hooks/Resources/ApricotResourceLoad.cs index 511e842f..f6cccc19 100644 --- a/Penumbra/Interop/Hooks/Resources/ApricotResourceLoad.cs +++ b/Penumbra/Interop/Hooks/Resources/ApricotResourceLoad.cs @@ -11,7 +11,7 @@ public sealed unsafe class ApricotResourceLoad : FastHook("Load Apricot Resource", Sigs.ApricotResourceLoad, Detour, HookSettings.ResourceHooks); + Task = hooks.CreateHook("Load Apricot Resource", Sigs.ApricotResourceLoad, Detour, HookOverrides.Instance.Resources.ApricotResourceLoad); } public delegate byte Delegate(ResourceHandle* handle, nint unk1, byte unk2); diff --git a/Penumbra/Interop/Hooks/Resources/LoadMtrlShpk.cs b/Penumbra/Interop/Hooks/Resources/LoadMtrlShpk.cs index 8447762b..7aaa62d5 100644 --- a/Penumbra/Interop/Hooks/Resources/LoadMtrlShpk.cs +++ b/Penumbra/Interop/Hooks/Resources/LoadMtrlShpk.cs @@ -14,7 +14,7 @@ public sealed unsafe class LoadMtrlShpk : FastHook { _gameState = gameState; _communicator = communicator; - Task = hooks.CreateHook("Load Material Shaders", Sigs.LoadMtrlShpk, Detour, HookSettings.ResourceHooks); + Task = hooks.CreateHook("Load Material Shaders", Sigs.LoadMtrlShpk, Detour, HookOverrides.Instance.Resources.LoadMtrlShpk); } public delegate byte Delegate(MaterialResourceHandle* mtrlResourceHandle); diff --git a/Penumbra/Interop/Hooks/Resources/LoadMtrlTex.cs b/Penumbra/Interop/Hooks/Resources/LoadMtrlTex.cs index 7bc3c7b0..ed0e067b 100644 --- a/Penumbra/Interop/Hooks/Resources/LoadMtrlTex.cs +++ b/Penumbra/Interop/Hooks/Resources/LoadMtrlTex.cs @@ -11,7 +11,7 @@ public sealed unsafe class LoadMtrlTex : FastHook public LoadMtrlTex(HookManager hooks, GameState gameState) { _gameState = gameState; - Task = hooks.CreateHook("Load Material Textures", Sigs.LoadMtrlTex, Detour, HookSettings.ResourceHooks); + Task = hooks.CreateHook("Load Material Textures", Sigs.LoadMtrlTex, Detour, HookOverrides.Instance.Resources.LoadMtrlTex); } public delegate byte Delegate(MaterialResourceHandle* mtrlResourceHandle); diff --git a/Penumbra/Interop/Hooks/Resources/ResolvePathHooksBase.cs b/Penumbra/Interop/Hooks/Resources/ResolvePathHooksBase.cs index e1b6e46e..66945009 100644 --- a/Penumbra/Interop/Hooks/Resources/ResolvePathHooksBase.cs +++ b/Penumbra/Interop/Hooks/Resources/ResolvePathHooksBase.cs @@ -67,7 +67,7 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable // @formatter:on - if (HookSettings.ResourceHooks) + if (HookOverrides.Instance.Resources.ResolvePathHooks) Enable(); } diff --git a/Penumbra/Interop/Hooks/Resources/ResourceHandleDestructor.cs b/Penumbra/Interop/Hooks/Resources/ResourceHandleDestructor.cs index cd4a53c4..5c4b5c90 100644 --- a/Penumbra/Interop/Hooks/Resources/ResourceHandleDestructor.cs +++ b/Penumbra/Interop/Hooks/Resources/ResourceHandleDestructor.cs @@ -23,7 +23,8 @@ public sealed unsafe class ResourceHandleDestructor : EventWrapperPtr _task = hooks.CreateHook(Name, Sigs.ResourceHandleDestructor, Detour, HookSettings.ResourceHooks); + => _task = hooks.CreateHook(Name, Sigs.ResourceHandleDestructor, Detour, + HookOverrides.Instance.Resources.ResourceHandleDestructor); private readonly Task> _task; diff --git a/Penumbra/Penumbra.cs b/Penumbra/Penumbra.cs index 5f8d6805..8ea74987 100644 --- a/Penumbra/Penumbra.cs +++ b/Penumbra/Penumbra.cs @@ -21,6 +21,7 @@ using Penumbra.GameData.Enums; using Penumbra.UI; using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager; using System.Xml.Linq; +using Penumbra.Interop.Hooks; using Penumbra.Interop.Hooks.ResourceLoading; namespace Penumbra; @@ -52,9 +53,10 @@ public class Penumbra : IDalamudPlugin { try { - _services = StaticServiceManager.CreateProvider(this, pluginInterface, Log); - Messager = _services.GetService(); - _validityChecker = _services.GetService(); + HookOverrides.Instance = HookOverrides.LoadFile(pluginInterface); + _services = StaticServiceManager.CreateProvider(this, pluginInterface, Log); + Messager = _services.GetService(); + _validityChecker = _services.GetService(); _services.EnsureRequiredServices(); var startup = _services.GetService() @@ -215,6 +217,7 @@ public class Penumbra : IDalamudPlugin sb.Append($"> **`Auto-Deduplication: `** {_config.AutoDeduplicateOnImport}\n"); sb.Append($"> **`Auto-UI-Reduplication: `** {_config.AutoReduplicateUiOnImport}\n"); sb.Append($"> **`Debug Mode: `** {_config.DebugMode}\n"); + sb.Append($"> **`Hook Overrides: `** {HookOverrides.Instance.IsCustomLoaded}\n"); sb.Append( $"> **`Synchronous Load (Dalamud): `** {(_services.GetService().GetDalamudConfig(DalamudConfigService.WaitingForPluginsOption, out bool v) ? v.ToString() : "Unknown")}\n"); sb.Append( diff --git a/Penumbra/UI/Tabs/Debug/DebugTab.cs b/Penumbra/UI/Tabs/Debug/DebugTab.cs index a1e9da03..3a64e556 100644 --- a/Penumbra/UI/Tabs/Debug/DebugTab.cs +++ b/Penumbra/UI/Tabs/Debug/DebugTab.cs @@ -97,6 +97,7 @@ public class DebugTab : Window, ITab, IUiService private readonly IpcTester _ipcTester; private readonly CrashHandlerPanel _crashHandlerPanel; private readonly TexHeaderDrawer _texHeaderDrawer; + private readonly HookOverrideDrawer _hookOverrides; public DebugTab(PerformanceTracker performance, Configuration config, CollectionManager collectionManager, ObjectManager objects, IClientState clientState, @@ -106,7 +107,8 @@ public class DebugTab : Window, ITab, IUiService DrawObjectState drawObjectState, PathState pathState, SubfileHelper subfileHelper, IdentifiedCollectionCache identifiedCollectionCache, CutsceneService cutsceneService, ModImportManager modImporter, ImportPopup importPopup, FrameworkManager framework, TextureManager textureManager, ShaderReplacementFixer shaderReplacementFixer, RedrawService redraws, DictEmote emotes, - Diagnostics diagnostics, IpcTester ipcTester, CrashHandlerPanel crashHandlerPanel, TexHeaderDrawer texHeaderDrawer) + Diagnostics diagnostics, IpcTester ipcTester, CrashHandlerPanel crashHandlerPanel, TexHeaderDrawer texHeaderDrawer, + HookOverrideDrawer hookOverrides) : base("Penumbra Debug Window", ImGuiWindowFlags.NoCollapse) { IsOpen = true; @@ -143,6 +145,7 @@ public class DebugTab : Window, ITab, IUiService _ipcTester = ipcTester; _crashHandlerPanel = crashHandlerPanel; _texHeaderDrawer = texHeaderDrawer; + _hookOverrides = hookOverrides; _objects = objects; _clientState = clientState; } @@ -166,34 +169,21 @@ public class DebugTab : Window, ITab, IUiService return; DrawDebugTabGeneral(); - ImGui.NewLine(); _crashHandlerPanel.Draw(); - ImGui.NewLine(); _diagnostics.DrawDiagnostics(); DrawPerformanceTab(); - ImGui.NewLine(); DrawPathResolverDebug(); - ImGui.NewLine(); DrawActorsDebug(); - ImGui.NewLine(); DrawCollectionCaches(); - ImGui.NewLine(); _texHeaderDrawer.Draw(); - ImGui.NewLine(); DrawDebugCharacterUtility(); - ImGui.NewLine(); DrawShaderReplacementFixer(); - ImGui.NewLine(); DrawData(); - ImGui.NewLine(); DrawResourceProblems(); - ImGui.NewLine(); + _hookOverrides.Draw(); DrawPlayerModelInfo(); - ImGui.NewLine(); DrawGlobalVariableInfo(); - ImGui.NewLine(); DrawDebugTabIpc(); - ImGui.NewLine(); } @@ -434,7 +424,6 @@ public class DebugTab : Window, ITab, IUiService private void DrawPerformanceTab() { - ImGui.NewLine(); if (!ImGui.CollapsingHeader("Performance")) return; diff --git a/Penumbra/UI/Tabs/Debug/HookOverrideDrawer.cs b/Penumbra/UI/Tabs/Debug/HookOverrideDrawer.cs new file mode 100644 index 00000000..7af1f884 --- /dev/null +++ b/Penumbra/UI/Tabs/Debug/HookOverrideDrawer.cs @@ -0,0 +1,63 @@ +using Dalamud.Plugin; +using ImGuiNET; +using OtterGui.Services; +using OtterGui.Text; +using Penumbra.Interop.Hooks; + +namespace Penumbra.UI.Tabs.Debug; + +public class HookOverrideDrawer(IDalamudPluginInterface pluginInterface) : IUiService +{ + private HookOverrides? _overrides; + + public void Draw() + { + using var header = ImUtf8.CollapsingHeaderId("Generate Hook Override"u8); + if (!header) + return; + + _overrides ??= HookOverrides.Instance.Clone(); + + if (ImUtf8.Button("Save"u8)) + _overrides.Write(pluginInterface); + + ImGui.SameLine(); + var path = Path.Combine(pluginInterface.GetPluginConfigDirectory(), HookOverrides.FileName); + var exists = File.Exists(path); + if (ImUtf8.ButtonEx("Delete"u8, disabled: !exists, tooltip: exists ? ""u8 : "File does not exist."u8)) + try + { + File.Delete(path); + } + catch (Exception ex) + { + Penumbra.Log.Error($"Could not delete hook override file at {path}:\n{ex}"); + } + + bool? all = null; + ImGui.SameLine(); + if (ImUtf8.Button("Disable All Hooks"u8)) + all = true; + ImGui.SameLine(); + if (ImUtf8.Button("Enable All Hooks"u8)) + all = false; + + foreach (var propertyField in typeof(HookOverrides).GetFields().Where(f => f is { IsStatic: false, FieldType.IsValueType: true })) + { + using var tree = ImUtf8.TreeNode(propertyField.Name); + if (!tree) + continue; + + var property = propertyField.GetValue(_overrides); + foreach (var valueField in propertyField.FieldType.GetFields()) + { + var value = valueField.GetValue(property) as bool? ?? false; + if (ImUtf8.Checkbox($"Disable {valueField.Name}", ref value) || all.HasValue) + { + valueField.SetValue(property, all ?? value); + propertyField.SetValue(_overrides, property); + } + } + } + } +}