Allow hook overrides.

This commit is contained in:
Ottermandias 2024-08-01 16:40:37 +02:00
parent 9e15865a99
commit a308fb9f77
52 changed files with 326 additions and 108 deletions

View file

@ -24,7 +24,7 @@ public sealed unsafe class ApricotListenerSoundPlayCaller : FastHook<ApricotList
_collectionResolver = collectionResolver;
_crashHandler = crashHandler;
Task = hooks.CreateHook<Delegate>("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);

View file

@ -26,7 +26,8 @@ public sealed unsafe class CharacterBaseLoadAnimation : FastHook<CharacterBaseLo
_collectionResolver = collectionResolver;
_drawObjectState = drawObjectState;
_crashHandler = crashHandler;
Task = hooks.CreateHook<Delegate>("CharacterBase Load Animation", Sigs.CharacterBaseLoadAnimation, Detour, HookSettings.VfxIdentificationHooks);
Task = hooks.CreateHook<Delegate>("CharacterBase Load Animation", Sigs.CharacterBaseLoadAnimation, Detour,
!HookOverrides.Instance.Animation.CharacterBaseLoadAnimation);
}
public delegate void Delegate(DrawObject* drawBase);

View file

@ -16,7 +16,7 @@ public sealed unsafe class Dismount : FastHook<Dismount.Delegate>
{
_state = state;
_collectionResolver = collectionResolver;
Task = hooks.CreateHook<Delegate>("Dismount", Sigs.Dismount, Detour, HookSettings.VfxIdentificationHooks);
Task = hooks.CreateHook<Delegate>("Dismount", Sigs.Dismount, Detour, !HookOverrides.Instance.Animation.Dismount);
}
public delegate void Delegate(MountContainer* a1, nint a2);

View file

