diff --git a/Glamourer/Automation/AutoDesignApplier.cs b/Glamourer/Automation/AutoDesignApplier.cs index 83ce3c4..90fb00d 100644 --- a/Glamourer/Automation/AutoDesignApplier.cs +++ b/Glamourer/Automation/AutoDesignApplier.cs @@ -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 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(); + } } } diff --git a/Glamourer/Designs/DesignManager.cs b/Glamourer/Designs/DesignManager.cs index b46e4e0..2d25cc2 100644 --- a/Glamourer/Designs/DesignManager.cs +++ b/Glamourer/Designs/DesignManager.cs @@ -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); } /// Whether an Undo for the given design is possible. @@ -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); } /// Rename a design. @@ -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; } diff --git a/Glamourer/Events/AutomationChanged.cs b/Glamourer/Events/AutomationChanged.cs index 4a35e4b..1d45084 100644 --- a/Glamourer/Events/AutomationChanged.cs +++ b/Glamourer/Events/AutomationChanged.cs @@ -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; /// Parameter is additional data depending on the type of change. /// /// -public sealed class AutomationChanged : EventWrapper, - AutomationChanged.Priority> +public sealed class AutomationChanged() + : EventWrapper(nameof(AutomationChanged)) { public enum Type { @@ -65,11 +64,4 @@ public sealed class AutomationChanged : EventWrapper AutoDesignApplier, } - - public AutomationChanged() - : base(nameof(AutomationChanged)) - { } - - public void Invoke(Type type, AutoDesignSet? set, object? data) - => Invoke(this, type, set, data); } diff --git a/Glamourer/Events/DesignChanged.cs b/Glamourer/Events/DesignChanged.cs index c528fde..76724eb 100644 --- a/Glamourer/Events/DesignChanged.cs +++ b/Glamourer/Events/DesignChanged.cs @@ -1,4 +1,3 @@ -using System; using Glamourer.Designs; using Glamourer.Gui; using OtterGui.Classes; @@ -13,7 +12,8 @@ namespace Glamourer.Events; /// Parameter is any additional data depending on the type of change. /// /// -public sealed class DesignChanged : EventWrapper, DesignChanged.Priority> +public sealed class DesignChanged() + : EventWrapper(nameof(DesignChanged)) { public enum Type { @@ -98,11 +98,4 @@ public sealed class DesignChanged : EventWrapper DesignCombo = -2, } - - public DesignChanged() - : base(nameof(DesignChanged)) - { } - - public void Invoke(Type type, Design design, object? data = null) - => Invoke(this, type, design, data); } diff --git a/Glamourer/Events/EquippedGearset.cs b/Glamourer/Events/EquippedGearset.cs index a8fafff..c4252eb 100644 --- a/Glamourer/Events/EquippedGearset.cs +++ b/Glamourer/Events/EquippedGearset.cs @@ -1,4 +1,3 @@ -using System; using OtterGui.Classes; namespace Glamourer.Events; @@ -13,18 +12,12 @@ namespace Glamourer.Events; /// Parameter is the job id of the associated job. /// /// -public sealed class EquippedGearset : EventWrapper, EquippedGearset.Priority> +public sealed class EquippedGearset() + : EventWrapper(nameof(EquippedGearset)) { public enum Priority { /// 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); } diff --git a/Glamourer/Events/GPoseService.cs b/Glamourer/Events/GPoseService.cs index 7403754..a87914e 100644 --- a/Glamourer/Events/GPoseService.cs +++ b/Glamourer/Events/GPoseService.cs @@ -5,7 +5,7 @@ using OtterGui.Classes; namespace Glamourer.Events; -public sealed class GPoseService : EventWrapper, GPoseService.Priority> +public sealed class GPoseService : EventWrapper { private readonly IFramework _framework; private readonly IClientState _state; @@ -56,7 +56,7 @@ public sealed class GPoseService : EventWrapper, GPoseService.Prior return; InGPose = inGPose; - Invoke(this, InGPose); + Invoke(InGPose); var actions = InGPose ? _onEnter : _onLeave; foreach (var action in actions) { diff --git a/Glamourer/Events/HeadGearVisibilityChanged.cs b/Glamourer/Events/HeadGearVisibilityChanged.cs index d12cd69..91454b3 100644 --- a/Glamourer/Events/HeadGearVisibilityChanged.cs +++ b/Glamourer/Events/HeadGearVisibilityChanged.cs @@ -1,4 +1,3 @@ -using System; using Glamourer.Interop.Structs; using OtterGui.Classes; @@ -11,22 +10,12 @@ namespace Glamourer.Events; /// Parameter is the new state. /// /// -public sealed class HeadGearVisibilityChanged : EventWrapper>, HeadGearVisibilityChanged.Priority> +public sealed class HeadGearVisibilityChanged() + : EventWrapperRef2(nameof(HeadGearVisibilityChanged)) { public enum Priority { /// StateListener = 0, } - - public HeadGearVisibilityChanged() - : base(nameof(HeadGearVisibilityChanged)) - { } - - public void Invoke(Actor actor, ref bool state) - { - var value = new Ref(state); - Invoke(this, actor, value); - state = value; - } } diff --git a/Glamourer/Events/MovedEquipment.cs b/Glamourer/Events/MovedEquipment.cs index 4548575..53491f1 100644 --- a/Glamourer/Events/MovedEquipment.cs +++ b/Glamourer/Events/MovedEquipment.cs @@ -1,4 +1,3 @@ -using System; using OtterGui.Classes; using Penumbra.GameData.Enums; using Penumbra.GameData.Structs; @@ -11,18 +10,12 @@ namespace Glamourer.Events; /// Parameter is an array of slots updated and corresponding item ids and stains. /// /// -public sealed class MovedEquipment : EventWrapper, MovedEquipment.Priority> +public sealed class MovedEquipment() + : EventWrapper<(EquipSlot, uint, StainId)[], MovedEquipment.Priority>(nameof(MovedEquipment)) { public enum Priority { /// StateListener = 0, } - - public MovedEquipment() - : base(nameof(MovedEquipment)) - { } - - public void Invoke((EquipSlot, uint, StainId)[] items) - => Invoke(this, items); } diff --git a/Glamourer/Events/ObjectUnlocked.cs b/Glamourer/Events/ObjectUnlocked.cs index 7b8c120..b31fa3e 100644 --- a/Glamourer/Events/ObjectUnlocked.cs +++ b/Glamourer/Events/ObjectUnlocked.cs @@ -11,7 +11,8 @@ namespace Glamourer.Events; /// Parameter is the timestamp of the unlock. /// /// -public sealed class ObjectUnlocked : EventWrapper, ObjectUnlocked.Priority> +public sealed class ObjectUnlocked() + : EventWrapper(nameof(ObjectUnlocked)) { public enum Type { @@ -25,11 +26,4 @@ public sealed class ObjectUnlocked : EventWrapper Currently used as a hack to make the unlock table dirty in it. If anything else starts using this, rework. UnlockTable = 0, } - - public ObjectUnlocked() - : base(nameof(ObjectUnlocked)) - { } - - public void Invoke(Type type, uint id, DateTimeOffset timestamp) - => Invoke(this, type, id, timestamp); } diff --git a/Glamourer/Events/PenumbraReloaded.cs b/Glamourer/Events/PenumbraReloaded.cs index 40a2527..7df8b3f 100644 --- a/Glamourer/Events/PenumbraReloaded.cs +++ b/Glamourer/Events/PenumbraReloaded.cs @@ -1,4 +1,3 @@ -using System; using OtterGui.Classes; namespace Glamourer.Events; @@ -6,18 +5,12 @@ namespace Glamourer.Events; /// /// Triggered when Penumbra is reloaded. /// -public sealed class PenumbraReloaded : EventWrapper +public sealed class PenumbraReloaded() + : EventWrapper(nameof(PenumbraReloaded)) { public enum Priority { /// ChangeCustomizeService = 0, } - - public PenumbraReloaded() - : base(nameof(PenumbraReloaded)) - { } - - public void Invoke() - => Invoke(this); } diff --git a/Glamourer/Events/SlotUpdating.cs b/Glamourer/Events/SlotUpdating.cs index d83822b..ab6e2f9 100644 --- a/Glamourer/Events/SlotUpdating.cs +++ b/Glamourer/Events/SlotUpdating.cs @@ -15,24 +15,12 @@ namespace Glamourer.Events; /// Parameter is the return value the function should return, if it is ulong.MaxValue, the original will be called and returned. /// /// -public sealed class SlotUpdating : EventWrapper, Ref>, SlotUpdating.Priority> +public sealed class SlotUpdating() + : EventWrapperRef34(nameof(SlotUpdating)) { public enum Priority { /// StateListener = 0, } - - public SlotUpdating() - : base(nameof(SlotUpdating)) - { } - - public void Invoke(Model model, EquipSlot slot, ref CharacterArmor armor, ref ulong returnValue) - { - var value = new Ref(armor); - var @return = new Ref(returnValue); - Invoke(this, model, slot, value, @return); - armor = value; - returnValue = @return; - } } diff --git a/Glamourer/Events/StateChanged.cs b/Glamourer/Events/StateChanged.cs index e02a6d9..3045b98 100644 --- a/Glamourer/Events/StateChanged.cs +++ b/Glamourer/Events/StateChanged.cs @@ -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; /// Parameter is any additional data depending on the type of change. /// /// -public sealed class StateChanged : EventWrapper, StateChanged.Priority> +public sealed class StateChanged() + : EventWrapper(nameof(StateChanged)) { public enum Type { @@ -62,11 +61,4 @@ public sealed class StateChanged : EventWrapper Invoke(this, type, source, state, actors, data); } diff --git a/Glamourer/Events/TabSelected.cs b/Glamourer/Events/TabSelected.cs index f43fee0..82a6abb 100644 --- a/Glamourer/Events/TabSelected.cs +++ b/Glamourer/Events/TabSelected.cs @@ -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; /// Parameter is the design to select if the tab is the designs tab. /// /// -public sealed class TabSelected : EventWrapper, - TabSelected.Priority> +public sealed class TabSelected() + : EventWrapper(nameof(TabSelected)) { public enum Priority { @@ -23,11 +22,4 @@ public sealed class TabSelected : EventWrapper MainWindow = 1, } - - public TabSelected() - : base(nameof(TabSelected)) - { } - - public void Invoke(MainWindow.TabType type, Design? design) - => Invoke(this, type, design); } diff --git a/Glamourer/Events/VisorStateChanged.cs b/Glamourer/Events/VisorStateChanged.cs index 0cd83d1..d71eccd 100644 --- a/Glamourer/Events/VisorStateChanged.cs +++ b/Glamourer/Events/VisorStateChanged.cs @@ -1,4 +1,3 @@ -using System; using Glamourer.Interop.Structs; using OtterGui.Classes; @@ -12,22 +11,12 @@ namespace Glamourer.Events; /// Parameter is whether to call the original function. /// /// -public sealed class VisorStateChanged : EventWrapper>, VisorStateChanged.Priority> +public sealed class VisorStateChanged() + : EventWrapperRef2(nameof(VisorStateChanged)) { public enum Priority { /// StateListener = 0, } - - public VisorStateChanged() - : base(nameof(VisorStateChanged)) - { } - - public void Invoke(Model model, ref bool state) - { - var value = new Ref(state); - Invoke(this, model, value); - state = value; - } } diff --git a/Glamourer/Events/WeaponLoading.cs b/Glamourer/Events/WeaponLoading.cs index 1224e7f..41da2aa 100644 --- a/Glamourer/Events/WeaponLoading.cs +++ b/Glamourer/Events/WeaponLoading.cs @@ -1,4 +1,3 @@ -using System; using Glamourer.Interop.Structs; using OtterGui.Classes; using Penumbra.GameData.Enums; @@ -14,7 +13,8 @@ namespace Glamourer.Events; /// Parameter is the model values to change the weapon to. /// /// -public sealed class WeaponLoading : EventWrapper>, WeaponLoading.Priority> +public sealed class WeaponLoading() + : EventWrapperRef3(nameof(WeaponLoading)) { public enum Priority { @@ -24,15 +24,4 @@ public sealed class WeaponLoading : EventWrapper AutoDesignApplier = -1, } - - public WeaponLoading() - : base(nameof(WeaponLoading)) - { } - - public void Invoke(Actor actor, EquipSlot slot, ref CharacterWeapon weapon) - { - var value = new Ref(weapon); - Invoke(this, actor, slot, value); - weapon = value; - } } diff --git a/Glamourer/Events/WeaponVisibilityChanged.cs b/Glamourer/Events/WeaponVisibilityChanged.cs index 561c793..a94eabf 100644 --- a/Glamourer/Events/WeaponVisibilityChanged.cs +++ b/Glamourer/Events/WeaponVisibilityChanged.cs @@ -1,4 +1,3 @@ -using System; using Glamourer.Interop.Structs; using OtterGui.Classes; @@ -11,22 +10,11 @@ namespace Glamourer.Events; /// Parameter is the new state. /// /// -public sealed class WeaponVisibilityChanged : EventWrapper>, WeaponVisibilityChanged.Priority> +public sealed class WeaponVisibilityChanged() : EventWrapperRef2(nameof(WeaponVisibilityChanged)) { public enum Priority { /// StateListener = 0, } - - public WeaponVisibilityChanged() - : base(nameof(WeaponVisibilityChanged)) - { } - - public void Invoke(Actor actor, ref bool state) - { - var value = new Ref(state); - Invoke(this, actor, value); - state = value; - } } diff --git a/Glamourer/Glamourer.cs b/Glamourer/Glamourer.cs index 00b94bb..c9d76ef 100644 --- a/Glamourer/Glamourer.cs +++ b/Glamourer/Glamourer.cs @@ -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(); + _services.EnsureRequiredServices(); + _services.GetService(); _services.GetService(); _services.GetService(); diff --git a/Glamourer/Interop/ChangeCustomizeService.cs b/Glamourer/Interop/ChangeCustomizeService.cs index 947ce43..9acb418 100644 --- a/Glamourer/Interop/ChangeCustomizeService.cs +++ b/Glamourer/Interop/ChangeCustomizeService.cs @@ -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. /// -public unsafe class ChangeCustomizeService : EventWrapper>, ChangeCustomizeService.Priority> +public unsafe class ChangeCustomizeService : EventWrapperRef2 { private readonly PenumbraReloaded _penumbraReloaded; private readonly IGameInteropProvider _interop; @@ -79,11 +79,7 @@ public unsafe class ChangeCustomizeService : EventWrapper(*(CustomizeArray*)data); - Invoke(this, (Model)human, customize); - *(CustomizeArray*)data = customize.Value; - } + Invoke(human, ref *(CustomizeArray*)data); return _changeCustomizeHook.Original(human, data, skipEquipment); } diff --git a/Glamourer/Interop/CrestService.cs b/Glamourer/Interop/CrestService.cs index 7db9a59..7764573 100644 --- a/Glamourer/Interop/CrestService.cs +++ b/Glamourer/Interop/CrestService.cs @@ -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; /// /// Parameter is the model with an update. /// Parameter is the equipment slot changed. -/// Parameter is the whether the crest will be shown. +/// Parameter is whether the crest will be shown. /// /// -public sealed unsafe class CrestService : EventWrapper>, CrestService.Priority> +public sealed unsafe class CrestService : EventWrapperRef3 { public enum Priority { @@ -72,9 +71,9 @@ public sealed unsafe class CrestService : EventWrapper(((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( diff --git a/Glamourer/Services/ServiceManager.cs b/Glamourer/Services/ServiceManager.cs index db3922c..2f64cf8 100644 --- a/Glamourer/Services/ServiceManager.cs +++ b/Glamourer/Services/ServiceManager.cs @@ -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() diff --git a/Glamourer/State/StateListener.cs b/Glamourer/State/StateListener.cs index bbc519f..3651553 100644 --- a/Glamourer/State/StateListener.cs +++ b/Glamourer/State/StateListener.cs @@ -138,7 +138,7 @@ public class StateListener : IDisposable ProtectRestrictedGear(equipDataPtr, customize.Race, customize.Gender); } - private unsafe void OnCustomizeChange(Model model, Ref 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. /// - private void OnSlotUpdating(Model model, EquipSlot slot, Ref armor, Ref 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. /// - private void OnWeaponLoading(Actor actor, EquipSlot slot, Ref 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); } /// Update base data for a single changed equipment slot. 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; + } } /// Handle a full equip slot update for base data and model data. @@ -406,7 +406,7 @@ public class StateListener : IDisposable } } - private void OnCrestChange(Actor actor, CrestFlag slot, Ref 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 } /// Handle visor state changes made by the game. - private void OnVisorChange(Model model, Ref 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(); } } /// Handle Hat Visibility changes. These act on the game object. - private void OnHeadGearVisibilityChange(Actor actor, Ref 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(); } } /// Handle Weapon Visibility changes. These act on the game object. - private void OnWeaponVisibilityChange(Actor actor, Ref 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(); } } diff --git a/Glamourer/State/StateManager.cs b/Glamourer/State/StateManager.cs index dc83305..a3f1de6 100644 --- a/Glamourer/State/StateManager.cs +++ b/Glamourer/State/StateManager.cs @@ -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) diff --git a/OtterGui b/OtterGui index e58c3c1..e4a8261 160000 --- a/OtterGui +++ b/OtterGui @@ -1 +1 @@ -Subproject commit e58c3c1240cda9d2d2b54f5ab7b8c729c1251fd4 +Subproject commit e4a82619332aade2748a381956a1ab8934de6211