Add new parameter to LoadWeapon hook.

This commit is contained in:
Ottermandias 2025-08-12 14:46:56 +02:00
parent 65f789880d
commit c9b291c2f3

View file

@ -13,7 +13,7 @@ public unsafe class WeaponService : IDisposable
private readonly WeaponLoading _event; private readonly WeaponLoading _event;
private readonly ThreadLocal<bool> _inUpdate = new(() => false); private readonly ThreadLocal<bool> _inUpdate = new(() => false);
private readonly delegate* unmanaged[Stdcall]<DrawDataContainer*, uint, ulong, byte, byte, byte, byte, void> private readonly delegate* unmanaged[Stdcall]<DrawDataContainer*, uint, ulong, byte, byte, byte, byte, int, void>
_original; _original;
public WeaponService(WeaponLoading @event, IGameInteropProvider interop) public WeaponService(WeaponLoading @event, IGameInteropProvider interop)
@ -22,7 +22,7 @@ public unsafe class WeaponService : IDisposable
_loadWeaponHook = _loadWeaponHook =
interop.HookFromAddress<LoadWeaponDelegate>((nint)DrawDataContainer.MemberFunctionPointers.LoadWeapon, LoadWeaponDetour); interop.HookFromAddress<LoadWeaponDelegate>((nint)DrawDataContainer.MemberFunctionPointers.LoadWeapon, LoadWeaponDetour);
_original = _original =
(delegate* unmanaged[Stdcall] < DrawDataContainer*, uint, ulong, byte, byte, byte, byte, void >) (delegate* unmanaged[Stdcall] < DrawDataContainer*, uint, ulong, byte, byte, byte, byte, int, void >)
DrawDataContainer.MemberFunctionPointers.LoadWeapon; DrawDataContainer.MemberFunctionPointers.LoadWeapon;
_loadWeaponHook.Enable(); _loadWeaponHook.Enable();
} }
@ -36,13 +36,14 @@ public unsafe class WeaponService : IDisposable
// redrawOnEquality controls whether the game does anything if the new weapon is identical to the old one. // redrawOnEquality controls whether the game does anything if the new weapon is identical to the old one.
// skipGameObject seems to control whether the new weapons are written to the game object or just influence the draw object. (1 = skip, 0 = change) // skipGameObject seems to control whether the new weapons are written to the game object or just influence the draw object. (1 = skip, 0 = change)
// unk4 seemed to be the same as unk1. // unk4 seemed to be the same as unk1.
// unk5 is new in 7.30 and is checked at the beginning of the function to call some timeline related function.
private delegate void LoadWeaponDelegate(DrawDataContainer* drawData, uint slot, ulong weapon, byte redrawOnEquality, byte unk2, private delegate void LoadWeaponDelegate(DrawDataContainer* drawData, uint slot, ulong weapon, byte redrawOnEquality, byte unk2,
byte skipGameObject, byte unk4); byte skipGameObject, byte unk4, byte unk5);
private readonly Hook<LoadWeaponDelegate> _loadWeaponHook; private readonly Hook<LoadWeaponDelegate> _loadWeaponHook;
private void LoadWeaponDetour(DrawDataContainer* drawData, uint slot, ulong weaponValue, byte redrawOnEquality, byte unk2, private void LoadWeaponDetour(DrawDataContainer* drawData, uint slot, ulong weaponValue, byte redrawOnEquality, byte unk2,
byte skipGameObject, byte unk4) byte skipGameObject, byte unk4, byte unk5)
{ {
if (!_inUpdate.Value) if (!_inUpdate.Value)
{ {
@ -64,21 +65,21 @@ public unsafe class WeaponService : IDisposable
else if (weaponValue == actor.GetMainhand().Value && weaponValue != 0) else if (weaponValue == actor.GetMainhand().Value && weaponValue != 0)
_event.Invoke(actor, EquipSlot.MainHand, ref tmpWeapon); _event.Invoke(actor, EquipSlot.MainHand, ref tmpWeapon);
_loadWeaponHook.Original(drawData, slot, weapon.Value, redrawOnEquality, unk2, skipGameObject, unk4); _loadWeaponHook.Original(drawData, slot, weapon.Value, redrawOnEquality, unk2, skipGameObject, unk4, unk5);
if (tmpWeapon.Value != weapon.Value) if (tmpWeapon.Value != weapon.Value)
{ {
if (tmpWeapon.Skeleton.Id == 0) if (tmpWeapon.Skeleton.Id == 0)
tmpWeapon.Stains = StainIds.None; tmpWeapon.Stains = StainIds.None;
_loadWeaponHook.Original(drawData, slot, tmpWeapon.Value, 1, unk2, 1, unk4); _loadWeaponHook.Original(drawData, slot, tmpWeapon.Value, 1, unk2, 1, unk4, unk5);
} }
Glamourer.Log.Excessive( Glamourer.Log.Excessive(
$"Weapon reloaded for 0x{actor.Address:X} ({actor.Utf8Name}) with attributes {slot} {weapon.Value:X14}, {redrawOnEquality}, {unk2}, {skipGameObject}, {unk4}"); $"Weapon reloaded for 0x{actor.Address:X} ({actor.Utf8Name}) with attributes {slot} {weapon.Value:X14}, {redrawOnEquality}, {unk2}, {skipGameObject}, {unk4}, {unk5}");
} }
else else
{ {
_loadWeaponHook.Original(drawData, slot, weaponValue, redrawOnEquality, unk2, skipGameObject, unk4); _loadWeaponHook.Original(drawData, slot, weaponValue, redrawOnEquality, unk2, skipGameObject, unk4, unk5);
} }
} }
@ -89,18 +90,18 @@ public unsafe class WeaponService : IDisposable
{ {
case EquipSlot.MainHand: case EquipSlot.MainHand:
_inUpdate.Value = true; _inUpdate.Value = true;
_original(&character.AsCharacter->DrawData, 0, weapon.Value, 1, 0, 1, 0); _original(&character.AsCharacter->DrawData, 0, weapon.Value, 1, 0, 1, 0, 0);
_inUpdate.Value = false; _inUpdate.Value = false;
return; return;
case EquipSlot.OffHand: case EquipSlot.OffHand:
_inUpdate.Value = true; _inUpdate.Value = true;
_original(&character.AsCharacter->DrawData, 1, weapon.Value, 1, 0, 1, 0); _original(&character.AsCharacter->DrawData, 1, weapon.Value, 1, 0, 1, 0, 0);
_inUpdate.Value = false; _inUpdate.Value = false;
return; return;
case EquipSlot.BothHand: case EquipSlot.BothHand:
_inUpdate.Value = true; _inUpdate.Value = true;
_original(&character.AsCharacter->DrawData, 0, weapon.Value, 1, 0, 1, 0); _original(&character.AsCharacter->DrawData, 0, weapon.Value, 1, 0, 1, 0, 0);
_original(&character.AsCharacter->DrawData, 1, CharacterWeapon.Empty.Value, 1, 0, 1, 0); _original(&character.AsCharacter->DrawData, 1, CharacterWeapon.Empty.Value, 1, 0, 1, 0, 0);
_inUpdate.Value = false; _inUpdate.Value = false;
return; return;
} }