@ -17,10 +17,10 @@ public sealed unsafe class LoadAreaVfx : FastHook<LoadAreaVfx.Delegate>
public LoadAreaVfx(HookManager hooks, GameState state, CollectionResolver collectionResolver, CrashHandlerService crashHandler)
{
_state = state;
_state = state;
_collectionResolver = collectionResolver;
_crashHandler = crashHandler;
Task = hooks.CreateHook<Delegate>("Load Area VFX", Sigs.LoadAreaVfx, Detour, HookSettings.VfxIdentificationHooks);
_crashHandler = crashHandler;
Task = hooks.CreateHook<Delegate>("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);

View file

@ -20,7 +20,7 @@ public sealed unsafe class LoadCharacterSound : FastHook<LoadCharacterSound.Dele
_collectionResolver = collectionResolver;
_crashHandler = crashHandler;
Task = hooks.CreateHook<Delegate>("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);

View file

@ -26,7 +26,7 @@ public sealed unsafe class LoadCharacterVfx : FastHook<LoadCharacterVfx.Delegate
_collectionResolver = collectionResolver;
_objects = objects;
_crashHandler = crashHandler;
Task = hooks.CreateHook<Delegate>("Load Character VFX", Sigs.LoadCharacterVfx, Detour, HookSettings.VfxIdentificationHooks);
Task = hooks.CreateHook<Delegate>("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);

View file

@ -31,7 +31,7 @@ public sealed unsafe class LoadTimelineResources : FastHook<LoadTimelineResource
_conditions = conditions;
_objects = objects;
_crashHandler = crashHandler;
Task = hooks.CreateHook<Delegate>("Load Timeline Resources", Sigs.LoadTimelineResources, Detour, HookSettings.VfxIdentificationHooks);
Task = hooks.CreateHook<Delegate>("Load Timeline Resources", Sigs.LoadTimelineResources, Detour, !HookOverrides.Instance.Animation.LoadTimelineResources);
}
public delegate ulong Delegate(SchedulerTimeline* timeline);

View file

@ -14,7 +14,7 @@ public sealed unsafe class PlayFootstep : FastHook<PlayFootstep.Delegate>
{
_state = state;
_collectionResolver = collectionResolver;
Task = hooks.CreateHook<Delegate>("Play Footstep", Sigs.FootStepSound, Detour, HookSettings.VfxIdentificationHooks);
Task = hooks.CreateHook<Delegate>("Play Footstep", Sigs.FootStepSound, Detour, !HookOverrides.Instance.Animation.PlayFootstep);
}
public delegate void Delegate(GameObject* gameObject, int id, int unk);

View file

@ -23,7 +23,7 @@ public sealed unsafe class ScheduleClipUpdate : FastHook<ScheduleClipUpdate.Dele
_collectionResolver = collectionResolver;
_objects = objects;
_crashHandler = crashHandler;
Task = hooks.CreateHook<Delegate>("Schedule Clip Update", Sigs.ScheduleClipUpdate, Detour, HookSettings.VfxIdentificationHooks);
Task = hooks.CreateHook<Delegate>("Schedule Clip Update", Sigs.ScheduleClipUpdate, Detour, !HookOverrides.Instance.Animation.ScheduleClipUpdate);
}
public delegate void Delegate(ClipScheduler* x);

View file

@ -20,7 +20,7 @@ public sealed unsafe class SomeActionLoad : FastHook<SomeActionLoad.Delegate>
_state = state;
_collectionResolver = collectionResolver;
_crashHandler = crashHandler;
Task = hooks.CreateHook<Delegate>("Some Action Load", Sigs.LoadSomeAction, Detour, HookSettings.VfxIdentificationHooks);
Task = hooks.CreateHook<Delegate>("Some Action Load", Sigs.LoadSomeAction, Detour, !HookOverrides.Instance.Animation.SomeActionLoad);
}
public delegate void Delegate(TimelineContainer* timelineManager);

View file

@ -15,7 +15,7 @@ public sealed unsafe class SomeMountAnimation : FastHook<SomeMountAnimation.Dele
{
_state = state;
_collectionResolver = collectionResolver;
Task = hooks.CreateHook<Delegate>("Some Mount Animation", Sigs.UnkMountAnimation, Detour, HookSettings.VfxIdentificationHooks);
Task = hooks.CreateHook<Delegate>("Some Mount Animation", Sigs.UnkMountAnimation, Detour, !HookOverrides.Instance.Animation.SomeMountAnimation);
}
public delegate void Delegate(DrawObject* drawObject, uint unk1, byte unk2, uint unk3);

View file

@ -22,7 +22,7 @@ public sealed unsafe class SomePapLoad : FastHook<SomePapLoad.Delegate>
_collectionResolver = collectionResolver;
_objects = objects;
_crashHandler = crashHandler;
Task = hooks.CreateHook<Delegate>("Some PAP Load", Sigs.LoadSomePap, Detour, HookSettings.VfxIdentificationHooks);
Task = hooks.CreateHook<Delegate>("Some PAP Load", Sigs.LoadSomePap, Detour, !HookOverrides.Instance.Animation.SomePapLoad);
}
public delegate void Delegate(nint a1, int a2, nint a3, int a4);

View file

@ -15,7 +15,7 @@ public sealed unsafe class SomeParasolAnimation : FastHook<SomeParasolAnimation.
{
_state = state;
_collectionResolver = collectionResolver;
Task = hooks.CreateHook<Delegate>("Some Parasol Animation", Sigs.UnkParasolAnimation, Detour, HookSettings.VfxIdentificationHooks);
Task = hooks.CreateHook<Delegate>("Some Parasol Animation", Sigs.UnkParasolAnimation, Detour, !HookOverrides.Instance.Animation.SomeParasolAnimation);
}
public delegate void Delegate(DrawObject* drawObject, int unk1);

View file

@ -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<HookOverrides>(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}");
}
}
}

View file

@ -14,7 +14,7 @@ public sealed unsafe class CalculateHeight : FastHook<CalculateHeight.Delegate>
{
_collectionResolver = collectionResolver;
_metaState = metaState;
Task = hooks.CreateHook<Delegate>("Calculate Height", (nint)Character.MemberFunctionPointers.CalculateHeight, Detour, HookSettings.MetaParentHooks);
Task = hooks.CreateHook<Delegate>("Calculate Height", (nint)Character.MemberFunctionPointers.CalculateHeight, Detour, !HookOverrides.Instance.Meta.CalculateHeight);
}
public delegate ulong Delegate(Character* character);

View file

