This commit is contained in:
Ottermandias 2023-01-31 17:45:42 +01:00
parent 33c2ed7903
commit e27a194cc6
47 changed files with 2037 additions and 1167 deletions

View file

@ -1,7 +1,6 @@
using System;
using Dalamud.Game.ClientState.Objects.Enums;
using Dalamud.Game.ClientState.Objects.Types;
using FFXIVClientStructs.FFXIV.Client.System.String;
using Glamourer.Customization;
using Penumbra.GameData.Actors;
using Penumbra.GameData.Structs;

View file

@ -1,23 +0,0 @@
namespace Glamourer.Interop;
public static class Offsets
{
public static class Character
{
public const int Wetness = 0x1ADA;
public const int HatVisible = 0x84E;
public const int VisorToggled = 0x84F;
public const int WeaponHidden1 = 0x84F;
public const int WeaponHidden2 = 0x72C;
public const int Alpha = 0x19E0;
public static class Flags
{
public const byte IsHatHidden = 0x01;
public const byte IsVisorToggled = 0x08;
public const byte IsWet = 0x80;
public const byte IsWeaponHidden1 = 0x01;
public const byte IsWeaponHidden2 = 0x02;
}
}
}

View file

@ -14,6 +14,8 @@ public unsafe partial class RedrawManager
[Signature("E8 ?? ?? ?? ?? 41 0F B6 C5 66 41 89 86")]
private readonly ChangeCustomizeDelegate _changeCustomize = null!;
public bool UpdateCustomize(Actor actor, Customize customize)
{
if (!actor.Valid || !actor.DrawObject.Valid)
@ -43,10 +45,11 @@ public unsafe partial class RedrawManager
return;
var flags = &data->CharacterBase.UnkFlags_01;
var state = (*flags & 0x40) != 0;
var state = (*flags & Offsets.DrawObjectVisorStateFlag) != 0;
if (state == on)
return;
*flags = (byte)((on ? *flags | 0x40 : *flags & 0xBF) | 0x80);
var newFlag = (byte)(on ? *flags | Offsets.DrawObjectVisorStateFlag : *flags & ~Offsets.DrawObjectVisorStateFlag);
*flags = (byte) (newFlag | Offsets.DrawObjectVisorToggleFlag);
}
}

View file

@ -1,8 +1,7 @@
using System;
using Dalamud.Hooking;
using Dalamud.Logging;
using Dalamud.Utility.Signatures;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using Glamourer.Designs;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
@ -10,59 +9,76 @@ namespace Glamourer.Interop;
public unsafe partial class RedrawManager
{
public delegate ulong FlagSlotForUpdateDelegate(Human* drawObject, uint slot, CharacterArmor* data);
private delegate ulong FlagSlotForUpdateDelegate(nint drawObject, uint slot, CharacterArmor* data);
// This gets called when one of the ten equip items of an existing draw object gets changed.
[Signature("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 8B DA 49 8B F0 48 8B F9 83 FA 0A", DetourName = nameof(FlagSlotForUpdateDetour))]
[Signature(Sigs.FlagSlotForUpdate, DetourName = nameof(FlagSlotForUpdateDetour))]
private readonly Hook<FlagSlotForUpdateDelegate> _flagSlotForUpdateHook = null!;
private ulong FlagSlotForUpdateDetour(Human* drawObject, uint slotIdx, CharacterArmor* data)
public void UpdateSlot(DrawObject drawObject, EquipSlot slot, CharacterArmor data)
=> FlagSlotForUpdateDetourBase(drawObject.Address, slot.ToIndex(), &data, true);
public void UpdateStain(DrawObject drawObject, EquipSlot slot, StainId stain)
{
var armor = drawObject.Equip[slot] with { Stain = stain};
UpdateSlot(drawObject, slot, armor);
}
private ulong FlagSlotForUpdateDetour(nint drawObject, uint slotIdx, CharacterArmor* data)
=> FlagSlotForUpdateDetourBase(drawObject, slotIdx, data, false);
private ulong FlagSlotForUpdateDetourBase(nint drawObject, uint slotIdx, CharacterArmor* data, bool manual)
{
var slot = slotIdx.ToEquipSlot();
try
{
var actor = Glamourer.Penumbra.GameObjectFromDrawObject((IntPtr)drawObject);
var identifier = actor.GetIdentifier();
if (_fixedDesigns.TryGetDesign(identifier, out var save))
{
PluginLog.Information($"Loaded {slot} from fixed design for {identifier}.");
(var replaced, *data) =
Glamourer.RestrictedGear.ResolveRestricted(save.Equipment[slot], slot, (Race)drawObject->Race, (Gender)drawObject->Sex);
}
else if (_currentManipulations.TryGetDesign(identifier, out var save2))
{
PluginLog.Information($"Updated {slot} from current designs for {identifier}.");
(var replaced, *data) =
Glamourer.RestrictedGear.ResolveRestricted(*data, slot, (Race)drawObject->Race, (Gender)(drawObject->Sex + 1));
save2.Data.Equipment[slot] = *data;
}
var slot = slotIdx.ToEquipSlot();
Glamourer.Log.Verbose(
$"Flagged slot {slot} of 0x{(ulong)drawObject:X} for update with {data->Set.Value}-{data->Variant} (Stain {data->Stain.Value}).");
HandleEquipUpdate(drawObject, slot, ref *data, manual);
}
catch (Exception e)
catch (Exception ex)
{
PluginLog.Error($"Error on loading new gear:\n{e}");
Glamourer.Log.Error($"Error invoking SlotUpdate:\n{ex}");
}
return _flagSlotForUpdateHook.Original(drawObject, slotIdx, data);
//try
//{
// var actor = Glamourer.Penumbra.GameObjectFromDrawObject((IntPtr)drawObject);
// var identifier = actor.GetIdentifier();
//
// if (_fixedDesigns.TryGetDesign(identifier, out var design))
// {
// PluginLog.Information($"Loaded {slot} from fixed design for {identifier}.");
// (var replaced, *data) =
// Glamourer.Items.RestrictedGear.ResolveRestricted(design.Armor(slot).Model, slot, (Race)drawObject->Race, (Gender)drawObject->Sex);
// }
// else if (_currentManipulations.TryGetDesign(identifier, out var save2))
// {
// PluginLog.Information($"Updated {slot} from current designs for {identifier}.");
// (var replaced, *data) =
// Glamourer.Items.RestrictedGear.ResolveRestricted(*data, slot, (Race)drawObject->Race, (Gender)(drawObject->Sex + 1));
// save2.Data.Equipment[slot] = *data;
// }
//}
//catch (Exception e)
//{
// PluginLog.Error($"Error on loading new gear:\n{e}");
//}
//
//return _flagSlotForUpdateHook.Original(drawObject, slotIdx, data);
}
public bool ChangeEquip(DrawObject drawObject, uint slotIdx, CharacterArmor data)
private void HandleEquipUpdate(nint drawObject, EquipSlot slot, ref CharacterArmor data, bool manual)
{
if (!drawObject)
return false;
var actor = Glamourer.Penumbra.GameObjectFromDrawObject(drawObject);
var identifier = actor.GetIdentifier();
if (slotIdx > 9)
return false;
if (!_currentManipulations.TryGetDesign(identifier, out var design))
return;
return FlagSlotForUpdateDetour(drawObject.Pointer, slotIdx, &data) != 0;
var flag = slot.ToFlag();
var stainFlag = slot.ToStainFlag();
}
public bool ChangeEquip(Actor actor, EquipSlot slot, CharacterArmor data)
=> actor && ChangeEquip(actor.DrawObject, slot.ToIndex(), data);
public bool ChangeEquip(DrawObject drawObject, EquipSlot slot, CharacterArmor data)
=> ChangeEquip(drawObject, slot.ToIndex(), data);
public bool ChangeEquip(Actor actor, uint slotIdx, CharacterArmor data)
=> actor && ChangeEquip(actor.DrawObject, slotIdx, data);
}

