mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 10:17:23 +01:00
Extricate bonus slots somewhat.
This commit is contained in:
parent
7caf6cc08a
commit
7a602d6ec5
8 changed files with 86 additions and 37 deletions
25
Glamourer/Events/BonusSlotUpdating.cs
Normal file
25
Glamourer/Events/BonusSlotUpdating.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when a model flags a bonus slot for an update.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is the model with a flagged slot. </item>
|
||||
/// <item>Parameter is the bonus slot changed. </item>
|
||||
/// <item>Parameter is the model values to change the bonus piece to. </item>
|
||||
/// <item>Parameter is the return value the function should return, if it is ulong.MaxValue, the original will be called and returned. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class BonusSlotUpdating()
|
||||
: EventWrapperRef34<Model, BonusEquipFlag, CharacterArmor, ulong, BonusSlotUpdating.Priority>(nameof(BonusSlotUpdating))
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="State.StateListener.OnBonusSlotUpdating"/>
|
||||
StateListener = 0,
|
||||
}
|
||||
}
|
||||
|
|
@ -14,12 +14,12 @@ namespace Glamourer.Events;
|
|||
/// <item>Parameter is the return value the function should return, if it is ulong.MaxValue, the original will be called and returned. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class SlotUpdating()
|
||||
: EventWrapperRef34<Model, EquipSlot, CharacterArmor, ulong, SlotUpdating.Priority>(nameof(SlotUpdating))
|
||||
public sealed class EquipSlotUpdating()
|
||||
: EventWrapperRef34<Model, EquipSlot, CharacterArmor, ulong, EquipSlotUpdating.Priority>(nameof(EquipSlotUpdating))
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="State.StateListener.OnSlotUpdating"/>
|
||||
/// <seealso cref="State.StateListener.OnEquipSlotUpdating"/>
|
||||
StateListener = 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -90,7 +90,7 @@ public unsafe class ModelEvaluationPanel(
|
|||
: "No CharacterBase");
|
||||
}
|
||||
|
||||
private void DrawParameters(Actor actor, Model model)
|
||||
private static void DrawParameters(Actor actor, Model model)
|
||||
{
|
||||
if (!model.IsHuman)
|
||||
return;
|
||||
|
|
@ -140,13 +140,13 @@ public unsafe class ModelEvaluationPanel(
|
|||
return;
|
||||
|
||||
if (ImGui.SmallButton("Hide"))
|
||||
_updateSlotService.UpdateSlot(model, EquipSlot.Head, CharacterArmor.Empty);
|
||||
_updateSlotService.UpdateEquipSlot(model, EquipSlot.Head, CharacterArmor.Empty);
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("Show"))
|
||||
_updateSlotService.UpdateSlot(model, EquipSlot.Head, actor.GetArmor(EquipSlot.Head));
|
||||
_updateSlotService.UpdateEquipSlot(model, EquipSlot.Head, actor.GetArmor(EquipSlot.Head));
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("Toggle"))
|
||||
_updateSlotService.UpdateSlot(model, EquipSlot.Head,
|
||||
_updateSlotService.UpdateEquipSlot(model, EquipSlot.Head,
|
||||
model.AsHuman->Head.Value == 0 ? actor.GetArmor(EquipSlot.Head) : CharacterArmor.Empty);
|
||||
}
|
||||
|
||||
|
|
@ -223,31 +223,32 @@ public unsafe class ModelEvaluationPanel(
|
|||
_updateSlotService.UpdateStain(model, slot, new StainIds(5, 7));
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("Reset"))
|
||||
_updateSlotService.UpdateSlot(model, slot, actor.GetArmor(slot));
|
||||
_updateSlotService.UpdateEquipSlot(model, slot, actor.GetArmor(slot));
|
||||
}
|
||||
|
||||
using (ImRaii.PushId((int)EquipSlot.FaceWear))
|
||||
foreach (var slot in BonusSlotExtensions.AllFlags)
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(EquipSlot.FaceWear.ToName());
|
||||
using var id2 = ImRaii.PushId((int)slot.ToModelIndex());
|
||||
ImGuiUtil.DrawTableColumn(slot.ToName());
|
||||
if (!actor.IsCharacter)
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn("No Character");
|
||||
}
|
||||
else
|
||||
{
|
||||
var glassesId = actor.AsCharacter->DrawData.GlassesIds[(int)EquipSlot.FaceWear.ToBonusIndex()];
|
||||
var glassesId = actor.GetBonusSlot(slot);
|
||||
if (_glasses.TryGetValue(glassesId, out var glasses))
|
||||
ImGuiUtil.DrawTableColumn($"{glasses.Id.Id},{glasses.Variant.Id} ({glassesId})");
|
||||
else
|
||||
ImGuiUtil.DrawTableColumn($"{glassesId}");
|
||||
}
|
||||
|
||||
ImGuiUtil.DrawTableColumn(model.IsHuman ? model.GetArmor(EquipSlot.FaceWear).ToString() : "No Human");
|
||||
ImGuiUtil.DrawTableColumn(model.IsHuman ? model.GetBonus(slot).ToString() : "No Human");
|
||||
ImGui.TableNextColumn();
|
||||
if (ImUtf8.SmallButton("Change Piece"u8))
|
||||
{
|
||||
var data = model.GetArmor(EquipSlot.FaceWear);
|
||||
_updateSlotService.UpdateSlot(model, EquipSlot.FaceWear, data with { Variant = (Variant)((data.Variant.Id + 1) % 12) });
|
||||
var data = model.GetBonus(slot);
|
||||
_updateSlotService.UpdateBonusSlot(model, slot, data with { Variant = (Variant)((data.Variant.Id + 1) % 12) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using Dalamud.Plugin.Services;
|
|||
using Dalamud.Utility.Signatures;
|
||||
using Glamourer.Events;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
|
@ -11,11 +12,16 @@ namespace Glamourer.Interop;
|
|||
|
||||
public unsafe class UpdateSlotService : IDisposable
|
||||
{
|
||||
public readonly SlotUpdating SlotUpdatingEvent;
|
||||
public readonly EquipSlotUpdating EquipSlotUpdatingEvent;
|
||||
public readonly BonusSlotUpdating BonusSlotUpdatingEvent;
|
||||
private readonly DictGlasses _glasses;
|
||||
|
||||
public UpdateSlotService(SlotUpdating slotUpdating, IGameInteropProvider interop)
|
||||
public UpdateSlotService(EquipSlotUpdating equipSlotUpdating, BonusSlotUpdating bonusSlotUpdating, IGameInteropProvider interop,
|
||||
DictGlasses glasses)
|
||||
{
|
||||
SlotUpdatingEvent = slotUpdating;
|
||||
EquipSlotUpdatingEvent = equipSlotUpdating;
|
||||
BonusSlotUpdatingEvent = bonusSlotUpdating;
|
||||
_glasses = glasses;
|
||||
interop.InitializeFromAttributes(this);
|
||||
_flagSlotForUpdateHook.Enable();
|
||||
_flagBonusSlotForUpdateHook.Enable();
|
||||
|
|
@ -27,20 +33,37 @@ public unsafe class UpdateSlotService : IDisposable
|
|||
_flagBonusSlotForUpdateHook.Dispose();
|
||||
}
|
||||
|
||||
public void UpdateSlot(Model drawObject, EquipSlot slot, CharacterArmor data)
|
||||
public void UpdateEquipSlot(Model drawObject, EquipSlot slot, CharacterArmor data)
|
||||
{
|
||||
if (!drawObject.IsCharacterBase)
|
||||
return;
|
||||
|
||||
var bonusSlot = slot.ToBonusIndex();
|
||||
if (bonusSlot == uint.MaxValue)
|
||||
FlagSlotForUpdateInterop(drawObject, slot, data);
|
||||
else
|
||||
_flagBonusSlotForUpdateHook.Original(drawObject.Address, bonusSlot, &data);
|
||||
FlagSlotForUpdateInterop(drawObject, slot, data);
|
||||
}
|
||||
|
||||
public void UpdateBonusSlot(Model drawObject, BonusEquipFlag slot, CharacterArmor data)
|
||||
{
|
||||
if (!drawObject.IsCharacterBase)
|
||||
return;
|
||||
|
||||
var index = slot.ToIndex();
|
||||
if (index == uint.MaxValue)
|
||||
return;
|
||||
|
||||
_flagBonusSlotForUpdateHook.Original(drawObject.Address, index, &data);
|
||||
}
|
||||
|
||||
public void UpdateGlasses(Model drawObject, GlassesId id)
|
||||
{
|
||||
if (!_glasses.TryGetValue(id, out var glasses))
|
||||
return;
|
||||
|
||||
var armor = new CharacterArmor(glasses.Id, glasses.Variant, StainIds.None);
|
||||
_flagBonusSlotForUpdateHook.Original(drawObject.Address, BonusEquipFlag.Glasses.ToIndex(), &armor);
|
||||
}
|
||||
|
||||
public void UpdateArmor(Model drawObject, EquipSlot slot, CharacterArmor armor, StainIds stains)
|
||||
=> UpdateSlot(drawObject, slot, armor.With(stains));
|
||||
=> UpdateEquipSlot(drawObject, slot, armor.With(stains));
|
||||
|
||||
public void UpdateArmor(Model drawObject, EquipSlot slot, CharacterArmor armor)
|
||||
=> UpdateArmor(drawObject, slot, armor, drawObject.GetArmor(slot).Stains);
|
||||
|
|
@ -60,7 +83,7 @@ public unsafe class UpdateSlotService : IDisposable
|
|||
{
|
||||
var slot = slotIdx.ToEquipSlot();
|
||||
var returnValue = ulong.MaxValue;
|
||||
SlotUpdatingEvent.Invoke(drawObject, slot, ref *data, ref returnValue);
|
||||
EquipSlotUpdatingEvent.Invoke(drawObject, slot, ref *data, ref returnValue);
|
||||
Glamourer.Log.Excessive($"[FlagSlotForUpdate] Called with 0x{drawObject:X} for slot {slot} with {*data} ({returnValue:X}).");
|
||||
return returnValue == ulong.MaxValue ? _flagSlotForUpdateHook.Original(drawObject, slotIdx, data) : returnValue;
|
||||
}
|
||||
|
|
@ -69,7 +92,7 @@ public unsafe class UpdateSlotService : IDisposable
|
|||
{
|
||||
var slot = slotIdx.ToBonusSlot();
|
||||
var returnValue = ulong.MaxValue;
|
||||
SlotUpdatingEvent.Invoke(drawObject, slot, ref *data, ref returnValue);
|
||||
BonusSlotUpdatingEvent.Invoke(drawObject, slot, ref *data, ref returnValue);
|
||||
Glamourer.Log.Excessive($"[FlagBonusSlotForUpdate] Called with 0x{drawObject:X} for slot {slot} with {*data} ({returnValue:X}).");
|
||||
return returnValue == ulong.MaxValue ? _flagBonusSlotForUpdateHook.Original(drawObject, slotIdx, data) : returnValue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ public static class StaticServiceManager
|
|||
|
||||
private static ServiceManager AddEvents(this ServiceManager services)
|
||||
=> services.AddSingleton<VisorStateChanged>()
|
||||
.AddSingleton<SlotUpdating>()
|
||||
.AddSingleton<EquipSlotUpdating>()
|
||||
.AddSingleton<DesignChanged>()
|
||||
.AddSingleton<AutomationChanged>()
|
||||
.AddSingleton<StateChanged>()
|
||||
|
|
|
|||
|
|
@ -105,11 +105,11 @@ public class StateApplier(
|
|||
{
|
||||
var customize = mdl.GetCustomize();
|
||||
var (_, resolvedItem) = _items.ResolveRestrictedGear(armor, slot, customize.Race, customize.Gender);
|
||||
_updateSlot.UpdateSlot(actor.Model, slot, resolvedItem);
|
||||
_updateSlot.UpdateEquipSlot(actor.Model, slot, resolvedItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
_updateSlot.UpdateSlot(actor.Model, slot, armor);
|
||||
_updateSlot.UpdateEquipSlot(actor.Model, slot, armor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public class StateListener : IDisposable
|
|||
private readonly ItemManager _items;
|
||||
private readonly CustomizeService _customizations;
|
||||
private readonly PenumbraService _penumbra;
|
||||
private readonly SlotUpdating _slotUpdating;
|
||||
private readonly EquipSlotUpdating _equipSlotUpdating;
|
||||
private readonly WeaponLoading _weaponLoading;
|
||||
private readonly HeadGearVisibilityChanged _headGearVisibility;
|
||||
private readonly VisorStateChanged _visorState;
|
||||
|
|
@ -52,7 +52,7 @@ public class StateListener : IDisposable
|
|||
private CharacterWeapon _lastFistOffhand = CharacterWeapon.Empty;
|
||||
|
||||
public StateListener(StateManager manager, ItemManager items, PenumbraService penumbra, ActorManager actors, Configuration config,
|
||||
SlotUpdating slotUpdating, WeaponLoading weaponLoading, VisorStateChanged visorState, WeaponVisibilityChanged weaponVisibility,
|
||||
EquipSlotUpdating equipSlotUpdating, WeaponLoading weaponLoading, VisorStateChanged visorState, WeaponVisibilityChanged weaponVisibility,
|
||||
HeadGearVisibilityChanged headGearVisibility, AutoDesignApplier autoDesignApplier, FunModule funModule, HumanModelList humans,
|
||||
StateApplier applier, MovedEquipment movedEquipment, ObjectManager objects, GPoseService gPose,
|
||||
ChangeCustomizeService changeCustomizeService, CustomizeService customizations, ICondition condition, CrestService crestService)
|
||||
|
|
@ -62,7 +62,7 @@ public class StateListener : IDisposable
|
|||
_penumbra = penumbra;
|
||||
_actors = actors;
|
||||
_config = config;
|
||||
_slotUpdating = slotUpdating;
|
||||
_equipSlotUpdating = equipSlotUpdating;
|
||||
_weaponLoading = weaponLoading;
|
||||
_visorState = visorState;
|
||||
_weaponVisibility = weaponVisibility;
|
||||
|
|
@ -202,7 +202,7 @@ public class StateListener : IDisposable
|
|||
/// A draw model loads a new equipment piece.
|
||||
/// Update base data, apply or update model data, and protect against restricted gear.
|
||||
/// </summary>
|
||||
private void OnSlotUpdating(Model model, EquipSlot slot, ref CharacterArmor armor, ref ulong returnValue)
|
||||
private void OnEquipSlotUpdating(Model model, EquipSlot slot, ref CharacterArmor armor, ref ulong returnValue)
|
||||
{
|
||||
var actor = _penumbra.GameObjectFromDrawObject(model);
|
||||
if (_condition[ConditionFlag.CreatingCharacter] && actor.Index >= ObjectIndex.CutsceneStart)
|
||||
|
|
@ -699,7 +699,7 @@ public class StateListener : IDisposable
|
|||
{
|
||||
_penumbra.CreatingCharacterBase += OnCreatingCharacterBase;
|
||||
_penumbra.CreatedCharacterBase += OnCreatedCharacterBase;
|
||||
_slotUpdating.Subscribe(OnSlotUpdating, SlotUpdating.Priority.StateListener);
|
||||
_equipSlotUpdating.Subscribe(OnEquipSlotUpdating, EquipSlotUpdating.Priority.StateListener);
|
||||
_movedEquipment.Subscribe(OnMovedEquipment, MovedEquipment.Priority.StateListener);
|
||||
_weaponLoading.Subscribe(OnWeaponLoading, WeaponLoading.Priority.StateListener);
|
||||
_visorState.Subscribe(OnVisorChange, VisorStateChanged.Priority.StateListener);
|
||||
|
|
@ -715,7 +715,7 @@ public class StateListener : IDisposable
|
|||
{
|
||||
_penumbra.CreatingCharacterBase -= OnCreatingCharacterBase;
|
||||
_penumbra.CreatedCharacterBase -= OnCreatedCharacterBase;
|
||||
_slotUpdating.Unsubscribe(OnSlotUpdating);
|
||||
_equipSlotUpdating.Unsubscribe(OnEquipSlotUpdating);
|
||||
_movedEquipment.Unsubscribe(OnMovedEquipment);
|
||||
_weaponLoading.Unsubscribe(OnWeaponLoading);
|
||||
_visorState.Unsubscribe(OnVisorChange);
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 8ec296d1f8113ae2ba509527749cd3e8f54debbf
|
||||
Subproject commit d83303ccc3ec5d7237f5da621e9c2433ad28f9e1
|
||||
Loading…
Add table
Add a link
Reference in a new issue