@ -16,7 +16,7 @@ public sealed unsafe class ChangeCustomize : FastHook<ChangeCustomize.Delegate>
{
_collectionResolver = collectionResolver;
_metaState = metaState;
Task = hooks.CreateHook<Delegate>("Change Customize", Sigs.ChangeCustomize, Detour, HookSettings.MetaParentHooks);
Task = hooks.CreateHook<Delegate>("Change Customize", Sigs.ChangeCustomize, Detour, !HookOverrides.Instance.Meta.ChangeCustomize);
}
public delegate bool Delegate(Human* human, CustomizeArray* data, byte skipEquipment);

View file

@ -16,8 +16,10 @@ public unsafe class EqdpAccessoryHook : FastHook<EqdpAccessoryHook.Delegate>, ID
public EqdpAccessoryHook(HookManager hooks, MetaState metaState)
{
_metaState = metaState;
Task = hooks.CreateHook<Delegate>("GetEqdpAccessoryEntry", Sigs.GetEqdpAccessoryEntry, Detour, metaState.Config.EnableMods && HookSettings.MetaEntryHooks);
_metaState.Config.ModsEnabled += Toggle;
Task = hooks.CreateHook<Delegate>("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)

View file

@ -16,8 +16,9 @@ public unsafe class EqdpEquipHook : FastHook<EqdpEquipHook.Delegate>, IDisposabl
public EqdpEquipHook(HookManager hooks, MetaState metaState)
{
_metaState = metaState;
Task = hooks.CreateHook<Delegate>("GetEqdpEquipEntry", Sigs.GetEqdpEquipEntry, Detour, metaState.Config.EnableMods && HookSettings.MetaEntryHooks);
_metaState.Config.ModsEnabled += Toggle;
Task = hooks.CreateHook<Delegate>("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)

View file

@ -15,8 +15,10 @@ public unsafe class EqpHook : FastHook<EqpHook.Delegate>, IDisposable
public EqpHook(HookManager hooks, MetaState metaState)
{
_metaState = metaState;
Task = hooks.CreateHook<Delegate>("GetEqpFlags", Sigs.GetEqpEntry, Detour, metaState.Config.EnableMods && HookSettings.MetaEntryHooks);
_metaState.Config.ModsEnabled += Toggle;
Task = hooks.CreateHook<Delegate>("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)

View file

@ -21,8 +21,9 @@ public unsafe class EstHook : FastHook<EstHook.Delegate>, IDisposable
_metaState = metaState;
_characterUtility = characterUtility;
Task = hooks.CreateHook<Delegate>("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)

View file

@ -17,8 +17,10 @@ public unsafe class GmpHook : FastHook<GmpHook.Delegate>, IDisposable
public GmpHook(HookManager hooks, MetaState metaState)
{
_metaState = metaState;
Task = hooks.CreateHook<Delegate>("GetGmpEntry", Sigs.GetGmpEntry, Detour, metaState.Config.EnableMods && HookSettings.MetaEntryHooks);
_metaState.Config.ModsEnabled += Toggle;
Task = hooks.CreateHook<Delegate>("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)

View file

@ -13,7 +13,7 @@ public sealed unsafe class ModelLoadComplete : FastHook<ModelLoadComplete.Delega
{
_collectionResolver = collectionResolver;
_metaState = metaState;
Task = hooks.CreateHook<Delegate>("Model Load Complete", vtables.HumanVTable[59], Detour, HookSettings.MetaParentHooks);
Task = hooks.CreateHook<Delegate>("Model Load Complete", vtables.HumanVTable[59], Detour, !HookOverrides.Instance.Meta.ModelLoadComplete);
}
public delegate void Delegate(DrawObject* drawObject);

View file

@ -19,8 +19,10 @@ public unsafe class RspBustHook : FastHook<RspBustHook.Delegate>, IDisposable
{
_metaState = metaState;
_metaFileManager = metaFileManager;
Task = hooks.CreateHook<Delegate>("GetRspBust", Sigs.GetRspBust, Detour, metaState.Config.EnableMods && HookSettings.MetaEntryHooks);
_metaState.Config.ModsEnabled += Toggle;
Task = hooks.CreateHook<Delegate>("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<RspBustHook.Delegate>, 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);

View file

@ -17,10 +17,12 @@ public class RspHeightHook : FastHook<RspHeightHook.Delegate>, IDisposable
public RspHeightHook(HookManager hooks, MetaState metaState, MetaFileManager metaFileManager)
{
_metaState = metaState;
_metaState = metaState;
_metaFileManager = metaFileManager;
Task = hooks.CreateHook<Delegate>("GetRspHeight", Sigs.GetRspHeight, Detour, metaState.Config.EnableMods && HookSettings.MetaEntryHooks);
_metaState.Config.ModsEnabled += Toggle;
Task = hooks.CreateHook<Delegate>("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<RspHeightHook.Delegate>, IDisposable
// Special cases.
if (height == 0xFF)
return 1.0f;
if (height > 100)
height = 0;

View file

@ -15,7 +15,7 @@ public sealed unsafe class RspSetupCharacter : FastHook<RspSetupCharacter.Delega
{
_collectionResolver = collectionResolver;
_metaState = metaState;
Task = hooks.CreateHook<Delegate>("RSP Setup Character", Sigs.RspSetupCharacter, Detour, HookSettings.MetaParentHooks);
Task = hooks.CreateHook<Delegate>("RSP Setup Character", Sigs.RspSetupCharacter, Detour, !HookOverrides.Instance.Meta.RspSetupCharacter);
}
public delegate void Delegate(DrawObject* drawObject, nint unk2, float unk3, nint unk4, byte unk5);

View file

@ -19,14 +19,18 @@ public class RspTailHook : FastHook<RspTailHook.Delegate>, IDisposable
{
_metaState = metaState;
_metaFileManager = metaFileManager;
Task = hooks.CreateHook<Delegate>("GetRspTail", Sigs.GetRspTail, Detour, metaState.Config.EnableMods && HookSettings.MetaEntryHooks);
_metaState.Config.ModsEnabled += Toggle;
Task = hooks.CreateHook<Delegate>("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

View file

@ -19,7 +19,7 @@ public sealed unsafe class SetupVisor : FastHook<SetupVisor.Delegate>
{
_collectionResolver = collectionResolver;
_metaState = metaState;
Task = hooks.CreateHook<Delegate>("Setup Visor", Sigs.SetupVisor, Detour, HookSettings.MetaParentHooks);
Task = hooks.CreateHook<Delegate>("Setup Visor", Sigs.SetupVisor, Detour, !HookOverrides.Instance.Meta.SetupVisor);
}
public delegate byte Delegate(DrawObject* drawObject, ushort modelId, byte visorState);

View file

@ -15,7 +15,7 @@ public sealed unsafe class UpdateModel : FastHook<UpdateModel.Delegate>
{
_collectionResolver = collectionResolver;
_metaState = metaState;
Task = hooks.CreateHook<Delegate>("Update Model", Sigs.UpdateModel, Detour, HookSettings.MetaParentHooks);
Task = hooks.CreateHook<Delegate>("Update Model", Sigs.UpdateModel, Detour, !HookOverrides.Instance.Meta.UpdateModel);
}
public delegate void Delegate(DrawObject* drawObject);

View file

@ -13,8 +13,8 @@ public sealed unsafe class UpdateRender : FastHook<UpdateRender.Delegate>
public UpdateRender(HookManager hooks, CollectionResolver collectionResolver, MetaState metaState, CharacterBaseVTables vTables)
{
_collectionResolver = collectionResolver;
_metaState = metaState;
Task = hooks.CreateHook<Delegate>("Human.UpdateRender", vTables.HumanVTable[4], Detour, HookSettings.MetaParentHooks);
_metaState = metaState;
Task = hooks.CreateHook<Delegate>("Human.UpdateRender", vTables.HumanVTable[4], Detour, !HookOverrides.Instance.Meta.UpdateRender);
}
public delegate void Delegate(DrawObject* drawObject);

View file

@ -19,7 +19,7 @@ public sealed unsafe class CharacterBaseDestructor : EventWrapperPtr<CharacterBa
public CharacterBaseDestructor(HookManager hooks)
: base("Destroy CharacterBase")
=> _task = hooks.CreateHook<Delegate>(Name, Address, Detour, HookSettings.ObjectHooks);
=> _task = hooks.CreateHook<Delegate>(Name, Address, Detour, !HookOverrides.Instance.Objects.CharacterBaseDestructor);
private readonly Task<Hook<Delegate>> _task;

View file

@ -19,7 +19,7 @@ public sealed unsafe class CharacterDestructor : EventWrapperPtr<Character, Char
public CharacterDestructor(HookManager hooks)
: base("Character Destructor")
=> _task = hooks.CreateHook<Delegate>(Name, Sigs.CharacterDestructor, Detour, HookSettings.ObjectHooks);
=> _task = hooks.CreateHook<Delegate>(Name, Sigs.CharacterDestructor, Detour, !HookOverrides.Instance.Objects.CharacterDestructor);
private readonly Task<Hook<Delegate>> _task;

View file

@ -15,7 +15,7 @@ public sealed unsafe class CopyCharacter : EventWrapperPtr<Character, Character,
public CopyCharacter(HookManager hooks)
: base("Copy Character")
=> _task = hooks.CreateHook<Delegate>(Name, Address, Detour, HookSettings.ObjectHooks);
=> _task = hooks.CreateHook<Delegate>(Name, Address, Detour, !HookOverrides.Instance.Objects.CopyCharacter);
private readonly Task<Hook<Delegate>> _task;

View file

@ -16,7 +16,7 @@ public sealed unsafe class CreateCharacterBase : EventWrapperPtr<ModelCharaId, C
public CreateCharacterBase(HookManager hooks)
: base("Create CharacterBase")
=> _task = hooks.CreateHook<Delegate>(Name, Address, Detour, HookSettings.ObjectHooks);
=> _task = hooks.CreateHook<Delegate>(Name, Address, Detour, !HookOverrides.Instance.Objects.CreateCharacterBase);
private readonly Task<Hook<Delegate>> _task;

View file

@ -17,7 +17,7 @@ public sealed unsafe class EnableDraw : IHookService
public EnableDraw(HookManager hooks, GameState state)
{
_state = state;
_task = hooks.CreateHook<Delegate>("Enable Draw", Sigs.EnableDraw, Detour, HookSettings.ObjectHooks);
_task = hooks.CreateHook<Delegate>("Enable Draw", Sigs.EnableDraw, Detour, !HookOverrides.Instance.Objects.EnableDraw);
}
private delegate void Delegate(GameObject* gameObject);

View file

@ -16,7 +16,7 @@ public sealed unsafe class WeaponReload : EventWrapperPtr<DrawDataContainer, Cha
public WeaponReload(HookManager hooks)
: base("Reload Weapon")
=> _task = hooks.CreateHook<Delegate>(Name, Address, Detour, HookSettings.ObjectHooks);
=> _task = hooks.CreateHook<Delegate>(Name, Address, Detour, !HookOverrides.Instance.Objects.WeaponReload);
private readonly Task<Hook<Delegate>> _task;

View file

@ -38,9 +38,9 @@ public sealed unsafe class PreBoneDeformerReplacer : IDisposable, IRequiredServi
_resourceLoader = resourceLoader;
_framework = framework;
_humanSetupScalingHook = hooks.CreateHook<CharacterBaseSetupScalingDelegate>("HumanSetupScaling", vTables.HumanVTable[58], SetupScaling,
HookSettings.PostProcessingHooks).Result;
!HookOverrides.Instance.PostProcessing.HumanSetupScaling).Result;
_humanCreateDeformerHook = hooks.CreateHook<CharacterBaseCreateDeformerDelegate>("HumanCreateDeformer", vTables.HumanVTable[101],
CreateDeformer, HookSettings.PostProcessingHooks).Result;
CreateDeformer, !HookOverrides.Instance.PostProcessing.HumanCreateDeformer).Result;
}
public void Dispose()

View file

@ -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<CharacterBaseOnRenderMaterialDelegate>("Human.OnRenderMaterial", vTables.HumanVTable[64],
OnRenderHumanMaterial, HookSettings.PostProcessingHooks).Result;
OnRenderHumanMaterial, !HookOverrides.Instance.PostProcessing.HumanOnRenderMaterial).Result;
_modelRendererOnRenderMaterialHook = hooks.CreateHook<ModelRendererOnRenderMaterialDelegate>("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)
{

View file

@ -19,7 +19,7 @@ public unsafe class CreateFileWHook : IDisposable, IRequiredService
public CreateFileWHook(IGameInteropProvider interop)
{
_createFileWHook = interop.HookFromImport<CreateFileWDelegate>(null, "KERNEL32.dll", "CreateFileW", 0, CreateFileWDetour);
if (HookSettings.ReplacementHooks)
if (!HookOverrides.Instance.ResourceLoading.CreateFileWHook)
_createFileWHook.Enable();
}

View file

@ -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();
}

View file

@ -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++);
}
}

View file

@ -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)),

View file

@ -14,7 +14,6 @@ public unsafe class PeSigScanner : IDisposable
private readonly nint _moduleBaseAddress;
private readonly uint _textSectionVirtualAddress;
public PeSigScanner()
{
var mainModule = Process.GetCurrentProcess().MainModule!;

View file

@ -30,13 +30,14 @@ public unsafe class ResourceService : IDisposable, IRequiredService
_decRefHook = interop.HookFromAddress<ResourceHandleDecRefPrototype>(
(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)

View file

@ -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();
}
}
/// <summary> Add CRC64 if the given file is a model or texture file and has an associated path. </summary>

View file

@ -11,7 +11,7 @@ public sealed unsafe class ApricotResourceLoad : FastHook<ApricotResourceLoad.De
public ApricotResourceLoad(HookManager hooks, GameState gameState)
{
_gameState = gameState;
Task = hooks.CreateHook<Delegate>("Load Apricot Resource", Sigs.ApricotResourceLoad, Detour, HookSettings.ResourceHooks);
Task = hooks.CreateHook<Delegate>("Load Apricot Resource", Sigs.ApricotResourceLoad, Detour, HookOverrides.Instance.Resources.ApricotResourceLoad);
}
public delegate byte Delegate(ResourceHandle* handle, nint unk1, byte unk2);

View file

@ -14,7 +14,7 @@ public sealed unsafe class LoadMtrlShpk : FastHook<LoadMtrlShpk.Delegate>
{
_gameState = gameState;
_communicator = communicator;
Task = hooks.CreateHook<Delegate>("Load Material Shaders", Sigs.LoadMtrlShpk, Detour, HookSettings.ResourceHooks);
Task = hooks.CreateHook<Delegate>("Load Material Shaders", Sigs.LoadMtrlShpk, Detour, HookOverrides.Instance.Resources.LoadMtrlShpk);
}
public delegate byte Delegate(MaterialResourceHandle* mtrlResourceHandle);

View file

@ -11,7 +11,7 @@ public sealed unsafe class LoadMtrlTex : FastHook<LoadMtrlTex.Delegate>
public LoadMtrlTex(HookManager hooks, GameState gameState)
{
_gameState = gameState;
Task = hooks.CreateHook<Delegate>("Load Material Textures", Sigs.LoadMtrlTex, Detour, HookSettings.ResourceHooks);
Task = hooks.CreateHook<Delegate>("Load Material Textures", Sigs.LoadMtrlTex, Detour, HookOverrides.Instance.Resources.LoadMtrlTex);
}
public delegate byte Delegate(MaterialResourceHandle* mtrlResourceHandle);

View file

@ -67,7 +67,7 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable
// @formatter:on
if (HookSettings.ResourceHooks)
if (HookOverrides.Instance.Resources.ResolvePathHooks)
Enable();
}

View file

@ -23,7 +23,8 @@ public sealed unsafe class ResourceHandleDestructor : EventWrapperPtr<ResourceHa
public ResourceHandleDestructor(HookManager hooks)
: base("Destroy ResourceHandle")
=> _task = hooks.CreateHook<Delegate>(Name, Sigs.ResourceHandleDestructor, Detour, HookSettings.ResourceHooks);
=> _task = hooks.CreateHook<Delegate>(Name, Sigs.ResourceHandleDestructor, Detour,
HookOverrides.Instance.Resources.ResourceHandleDestructor);
private readonly Task<Hook<Delegate>> _task;

View file

@ -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<MessageService>();
_validityChecker = _services.GetService<ValidityChecker>();
HookOverrides.Instance = HookOverrides.LoadFile(pluginInterface);
_services = StaticServiceManager.CreateProvider(this, pluginInterface, Log);
Messager = _services.GetService<MessageService>();
_validityChecker = _services.GetService<ValidityChecker>();
_services.EnsureRequiredServices();
var startup = _services.GetService<DalamudConfigService>()
@ -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<DalamudConfigService>().GetDalamudConfig(DalamudConfigService.WaitingForPluginsOption, out bool v) ? v.ToString() : "Unknown")}\n");
sb.Append(

View file

@ -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;

View file

@ -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);
}
}
}
}
}