View file

@ -40,8 +40,8 @@ public unsafe partial class RedrawManager
PluginLog.Information($"Loaded weapon from fixed design for {identifier}.");
weapon = slot switch
{
0 => save.MainHand.Value,
1 => save.OffHand.Value,
0 => save.WeaponMain.Model.Value,
1 => save.WeaponOff.Model.Value,
_ => weapon,
};
}

View file

@ -2,27 +2,40 @@
using Dalamud.Hooking;
using Dalamud.Logging;
using Dalamud.Utility.Signatures;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using Glamourer.Customization;
using Glamourer.State;
using Glamourer.Structs;
using Penumbra.GameData.Data;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
using CustomizeData = Penumbra.GameData.Structs.CustomizeData;
namespace Glamourer.Interop;
public class DesignBaseValidator
{
private readonly CustomizationManager _manager;
private readonly RestrictedGear _restrictedGear;
public DesignBaseValidator(CustomizationManager manager, RestrictedGear restrictedGear)
{
_manager = manager;
_restrictedGear = restrictedGear;
}
}
public unsafe partial class RedrawManager
{
private delegate void ChangeJobDelegate(IntPtr data, uint job);
[Signature("88 51 ?? 44 3B CA", DetourName = nameof(ChangeJobDetour))]
[Signature(Sigs.ChangeJob, DetourName = nameof(ChangeJobDetour))]
private readonly Hook<ChangeJobDelegate> _changeJobHook = null!;
private void ChangeJobDetour(IntPtr data, uint job)
{
_changeJobHook.Original(data, job);
JobChanged?.Invoke(data - 0x1A8, GameData.Jobs(Dalamud.GameData)[(byte)job]);
JobChanged?.Invoke(data - Offsets.Character.ClassJobContainer, GameData.Jobs(Dalamud.GameData)[(byte)job]);
}
public event Action<Actor, Job>? JobChanged;
@ -70,18 +83,18 @@ public unsafe partial class RedrawManager : IDisposable
// Apply customization if they correspond and there is customization to apply.
var gameObjectCustomize = new Customize((CustomizeData*)actor.Pointer->CustomizeData);
if (gameObjectCustomize.Equals(customize))
customize.Load(save!.Data.Customize);
customize.Load(save!.Customize());
// Compare game object equip data against draw object equip data for transformations.
// Apply each piece of equip that should be applied if they correspond.
var gameObjectEquip = new CharacterEquip((CharacterArmor*)actor.Pointer->EquipSlotData);
if (gameObjectEquip.Equals(equip))
{
var saveEquip = save!.Data.Equipment;
var saveEquip = save!.Equipment();
foreach (var slot in EquipSlotExtensions.EqdpSlots)
{
(_, equip[slot]) =
Glamourer.RestrictedGear.ResolveRestricted(saveEquip[slot], slot, customize.Race, customize.Gender);
Glamourer.Items.RestrictedGear.ResolveRestricted(saveEquip[slot], slot, customize.Race, customize.Gender);
}
}
}