mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 18:27:24 +01:00
Update OtterGui
This commit is contained in:
parent
6130bae81d
commit
6ecf06a671
23 changed files with 142 additions and 254 deletions
|
|
@ -11,7 +11,6 @@ using Glamourer.Interop.Structs;
|
|||
using Glamourer.Services;
|
||||
using Glamourer.State;
|
||||
using Glamourer.Unlocks;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
|
@ -27,7 +26,7 @@ public class AutoDesignApplier : IDisposable
|
|||
private readonly JobService _jobs;
|
||||
private readonly EquippedGearset _equippedGearset;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly CustomizeService _customizations;
|
||||
private readonly CustomizeService _customizations;
|
||||
private readonly CustomizeUnlockManager _customizeUnlocks;
|
||||
private readonly ItemUnlockManager _itemUnlocks;
|
||||
private readonly AutomationChanged _event;
|
||||
|
|
@ -80,7 +79,7 @@ public class AutoDesignApplier : IDisposable
|
|||
_jobs.JobChanged -= OnJobChange;
|
||||
}
|
||||
|
||||
private void OnWeaponLoading(Actor actor, EquipSlot slot, Ref<CharacterWeapon> weapon)
|
||||
private void OnWeaponLoading(Actor actor, EquipSlot slot, ref CharacterWeapon weapon)
|
||||
{
|
||||
if (_jobChangeState == null || !_config.EnableAutoDesigns)
|
||||
return;
|
||||
|
|
@ -89,27 +88,33 @@ public class AutoDesignApplier : IDisposable
|
|||
if (id == _jobChangeState.Identifier)
|
||||
{
|
||||
var current = _jobChangeState.BaseData.Item(slot);
|
||||
if (slot is EquipSlot.MainHand)
|
||||
switch (slot)
|
||||
{
|
||||
if (_jobChangeMainhand.TryGetValue(current.Type, out var data))
|
||||
case EquipSlot.MainHand:
|
||||
{
|
||||
Glamourer.Log.Verbose(
|
||||
$"Changing Mainhand from {_jobChangeState.ModelData.Weapon(EquipSlot.MainHand)} | {_jobChangeState.BaseData.Weapon(EquipSlot.MainHand)} to {data.Item1} for 0x{actor.Address:X}.");
|
||||
_state.ChangeItem(_jobChangeState, EquipSlot.MainHand, data.Item1, data.Item2);
|
||||
weapon.Value = _jobChangeState.ModelData.Weapon(EquipSlot.MainHand);
|
||||
}
|
||||
}
|
||||
else if (slot is EquipSlot.OffHand && current.Type == _jobChangeState.BaseData.MainhandType.Offhand())
|
||||
{
|
||||
if (_jobChangeOffhand.TryGetValue(current.Type, out var data))
|
||||
{
|
||||
Glamourer.Log.Verbose(
|
||||
$"Changing Offhand from {_jobChangeState.ModelData.Weapon(EquipSlot.OffHand)} | {_jobChangeState.BaseData.Weapon(EquipSlot.OffHand)} to {data.Item1} for 0x{actor.Address:X}.");
|
||||
_state.ChangeItem(_jobChangeState, EquipSlot.OffHand, data.Item1, data.Item2);
|
||||
weapon.Value = _jobChangeState.ModelData.Weapon(EquipSlot.OffHand);
|
||||
}
|
||||
if (_jobChangeMainhand.TryGetValue(current.Type, out var data))
|
||||
{
|
||||
Glamourer.Log.Verbose(
|
||||
$"Changing Mainhand from {_jobChangeState.ModelData.Weapon(EquipSlot.MainHand)} | {_jobChangeState.BaseData.Weapon(EquipSlot.MainHand)} to {data.Item1} for 0x{actor.Address:X}.");
|
||||
_state.ChangeItem(_jobChangeState, EquipSlot.MainHand, data.Item1, data.Item2);
|
||||
weapon = _jobChangeState.ModelData.Weapon(EquipSlot.MainHand);
|
||||
}
|
||||
|
||||
ResetJobChange();
|
||||
break;
|
||||
}
|
||||
case EquipSlot.OffHand when current.Type == _jobChangeState.BaseData.MainhandType.Offhand():
|
||||
{
|
||||
if (_jobChangeOffhand.TryGetValue(current.Type, out var data))
|
||||
{
|
||||
Glamourer.Log.Verbose(
|
||||
$"Changing Offhand from {_jobChangeState.ModelData.Weapon(EquipSlot.OffHand)} | {_jobChangeState.BaseData.Weapon(EquipSlot.OffHand)} to {data.Item1} for 0x{actor.Address:X}.");
|
||||
_state.ChangeItem(_jobChangeState, EquipSlot.OffHand, data.Item1, data.Item2);
|
||||
weapon = _jobChangeState.ModelData.Weapon(EquipSlot.OffHand);
|
||||
}
|
||||
|
||||
ResetJobChange();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -123,21 +128,32 @@ public class AutoDesignApplier : IDisposable
|
|||
if (!_config.EnableAutoDesigns || set == null)
|
||||
return;
|
||||
|
||||
void RemoveOld(ActorIdentifier[]? identifiers)
|
||||
switch (type)
|
||||
{
|
||||
if (identifiers == null)
|
||||
return;
|
||||
|
||||
foreach (var id in identifiers)
|
||||
{
|
||||
if (id.Type is IdentifierType.Player && id.HomeWorld == WorldId.AnyWorld)
|
||||
foreach (var state in _state.Where(kvp => kvp.Key.PlayerName == id.PlayerName).Select(kvp => kvp.Value))
|
||||
state.RemoveFixedDesignSources();
|
||||
else if (_state.TryGetValue(id, out var state))
|
||||
state.RemoveFixedDesignSources();
|
||||
}
|
||||
case AutomationChanged.Type.ToggleSet when !set.Enabled:
|
||||
case AutomationChanged.Type.DeletedDesign when set.Enabled:
|
||||
// The automation set was disabled or deleted, no other for those identifiers can be enabled, remove existing Fixed Locks.
|
||||
RemoveOld(set.Identifiers);
|
||||
break;
|
||||
case AutomationChanged.Type.ChangeIdentifier when set.Enabled:
|
||||
// Remove fixed state from the old identifiers assigned and the old enabled set, if any.
|
||||
var (oldIds, _, oldSet) = ((ActorIdentifier[], ActorIdentifier, AutoDesignSet?))bonusData!;
|
||||
RemoveOld(oldIds);
|
||||
ApplyNew(set); // Does not need to disable oldSet because same identifiers.
|
||||
break;
|
||||
case AutomationChanged.Type.ToggleSet: // Does not need to disable old states because same identifiers.
|
||||
case AutomationChanged.Type.ChangedBase:
|
||||
case AutomationChanged.Type.AddedDesign:
|
||||
case AutomationChanged.Type.MovedDesign:
|
||||
case AutomationChanged.Type.ChangedDesign:
|
||||
case AutomationChanged.Type.ChangedConditions:
|
||||
case AutomationChanged.Type.ChangedType:
|
||||
ApplyNew(set);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
void ApplyNew(AutoDesignSet? newSet)
|
||||
{
|
||||
if (newSet is not { Enabled: true })
|
||||
|
|
@ -174,28 +190,19 @@ public class AutoDesignApplier : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
switch (type)
|
||||
void RemoveOld(ActorIdentifier[]? identifiers)
|
||||
{
|
||||
case AutomationChanged.Type.ToggleSet when !set.Enabled:
|
||||
case AutomationChanged.Type.DeletedDesign when set.Enabled:
|
||||
// The automation set was disabled or deleted, no other for those identifiers can be enabled, remove existing Fixed Locks.
|
||||
RemoveOld(set.Identifiers);
|
||||
break;
|
||||
case AutomationChanged.Type.ChangeIdentifier when set.Enabled:
|
||||
// Remove fixed state from the old identifiers assigned and the old enabled set, if any.
|
||||
var (oldIds, _, oldSet) = ((ActorIdentifier[], ActorIdentifier, AutoDesignSet?))bonusData!;
|
||||
RemoveOld(oldIds);
|
||||
ApplyNew(set); // Does not need to disable oldSet because same identifiers.
|
||||
break;
|
||||
case AutomationChanged.Type.ToggleSet: // Does not need to disable old states because same identifiers.
|
||||
case AutomationChanged.Type.ChangedBase:
|
||||
case AutomationChanged.Type.AddedDesign:
|
||||
case AutomationChanged.Type.MovedDesign:
|
||||
case AutomationChanged.Type.ChangedDesign:
|
||||
case AutomationChanged.Type.ChangedConditions:
|
||||
case AutomationChanged.Type.ChangedType:
|
||||
ApplyNew(set);
|
||||
break;
|
||||
if (identifiers == null)
|
||||
return;
|
||||
|
||||
foreach (var id in identifiers)
|
||||
{
|
||||
if (id.Type is IdentifierType.Player && id.HomeWorld == WorldId.AnyWorld)
|
||||
foreach (var state in _state.Where(kvp => kvp.Key.PlayerName == id.PlayerName).Select(kvp => kvp.Value))
|
||||
state.RemoveFixedDesignSources();
|
||||
else if (_state.TryGetValue(id, out var state))
|
||||
state.RemoveFixedDesignSources();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ public class DesignManager
|
|||
|
||||
Glamourer.Log.Information(
|
||||
$"Loaded {_designs.Count} designs in {stopwatch.ElapsedMilliseconds} ms.{(skipped > 0 ? $" Skipped loading {skipped} designs due to errors." : string.Empty)}");
|
||||
_event.Invoke(DesignChanged.Type.ReloadedAll, null!);
|
||||
_event.Invoke(DesignChanged.Type.ReloadedAll, null!, null);
|
||||
}
|
||||
|
||||
/// <summary> Whether an Undo for the given design is possible. </summary>
|
||||
|
|
@ -176,7 +176,7 @@ public class DesignManager
|
|||
--d.Index;
|
||||
_designs.RemoveAt(design.Index);
|
||||
_saveService.ImmediateDelete(design);
|
||||
_event.Invoke(DesignChanged.Type.Deleted, design);
|
||||
_event.Invoke(DesignChanged.Type.Deleted, design, null);
|
||||
}
|
||||
|
||||
/// <summary> Rename a design. </summary>
|
||||
|
|
@ -723,7 +723,7 @@ public class DesignManager
|
|||
if (!message.IsNullOrEmpty())
|
||||
Glamourer.Log.Debug(message);
|
||||
_saveService.ImmediateSave(design);
|
||||
_event.Invoke(DesignChanged.Type.Created, design);
|
||||
_event.Invoke(DesignChanged.Type.Created, design, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Automation;
|
||||
using OtterGui.Classes;
|
||||
|
||||
namespace Glamourer.Events;
|
||||
|
|
@ -12,8 +11,8 @@ namespace Glamourer.Events;
|
|||
/// <item>Parameter is additional data depending on the type of change. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class AutomationChanged : EventWrapper<Action<AutomationChanged.Type, AutoDesignSet?, object?>,
|
||||
AutomationChanged.Priority>
|
||||
public sealed class AutomationChanged()
|
||||
: EventWrapper<AutomationChanged.Type, AutoDesignSet?, object?, AutomationChanged.Priority>(nameof(AutomationChanged))
|
||||
{
|
||||
public enum Type
|
||||
{
|
||||
|
|
@ -65,11 +64,4 @@ public sealed class AutomationChanged : EventWrapper<Action<AutomationChanged.Ty
|
|||
/// <seealso cref="AutoDesignApplier.OnAutomationChange"/>
|
||||
AutoDesignApplier,
|
||||
}
|
||||
|
||||
public AutomationChanged()
|
||||
: base(nameof(AutomationChanged))
|
||||
{ }
|
||||
|
||||
public void Invoke(Type type, AutoDesignSet? set, object? data)
|
||||
=> Invoke(this, type, set, data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Gui;
|
||||
using OtterGui.Classes;
|
||||
|
|
@ -13,7 +12,8 @@ namespace Glamourer.Events;
|
|||
/// <item>Parameter is any additional data depending on the type of change. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class DesignChanged : EventWrapper<Action<DesignChanged.Type, Design, object?>, DesignChanged.Priority>
|
||||
public sealed class DesignChanged()
|
||||
: EventWrapper<DesignChanged.Type, Design, object?, DesignChanged.Priority>(nameof(DesignChanged))
|
||||
{
|
||||
public enum Type
|
||||
{
|
||||
|
|
@ -98,11 +98,4 @@ public sealed class DesignChanged : EventWrapper<Action<DesignChanged.Type, Desi
|
|||
/// <seealso cref="RevertDesignCombo.OnDesignChange"/>
|
||||
DesignCombo = -2,
|
||||
}
|
||||
|
||||
public DesignChanged()
|
||||
: base(nameof(DesignChanged))
|
||||
{ }
|
||||
|
||||
public void Invoke(Type type, Design design, object? data = null)
|
||||
=> Invoke(this, type, design, data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using OtterGui.Classes;
|
||||
|
||||
namespace Glamourer.Events;
|
||||
|
|
@ -13,18 +12,12 @@ namespace Glamourer.Events;
|
|||
/// <item>Parameter is the job id of the associated job. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class EquippedGearset : EventWrapper<Action<string, int, int, byte, byte>, EquippedGearset.Priority>
|
||||
public sealed class EquippedGearset()
|
||||
: EventWrapper<string, int, int, byte, byte, EquippedGearset.Priority>(nameof(EquippedGearset))
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="Automation.AutoDesignApplier.OnEquippedGearset"/>
|
||||
AutoDesignApplier = 0,
|
||||
}
|
||||
|
||||
public EquippedGearset()
|
||||
: base(nameof(EquippedGearset))
|
||||
{ }
|
||||
|
||||
public void Invoke(string name, int id, int lastId, byte glamour, byte jobId)
|
||||
=> Invoke(this, name, id, lastId, glamour, jobId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ using OtterGui.Classes;
|
|||
|
||||
namespace Glamourer.Events;
|
||||
|
||||
public sealed class GPoseService : EventWrapper<Action<bool>, GPoseService.Priority>
|
||||
public sealed class GPoseService : EventWrapper<bool, GPoseService.Priority>
|
||||
{
|
||||
private readonly IFramework _framework;
|
||||
private readonly IClientState _state;
|
||||
|
|
@ -56,7 +56,7 @@ public sealed class GPoseService : EventWrapper<Action<bool>, GPoseService.Prior
|
|||
return;
|
||||
|
||||
InGPose = inGPose;
|
||||
Invoke(this, InGPose);
|
||||
Invoke(InGPose);
|
||||
var actions = InGPose ? _onEnter : _onLeave;
|
||||
foreach (var action in actions)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using Glamourer.Interop.Structs;
|
||||
using OtterGui.Classes;
|
||||
|
||||
|
|
@ -11,22 +10,12 @@ namespace Glamourer.Events;
|
|||
/// <item>Parameter is the new state. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class HeadGearVisibilityChanged : EventWrapper<Action<Actor, Ref<bool>>, HeadGearVisibilityChanged.Priority>
|
||||
public sealed class HeadGearVisibilityChanged()
|
||||
: EventWrapperRef2<Actor, bool, HeadGearVisibilityChanged.Priority>(nameof(HeadGearVisibilityChanged))
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="State.StateListener.OnHeadGearVisibilityChange"/>
|
||||
StateListener = 0,
|
||||
}
|
||||
|
||||
public HeadGearVisibilityChanged()
|
||||
: base(nameof(HeadGearVisibilityChanged))
|
||||
{ }
|
||||
|
||||
public void Invoke(Actor actor, ref bool state)
|
||||
{
|
||||
var value = new Ref<bool>(state);
|
||||
Invoke(this, actor, value);
|
||||
state = value;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
|
@ -11,18 +10,12 @@ namespace Glamourer.Events;
|
|||
/// <item>Parameter is an array of slots updated and corresponding item ids and stains. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class MovedEquipment : EventWrapper<Action<(EquipSlot, uint, StainId)[]>, MovedEquipment.Priority>
|
||||
public sealed class MovedEquipment()
|
||||
: EventWrapper<(EquipSlot, uint, StainId)[], MovedEquipment.Priority>(nameof(MovedEquipment))
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="State.StateListener.OnMovedEquipment"/>
|
||||
StateListener = 0,
|
||||
}
|
||||
|
||||
public MovedEquipment()
|
||||
: base(nameof(MovedEquipment))
|
||||
{ }
|
||||
|
||||
public void Invoke((EquipSlot, uint, StainId)[] items)
|
||||
=> Invoke(this, items);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ namespace Glamourer.Events;
|
|||
/// <item>Parameter is the timestamp of the unlock. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class ObjectUnlocked : EventWrapper<Action<ObjectUnlocked.Type, uint, DateTimeOffset>, ObjectUnlocked.Priority>
|
||||
public sealed class ObjectUnlocked()
|
||||
: EventWrapper<ObjectUnlocked.Type, uint, DateTimeOffset, ObjectUnlocked.Priority>(nameof(ObjectUnlocked))
|
||||
{
|
||||
public enum Type
|
||||
{
|
||||
|
|
@ -25,11 +26,4 @@ public sealed class ObjectUnlocked : EventWrapper<Action<ObjectUnlocked.Type, ui
|
|||
/// <remarks> Currently used as a hack to make the unlock table dirty in it. If anything else starts using this, rework. </remarks>
|
||||
UnlockTable = 0,
|
||||
}
|
||||
|
||||
public ObjectUnlocked()
|
||||
: base(nameof(ObjectUnlocked))
|
||||
{ }
|
||||
|
||||
public void Invoke(Type type, uint id, DateTimeOffset timestamp)
|
||||
=> Invoke(this, type, id, timestamp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using OtterGui.Classes;
|
||||
|
||||
namespace Glamourer.Events;
|
||||
|
|
@ -6,18 +5,12 @@ namespace Glamourer.Events;
|
|||
/// <summary>
|
||||
/// Triggered when Penumbra is reloaded.
|
||||
/// </summary>
|
||||
public sealed class PenumbraReloaded : EventWrapper<Action, PenumbraReloaded.Priority>
|
||||
public sealed class PenumbraReloaded()
|
||||
: EventWrapper<PenumbraReloaded.Priority>(nameof(PenumbraReloaded))
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="Interop.ChangeCustomizeService.Restore"/>
|
||||
ChangeCustomizeService = 0,
|
||||
}
|
||||
|
||||
public PenumbraReloaded()
|
||||
: base(nameof(PenumbraReloaded))
|
||||
{ }
|
||||
|
||||
public void Invoke()
|
||||
=> Invoke(this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,24 +15,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 : EventWrapper<Action<Model, EquipSlot, Ref<CharacterArmor>, Ref<ulong>>, SlotUpdating.Priority>
|
||||
public sealed class SlotUpdating()
|
||||
: EventWrapperRef34<Model, EquipSlot, CharacterArmor, ulong, SlotUpdating.Priority>(nameof(SlotUpdating))
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="State.StateListener.OnSlotUpdating"/>
|
||||
StateListener = 0,
|
||||
}
|
||||
|
||||
public SlotUpdating()
|
||||
: base(nameof(SlotUpdating))
|
||||
{ }
|
||||
|
||||
public void Invoke(Model model, EquipSlot slot, ref CharacterArmor armor, ref ulong returnValue)
|
||||
{
|
||||
var value = new Ref<CharacterArmor>(armor);
|
||||
var @return = new Ref<ulong>(returnValue);
|
||||
Invoke(this, model, slot, value, @return);
|
||||
armor = value;
|
||||
returnValue = @return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
using System;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.State;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Actors;
|
||||
|
||||
namespace Glamourer.Events;
|
||||
|
||||
|
|
@ -15,7 +13,8 @@ namespace Glamourer.Events;
|
|||
/// <item>Parameter is any additional data depending on the type of change. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class StateChanged : EventWrapper<Action<StateChanged.Type, StateChanged.Source, ActorState, ActorData, object?>, StateChanged.Priority>
|
||||
public sealed class StateChanged()
|
||||
: EventWrapper<StateChanged.Type, StateChanged.Source, ActorState, ActorData, object?, StateChanged.Priority>(nameof(StateChanged))
|
||||
{
|
||||
public enum Type
|
||||
{
|
||||
|
|
@ -62,11 +61,4 @@ public sealed class StateChanged : EventWrapper<Action<StateChanged.Type, StateC
|
|||
{
|
||||
GlamourerIpc = int.MinValue,
|
||||
}
|
||||
|
||||
public StateChanged()
|
||||
: base(nameof(StateChanged))
|
||||
{ }
|
||||
|
||||
public void Invoke(Type type, Source source, ActorState state, ActorData actors, object? data = null)
|
||||
=> Invoke(this, type, source, state, actors, data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Gui;
|
||||
using OtterGui.Classes;
|
||||
|
||||
|
|
@ -12,8 +11,8 @@ namespace Glamourer.Events;
|
|||
/// <item>Parameter is the design to select if the tab is the designs tab. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class TabSelected : EventWrapper<Action<MainWindow.TabType, Design?>,
|
||||
TabSelected.Priority>
|
||||
public sealed class TabSelected()
|
||||
: EventWrapper<MainWindow.TabType, Design?, TabSelected.Priority>(nameof(TabSelected))
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
@ -23,11 +22,4 @@ public sealed class TabSelected : EventWrapper<Action<MainWindow.TabType, Design
|
|||
/// <seealso cref="Gui.MainWindow.OnTabSelected"/>
|
||||
MainWindow = 1,
|
||||
}
|
||||
|
||||
public TabSelected()
|
||||
: base(nameof(TabSelected))
|
||||
{ }
|
||||
|
||||
public void Invoke(MainWindow.TabType type, Design? design)
|
||||
=> Invoke(this, type, design);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using Glamourer.Interop.Structs;
|
||||
using OtterGui.Classes;
|
||||
|
||||
|
|
@ -12,22 +11,12 @@ namespace Glamourer.Events;
|
|||
/// <item>Parameter is whether to call the original function. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class VisorStateChanged : EventWrapper<Action<Model, Ref<bool>>, VisorStateChanged.Priority>
|
||||
public sealed class VisorStateChanged()
|
||||
: EventWrapperRef2<Model, bool, VisorStateChanged.Priority>(nameof(VisorStateChanged))
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="State.StateListener.OnVisorChange"/>
|
||||
StateListener = 0,
|
||||
}
|
||||
|
||||
public VisorStateChanged()
|
||||
: base(nameof(VisorStateChanged))
|
||||
{ }
|
||||
|
||||
public void Invoke(Model model, ref bool state)
|
||||
{
|
||||
var value = new Ref<bool>(state);
|
||||
Invoke(this, model, value);
|
||||
state = value;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using Glamourer.Interop.Structs;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
|
@ -14,7 +13,8 @@ namespace Glamourer.Events;
|
|||
/// <item>Parameter is the model values to change the weapon to. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class WeaponLoading : EventWrapper<Action<Actor, EquipSlot, Ref<CharacterWeapon>>, WeaponLoading.Priority>
|
||||
public sealed class WeaponLoading()
|
||||
: EventWrapperRef3<Actor, EquipSlot, CharacterWeapon, WeaponLoading.Priority>(nameof(WeaponLoading))
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
@ -24,15 +24,4 @@ public sealed class WeaponLoading : EventWrapper<Action<Actor, EquipSlot, Ref<Ch
|
|||
/// <seealso cref="Automation.AutoDesignApplier.OnWeaponLoading"/>
|
||||
AutoDesignApplier = -1,
|
||||
}
|
||||
|
||||
public WeaponLoading()
|
||||
: base(nameof(WeaponLoading))
|
||||
{ }
|
||||
|
||||
public void Invoke(Actor actor, EquipSlot slot, ref CharacterWeapon weapon)
|
||||
{
|
||||
var value = new Ref<CharacterWeapon>(weapon);
|
||||
Invoke(this, actor, slot, value);
|
||||
weapon = value;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using Glamourer.Interop.Structs;
|
||||
using OtterGui.Classes;
|
||||
|
||||
|
|
@ -11,22 +10,11 @@ namespace Glamourer.Events;
|
|||
/// <item>Parameter is the new state. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class WeaponVisibilityChanged : EventWrapper<Action<Actor, Ref<bool>>, WeaponVisibilityChanged.Priority>
|
||||
public sealed class WeaponVisibilityChanged() : EventWrapperRef2<Actor, bool, WeaponVisibilityChanged.Priority>(nameof(WeaponVisibilityChanged))
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="State.StateListener.OnWeaponVisibilityChange"/>
|
||||
StateListener = 0,
|
||||
}
|
||||
|
||||
public WeaponVisibilityChanged()
|
||||
: base(nameof(WeaponVisibilityChanged))
|
||||
{ }
|
||||
|
||||
public void Invoke(Actor actor, ref bool state)
|
||||
{
|
||||
var value = new Ref<bool>(state);
|
||||
Invoke(this, actor, value);
|
||||
state = value;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ using Glamourer.Gui;
|
|||
using Glamourer.Interop;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.State;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Services;
|
||||
|
|
@ -34,6 +33,8 @@ public class Glamourer : IDalamudPlugin
|
|||
{
|
||||
_services = ServiceManagerA.CreateProvider(pluginInterface, Log);
|
||||
Messager = _services.GetService<MessageService>();
|
||||
_services.EnsureRequiredServices();
|
||||
|
||||
_services.GetService<VisorService>();
|
||||
_services.GetService<WeaponService>();
|
||||
_services.GetService<ScalingService>();
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ namespace Glamourer.Interop;
|
|||
/// Changes in Race, body type or Gender are probably ignored.
|
||||
/// This operates on draw objects, not game objects.
|
||||
/// </summary>
|
||||
public unsafe class ChangeCustomizeService : EventWrapper<Action<Model, Ref<CustomizeArray>>, ChangeCustomizeService.Priority>
|
||||
public unsafe class ChangeCustomizeService : EventWrapperRef2<Model, CustomizeArray, ChangeCustomizeService.Priority>
|
||||
{
|
||||
private readonly PenumbraReloaded _penumbraReloaded;
|
||||
private readonly IGameInteropProvider _interop;
|
||||
|
|
@ -79,11 +79,7 @@ public unsafe class ChangeCustomizeService : EventWrapper<Action<Model, Ref<Cust
|
|||
private bool ChangeCustomizeDetour(Human* human, byte* data, byte skipEquipment)
|
||||
{
|
||||
if (!InUpdate.InMethod)
|
||||
{
|
||||
var customize = new Ref<CustomizeArray>(*(CustomizeArray*)data);
|
||||
Invoke(this, (Model)human, customize);
|
||||
*(CustomizeArray*)data = customize.Value;
|
||||
}
|
||||
Invoke(human, ref *(CustomizeArray*)data);
|
||||
|
||||
return _changeCustomizeHook.Original(human, data, skipEquipment);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
|
|
@ -15,10 +14,10 @@ namespace Glamourer.Interop;
|
|||
/// <list type="number">
|
||||
/// <item>Parameter is the model with an update. </item>
|
||||
/// <item>Parameter is the equipment slot changed. </item>
|
||||
/// <item>Parameter is the whether the crest will be shown. </item>
|
||||
/// <item>Parameter is whether the crest will be shown. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed unsafe class CrestService : EventWrapper<Action<Actor, CrestFlag, Ref<bool>>, CrestService.Priority>
|
||||
public sealed unsafe class CrestService : EventWrapperRef3<Actor, CrestFlag, bool, CrestService.Priority>
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
@ -72,9 +71,9 @@ public sealed unsafe class CrestService : EventWrapper<Action<Actor, CrestFlag,
|
|||
var actor = (Actor)character;
|
||||
foreach (var slot in CrestExtensions.AllRelevantSet)
|
||||
{
|
||||
var newValue = new Ref<bool>(((CrestFlag)crestFlags).HasFlag(slot));
|
||||
Invoke(this, actor, slot, newValue);
|
||||
crestFlags = (byte)(newValue.Value ? crestFlags | (byte)slot : crestFlags & (byte)~slot);
|
||||
var newValue = ((CrestFlag)crestFlags).HasFlag(slot);
|
||||
Invoke(actor, slot, ref newValue);
|
||||
crestFlags = (byte)(newValue ? crestFlags | (byte)slot : crestFlags & (byte)~slot);
|
||||
}
|
||||
|
||||
Glamourer.Log.Verbose(
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ public static class ServiceManagerA
|
|||
{
|
||||
public static ServiceManager CreateProvider(DalamudPluginInterface pi, Logger log)
|
||||
{
|
||||
EventWrapper.ChangeLogger(log);
|
||||
EventWrapperBase.ChangeLogger(log);
|
||||
var services = new ServiceManager(log)
|
||||
.AddExistingService(log)
|
||||
.AddMeta()
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ public class StateListener : IDisposable
|
|||
ProtectRestrictedGear(equipDataPtr, customize.Race, customize.Gender);
|
||||
}
|
||||
|
||||
private unsafe void OnCustomizeChange(Model model, Ref<CustomizeArray> customize)
|
||||
private unsafe void OnCustomizeChange(Model model, ref CustomizeArray customize)
|
||||
{
|
||||
if (!model.IsHuman)
|
||||
return;
|
||||
|
|
@ -151,7 +151,7 @@ public class StateListener : IDisposable
|
|||
|| !_manager.TryGetValue(identifier, out var state))
|
||||
return;
|
||||
|
||||
UpdateCustomize(actor, state, ref customize.Value, false);
|
||||
UpdateCustomize(actor, state, ref customize, false);
|
||||
}
|
||||
|
||||
private void UpdateCustomize(Actor actor, ActorState state, ref CustomizeArray customize, bool checkTransform)
|
||||
|
|
@ -199,7 +199,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 OnSlotUpdating(Model model, EquipSlot slot, ref CharacterArmor armor, ref ulong returnValue)
|
||||
{
|
||||
var actor = _penumbra.GameObjectFromDrawObject(model);
|
||||
if (_condition[ConditionFlag.CreatingCharacter] && actor.Index >= ObjectIndex.CutsceneStart)
|
||||
|
|
@ -212,16 +212,16 @@ public class StateListener : IDisposable
|
|||
if (actor.Identifier(_actors, out var identifier)
|
||||
&& _manager.TryGetValue(identifier, out var state))
|
||||
{
|
||||
HandleEquipSlot(actor, state, slot, ref armor.Value);
|
||||
HandleEquipSlot(actor, state, slot, ref armor);
|
||||
locked = state[slot, false] is StateChanged.Source.Ipc;
|
||||
}
|
||||
|
||||
_funModule.ApplyFunToSlot(actor, ref armor.Value, slot);
|
||||
_funModule.ApplyFunToSlot(actor, ref armor, slot);
|
||||
if (!_config.UseRestrictedGearProtection || locked)
|
||||
return;
|
||||
|
||||
var customize = model.GetCustomize();
|
||||
(_, armor.Value) = _items.RestrictedGear.ResolveRestricted(armor, slot, customize.Race, customize.Gender);
|
||||
(_, armor) = _items.RestrictedGear.ResolveRestricted(armor, slot, customize.Race, customize.Gender);
|
||||
}
|
||||
|
||||
private void OnMovedEquipment((EquipSlot, uint, StainId)[] items)
|
||||
|
|
@ -264,20 +264,20 @@ public class StateListener : IDisposable
|
|||
/// Update base data, apply or update model data.
|
||||
/// Verify consistent weapon types.
|
||||
/// </summary>
|
||||
private void OnWeaponLoading(Actor actor, EquipSlot slot, Ref<CharacterWeapon> weapon)
|
||||
private void OnWeaponLoading(Actor actor, EquipSlot slot, ref CharacterWeapon weapon)
|
||||
{
|
||||
if (_condition[ConditionFlag.CreatingCharacter] && actor.Index >= ObjectIndex.CutsceneStart)
|
||||
return;
|
||||
|
||||
// Fist weapon gauntlet hack.
|
||||
if (slot is EquipSlot.OffHand && weapon.Value.Variant == 0 && weapon.Value.Weapon.Id != 0 && _lastFistOffhand.Weapon.Id != 0)
|
||||
weapon.Value = _lastFistOffhand;
|
||||
if (slot is EquipSlot.OffHand && weapon.Variant == 0 && weapon.Weapon.Id != 0 && _lastFistOffhand.Weapon.Id != 0)
|
||||
weapon = _lastFistOffhand;
|
||||
|
||||
if (!actor.Identifier(_actors, out var identifier)
|
||||
|| !_manager.TryGetValue(identifier, out var state))
|
||||
return;
|
||||
|
||||
ref var actorWeapon = ref weapon.Value;
|
||||
ref var actorWeapon = ref weapon;
|
||||
var baseType = state.BaseData.Item(slot).Type;
|
||||
var apply = false;
|
||||
switch (UpdateBaseData(actor, state, slot, actorWeapon))
|
||||
|
|
@ -311,25 +311,16 @@ public class StateListener : IDisposable
|
|||
}
|
||||
|
||||
// Fist Weapon Offhand hack.
|
||||
if (slot is EquipSlot.MainHand && weapon.Value.Skeleton.Id is > 1600 and < 1651)
|
||||
_lastFistOffhand = new CharacterWeapon((PrimaryId)(weapon.Value.Skeleton.Id + 50), weapon.Value.Weapon, weapon.Value.Variant,
|
||||
weapon.Value.Stain);
|
||||
if (slot is EquipSlot.MainHand && weapon.Skeleton.Id is > 1600 and < 1651)
|
||||
_lastFistOffhand = new CharacterWeapon((PrimaryId)(weapon.Skeleton.Id + 50), weapon.Weapon, weapon.Variant,
|
||||
weapon.Stain);
|
||||
|
||||
_funModule.ApplyFunToWeapon(actor, ref weapon.Value, slot);
|
||||
_funModule.ApplyFunToWeapon(actor, ref weapon, slot);
|
||||
}
|
||||
|
||||
/// <summary> Update base data for a single changed equipment slot. </summary>
|
||||
private UpdateState UpdateBaseData(Actor actor, ActorState state, EquipSlot slot, CharacterArmor armor)
|
||||
{
|
||||
bool FistWeaponGauntletHack()
|
||||
{
|
||||
if (slot is not EquipSlot.Hands)
|
||||
return false;
|
||||
|
||||
var offhand = actor.GetOffhand();
|
||||
return offhand.Variant == 0 && offhand.Weapon.Id != 0 && armor.Set.Id == offhand.Weapon.Id;
|
||||
}
|
||||
|
||||
var actorArmor = actor.GetArmor(slot);
|
||||
var fistWeapon = FistWeaponGauntletHack();
|
||||
|
||||
|
|
@ -373,6 +364,15 @@ public class StateListener : IDisposable
|
|||
}
|
||||
|
||||
return change;
|
||||
|
||||
bool FistWeaponGauntletHack()
|
||||
{
|
||||
if (slot is not EquipSlot.Hands)
|
||||
return false;
|
||||
|
||||
var offhand = actor.GetOffhand();
|
||||
return offhand.Variant == 0 && offhand.Weapon.Id != 0 && armor.Set.Id == offhand.Weapon.Id;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Handle a full equip slot update for base data and model data. </summary>
|
||||
|
|
@ -406,7 +406,7 @@ public class StateListener : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
private void OnCrestChange(Actor actor, CrestFlag slot, Ref<bool> value)
|
||||
private void OnCrestChange(Actor actor, CrestFlag slot, ref bool value)
|
||||
{
|
||||
if (_condition[ConditionFlag.CreatingCharacter] && actor.Index >= ObjectIndex.CutsceneStart)
|
||||
return;
|
||||
|
|
@ -415,17 +415,17 @@ public class StateListener : IDisposable
|
|||
|| !_manager.TryGetValue(identifier, out var state))
|
||||
return;
|
||||
|
||||
switch (UpdateBaseCrest(actor, state, slot, value.Value))
|
||||
switch (UpdateBaseCrest(actor, state, slot, value))
|
||||
{
|
||||
case UpdateState.Change:
|
||||
if (state[slot] is not StateChanged.Source.Fixed and not StateChanged.Source.Ipc)
|
||||
_manager.ChangeCrest(state, slot, state.BaseData.Crest(slot), StateChanged.Source.Game);
|
||||
else
|
||||
value.Value = state.ModelData.Crest(slot);
|
||||
value = state.ModelData.Crest(slot);
|
||||
break;
|
||||
case UpdateState.NoChange:
|
||||
case UpdateState.HatHack:
|
||||
value.Value = state.ModelData.Crest(slot);
|
||||
value = state.ModelData.Crest(slot);
|
||||
break;
|
||||
case UpdateState.Transformed: break;
|
||||
}
|
||||
|
|
@ -540,7 +540,7 @@ public class StateListener : IDisposable
|
|||
}
|
||||
|
||||
/// <summary> Handle visor state changes made by the game. </summary>
|
||||
private void OnVisorChange(Model model, Ref<bool> value)
|
||||
private void OnVisorChange(Model model, ref bool value)
|
||||
{
|
||||
// Skip updates when in customize update.
|
||||
if (ChangeCustomizeService.InUpdate.InMethod)
|
||||
|
|
@ -565,19 +565,19 @@ public class StateListener : IDisposable
|
|||
// if base state changed, either overwrite the actual value if we have fixed values,
|
||||
// or overwrite the stored model state with the new one.
|
||||
if (state[ActorState.MetaIndex.VisorState] is StateChanged.Source.Fixed or StateChanged.Source.Ipc)
|
||||
value.Value = state.ModelData.IsVisorToggled();
|
||||
value = state.ModelData.IsVisorToggled();
|
||||
else
|
||||
_manager.ChangeVisorState(state, value, StateChanged.Source.Game);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if base state did not change, overwrite the value with the model state one.
|
||||
value.Value = state.ModelData.IsVisorToggled();
|
||||
value = state.ModelData.IsVisorToggled();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Handle Hat Visibility changes. These act on the game object. </summary>
|
||||
private void OnHeadGearVisibilityChange(Actor actor, Ref<bool> value)
|
||||
private void OnHeadGearVisibilityChange(Actor actor, ref bool value)
|
||||
{
|
||||
if (_condition[ConditionFlag.CreatingCharacter] && actor.Index >= ObjectIndex.CutsceneStart)
|
||||
return;
|
||||
|
|
@ -598,19 +598,19 @@ public class StateListener : IDisposable
|
|||
// if base state changed, either overwrite the actual value if we have fixed values,
|
||||
// or overwrite the stored model state with the new one.
|
||||
if (state[ActorState.MetaIndex.HatState] is StateChanged.Source.Fixed or StateChanged.Source.Ipc)
|
||||
value.Value = state.ModelData.IsHatVisible();
|
||||
value = state.ModelData.IsHatVisible();
|
||||
else
|
||||
_manager.ChangeHatState(state, value, StateChanged.Source.Game);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if base state did not change, overwrite the value with the model state one.
|
||||
value.Value = state.ModelData.IsHatVisible();
|
||||
value = state.ModelData.IsHatVisible();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Handle Weapon Visibility changes. These act on the game object. </summary>
|
||||
private void OnWeaponVisibilityChange(Actor actor, Ref<bool> value)
|
||||
private void OnWeaponVisibilityChange(Actor actor, ref bool value)
|
||||
{
|
||||
if (_condition[ConditionFlag.CreatingCharacter] && actor.Index >= ObjectIndex.CutsceneStart)
|
||||
return;
|
||||
|
|
@ -631,14 +631,14 @@ public class StateListener : IDisposable
|
|||
// if base state changed, either overwrite the actual value if we have fixed values,
|
||||
// or overwrite the stored model state with the new one.
|
||||
if (state[ActorState.MetaIndex.WeaponState] is StateChanged.Source.Fixed or StateChanged.Source.Ipc)
|
||||
value.Value = state.ModelData.IsWeaponVisible();
|
||||
value = state.ModelData.IsWeaponVisible();
|
||||
else
|
||||
_manager.ChangeWeaponState(state, value, StateChanged.Source.Game);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if base state did not change, overwrite the value with the model state one.
|
||||
value.Value = state.ModelData.IsWeaponVisible();
|
||||
value = state.ModelData.IsWeaponVisible();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -476,7 +476,7 @@ public class StateManager(
|
|||
actors = ApplyAll(state, redraw, true);
|
||||
Glamourer.Log.Verbose(
|
||||
$"Reset entire state of {state.Identifier.Incognito(null)} to game base. [Affecting {actors.ToLazyString("nothing")}.]");
|
||||
_event.Invoke(StateChanged.Type.Reset, StateChanged.Source.Manual, state, actors);
|
||||
_event.Invoke(StateChanged.Type.Reset, StateChanged.Source.Manual, state, actors, null);
|
||||
}
|
||||
|
||||
public void ResetStateFixed(ActorState state, uint key = 0)
|
||||
|
|
|
|||
2
OtterGui
2
OtterGui
|
|
@ -1 +1 @@
|
|||
Subproject commit e58c3c1240cda9d2d2b54f5ab7b8c729c1251fd4
|
||||
Subproject commit e4a82619332aade2748a381956a1ab8934de6211
|
||||
Loading…
Add table
Add a link
Reference in a new issue