mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 10:17:23 +01:00
102 lines
4.8 KiB
C#
102 lines
4.8 KiB
C#
using System;
|
|
using System.Runtime.InteropServices;
|
|
using Dalamud.Hooking;
|
|
using Dalamud.Logging;
|
|
using Dalamud.Utility.Signatures;
|
|
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
|
using Penumbra.GameData.Enums;
|
|
using Penumbra.GameData.Structs;
|
|
|
|
namespace Glamourer.Interop;
|
|
|
|
public unsafe partial class RedrawManager
|
|
{
|
|
public static readonly int CharacterWeaponOffset = (int)Marshal.OffsetOf<Character>("DrawData");
|
|
|
|
public delegate void LoadWeaponDelegate(IntPtr offsetCharacter, uint slot, ulong weapon, byte redrawOnEquality, byte unk2,
|
|
byte skipGameObject,
|
|
byte unk4);
|
|
|
|
// Weapons for a specific character are reloaded with this function.
|
|
// The first argument is a pointer to the game object but shifted a bit inside.
|
|
// slot is 0 for main hand, 1 for offhand, 2 for unknown (always called with empty data.
|
|
// weapon argument is the new weapon data.
|
|
// 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)
|
|
// unk4 seemed to be the same as unk1.
|
|
[Signature("E8 ?? ?? ?? ?? 44 8B 9F", DetourName = nameof(LoadWeaponDetour))]
|
|
private readonly Hook<LoadWeaponDelegate> _loadWeaponHook = null!;
|
|
|
|
private void LoadWeaponDetour(IntPtr characterOffset, uint slot, ulong weapon, byte redrawOnEquality, byte unk2, byte skipGameObject,
|
|
byte unk4)
|
|
{
|
|
var oldWeapon = weapon;
|
|
var character = (Actor)(characterOffset - CharacterWeaponOffset);
|
|
try
|
|
{
|
|
var identifier = character.GetIdentifier();
|
|
if (_fixedDesigns.TryGetDesign(identifier, out var save))
|
|
{
|
|
PluginLog.Information($"Loaded weapon from fixed design for {identifier}.");
|
|
weapon = slot switch
|
|
{
|
|
0 => save.MainHand.Value,
|
|
1 => save.OffHand.Value,
|
|
_ => weapon,
|
|
};
|
|
}
|
|
else if (redrawOnEquality == 1 && _currentManipulations.TryGetDesign(identifier, out var save2))
|
|
{
|
|
PluginLog.Information($"Loaded weapon from current design for {identifier}.");
|
|
switch (slot)
|
|
{
|
|
case 0:
|
|
save2.Data.MainHand = new CharacterWeapon(weapon);
|
|
break;
|
|
case 1:
|
|
save2.Data.OffHand = new CharacterWeapon(weapon);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
PluginLog.Error($"Error on loading new weapon:\n{e}");
|
|
}
|
|
|
|
// First call the regular function.
|
|
_loadWeaponHook.Original(characterOffset, slot, oldWeapon, redrawOnEquality, unk2, skipGameObject, unk4);
|
|
// If something changed the weapon, call it again with the actual change, not forcing redraws and skipping applying it to the game object.
|
|
if (oldWeapon != weapon)
|
|
_loadWeaponHook.Original(characterOffset, slot, weapon, 0 /* redraw */, unk2, 1 /* skip */, unk4);
|
|
// If we're not actively changing the offhand and the game object has no offhand, redraw an empty offhand to fix animation problems.
|
|
else if (slot != 1 && character.OffHand.Value == 0)
|
|
_loadWeaponHook.Original(characterOffset, 1, 0, 1 /* redraw */, unk2, 1 /* skip */, unk4);
|
|
}
|
|
|
|
// Load a specific weapon for a character by its data and slot.
|
|
public void LoadWeapon(Actor character, EquipSlot slot, CharacterWeapon weapon)
|
|
{
|
|
switch (slot)
|
|
{
|
|
case EquipSlot.MainHand:
|
|
LoadWeaponDetour(character.Address + CharacterWeaponOffset, 0, weapon.Value, 0, 0, 1, 0);
|
|
return;
|
|
case EquipSlot.OffHand:
|
|
LoadWeaponDetour(character.Address + CharacterWeaponOffset, 1, weapon.Value, 0, 0, 1, 0);
|
|
return;
|
|
case EquipSlot.BothHand:
|
|
LoadWeaponDetour(character.Address + CharacterWeaponOffset, 0, weapon.Value, 0, 0, 1, 0);
|
|
LoadWeaponDetour(character.Address + CharacterWeaponOffset, 1, CharacterWeapon.Empty.Value, 0, 0, 1, 0);
|
|
return;
|
|
// function can also be called with '2', but does not seem to ever be.
|
|
}
|
|
}
|
|
|
|
// Load specific Main- and Offhand weapons.
|
|
public void LoadWeapon(Actor character, CharacterWeapon main, CharacterWeapon off)
|
|
{
|
|
LoadWeaponDetour(character.Address + CharacterWeaponOffset, 0, main.Value, 1, 0, 1, 0);
|
|
LoadWeaponDetour(character.Address + CharacterWeaponOffset, 1, off.Value, 1, 0, 1, 0);
|
|
}
|
|
}
|