mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2026-02-13 19:27:43 +01:00
Revamp, temp state.
This commit is contained in:
parent
358e33346f
commit
cc09cced61
22 changed files with 365 additions and 298 deletions
|
|
@ -1,13 +1,12 @@
|
|||
using System.Linq;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
|
|
@ -17,30 +16,9 @@ namespace Glamourer.State;
|
|||
/// This class applies changes made to state to actual objects in the game.
|
||||
/// It handles applying those changes as well as redrawing the actor if necessary.
|
||||
/// </summary>
|
||||
public class StateApplier
|
||||
public class StateApplier(UpdateSlotService _updateSlot, VisorService _visor, WeaponService _weapon, ChangeCustomizeService _changeCustomize,
|
||||
ItemManager _items, PenumbraService _penumbra, MetaService _metaService, ObjectManager _objects, CrestService _crests)
|
||||
{
|
||||
private readonly PenumbraService _penumbra;
|
||||
private readonly UpdateSlotService _updateSlot;
|
||||
private readonly VisorService _visor;
|
||||
private readonly WeaponService _weapon;
|
||||
private readonly MetaService _metaService;
|
||||
private readonly ChangeCustomizeService _changeCustomize;
|
||||
private readonly ItemManager _items;
|
||||
private readonly ObjectManager _objects;
|
||||
|
||||
public StateApplier(UpdateSlotService updateSlot, VisorService visor, WeaponService weapon, ChangeCustomizeService changeCustomize,
|
||||
ItemManager items, PenumbraService penumbra, MetaService metaService, ObjectManager objects)
|
||||
{
|
||||
_updateSlot = updateSlot;
|
||||
_visor = visor;
|
||||
_weapon = weapon;
|
||||
_changeCustomize = changeCustomize;
|
||||
_items = items;
|
||||
_penumbra = penumbra;
|
||||
_metaService = metaService;
|
||||
_objects = objects;
|
||||
}
|
||||
|
||||
/// <summary> Simply force a redraw regardless of conditions. </summary>
|
||||
public void ForceRedraw(ActorData data)
|
||||
{
|
||||
|
|
@ -279,6 +257,22 @@ public class StateApplier
|
|||
return data;
|
||||
}
|
||||
|
||||
/// <summary> Change the crest state on actors. </summary>
|
||||
public void ChangeCrests(ActorData data, CrestFlag flags)
|
||||
{
|
||||
foreach (var actor in data.Objects.Where(a => a.IsCharacter))
|
||||
_crests.UpdateCrests(actor, flags);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ChangeCrests(ActorData, CrestFlag)"/>
|
||||
public ActorData ChangeCrests(ActorState state, bool apply)
|
||||
{
|
||||
var data = GetData(state);
|
||||
if (apply)
|
||||
ChangeCrests(data, state.ModelData.CrestVisibility);
|
||||
return data;
|
||||
}
|
||||
|
||||
private ActorData GetData(ActorState state)
|
||||
{
|
||||
_objects.Update();
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using Dalamud.Plugin.Services;
|
|||
using Glamourer.Customization;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
|
@ -197,6 +198,18 @@ public class StateEditor
|
|||
return true;
|
||||
}
|
||||
|
||||
/// <summary> Change the crest of an equipment piece. </summary>
|
||||
public bool ChangeCrest(ActorState state, CrestFlag slot, bool crest, StateChanged.Source source, out bool oldCrest, uint key = 0)
|
||||
{
|
||||
oldCrest = state.ModelData.Crest(slot);
|
||||
if (!state.CanUnlock(key))
|
||||
return false;
|
||||
|
||||
state.ModelData.SetCrest(slot, crest);
|
||||
state[slot] = source;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool ChangeMetaState(ActorState state, ActorState.MetaIndex index, bool value, StateChanged.Source source, out bool oldValue,
|
||||
uint key = 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ using Penumbra.GameData.Structs;
|
|||
using System;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Structs;
|
||||
|
||||
namespace Glamourer.State;
|
||||
|
||||
|
|
@ -42,6 +43,7 @@ public class StateListener : IDisposable
|
|||
private readonly MovedEquipment _movedEquipment;
|
||||
private readonly GPoseService _gPose;
|
||||
private readonly ChangeCustomizeService _changeCustomizeService;
|
||||
private readonly CrestService _crestService;
|
||||
private readonly ICondition _condition;
|
||||
|
||||
private ActorIdentifier _creatingIdentifier = ActorIdentifier.Invalid;
|
||||
|
|
@ -52,7 +54,7 @@ public class StateListener : IDisposable
|
|||
SlotUpdating slotUpdating, WeaponLoading weaponLoading, VisorStateChanged visorState, WeaponVisibilityChanged weaponVisibility,
|
||||
HeadGearVisibilityChanged headGearVisibility, AutoDesignApplier autoDesignApplier, FunModule funModule, HumanModelList humans,
|
||||
StateApplier applier, MovedEquipment movedEquipment, ObjectManager objects, GPoseService gPose,
|
||||
ChangeCustomizeService changeCustomizeService, CustomizationService customizations, ICondition condition)
|
||||
ChangeCustomizeService changeCustomizeService, CustomizationService customizations, ICondition condition, CrestService crestService)
|
||||
{
|
||||
_manager = manager;
|
||||
_items = items;
|
||||
|
|
@ -74,6 +76,7 @@ public class StateListener : IDisposable
|
|||
_changeCustomizeService = changeCustomizeService;
|
||||
_customizations = customizations;
|
||||
_condition = condition;
|
||||
_crestService = crestService;
|
||||
Subscribe();
|
||||
}
|
||||
|
||||
|
|
@ -405,6 +408,58 @@ public class StateListener : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
private void OnCrestChange(Actor actor, CrestFlag slot, Ref<bool> value)
|
||||
{
|
||||
if (_condition[ConditionFlag.CreatingCharacter] && actor.Index >= ObjectIndex.CutsceneStart)
|
||||
return;
|
||||
|
||||
if (!actor.Identifier(_actors.AwaitedService, out var identifier)
|
||||
|| !_manager.TryGetValue(identifier, out var state))
|
||||
return;
|
||||
|
||||
switch (UpdateBaseCrest(actor, state, slot, value.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);
|
||||
break;
|
||||
case UpdateState.NoChange:
|
||||
case UpdateState.HatHack:
|
||||
value.Value = state.ModelData.Crest(slot);
|
||||
break;
|
||||
case UpdateState.Transformed: break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnModelCrestSetup(Model model, CrestFlag slot, ref bool value)
|
||||
{
|
||||
var actor = _penumbra.GameObjectFromDrawObject(model);
|
||||
if (_condition[ConditionFlag.CreatingCharacter] && actor.Index >= ObjectIndex.CutsceneStart)
|
||||
return;
|
||||
|
||||
if (!actor.Identifier(_actors.AwaitedService, out var identifier)
|
||||
|| !_manager.TryGetValue(identifier, out var state))
|
||||
return;
|
||||
|
||||
value = state.ModelData.Crest(slot);
|
||||
}
|
||||
|
||||
private static UpdateState UpdateBaseCrest(Actor actor, ActorState state, CrestFlag slot, bool visible)
|
||||
{
|
||||
if (actor.IsTransformed)
|
||||
return UpdateState.Transformed;
|
||||
|
||||
if (state.BaseData.Crest(slot) != visible)
|
||||
{
|
||||
state.BaseData.SetCrest(slot, visible);
|
||||
return UpdateState.Change;
|
||||
}
|
||||
|
||||
return UpdateState.NoChange;
|
||||
}
|
||||
|
||||
/// <summary> Update base data for a single changed weapon slot. </summary>
|
||||
private unsafe UpdateState UpdateBaseData(Actor actor, ActorState state, EquipSlot slot, CharacterWeapon weapon)
|
||||
{
|
||||
|
|
@ -616,6 +671,8 @@ public class StateListener : IDisposable
|
|||
_headGearVisibility.Subscribe(OnHeadGearVisibilityChange, HeadGearVisibilityChanged.Priority.StateListener);
|
||||
_weaponVisibility.Subscribe(OnWeaponVisibilityChange, WeaponVisibilityChanged.Priority.StateListener);
|
||||
_changeCustomizeService.Subscribe(OnCustomizeChange, ChangeCustomizeService.Priority.StateListener);
|
||||
_crestService.Subscribe(OnCrestChange, CrestService.Priority.StateListener);
|
||||
_crestService.ModelCrestSetup += OnModelCrestSetup;
|
||||
}
|
||||
|
||||
private void Unsubscribe()
|
||||
|
|
@ -629,6 +686,8 @@ public class StateListener : IDisposable
|
|||
_headGearVisibility.Unsubscribe(OnHeadGearVisibilityChange);
|
||||
_weaponVisibility.Unsubscribe(OnWeaponVisibilityChange);
|
||||
_changeCustomizeService.Unsubscribe(OnCustomizeChange);
|
||||
_crestService.Unsubscribe(OnCrestChange);
|
||||
_crestService.ModelCrestSetup -= OnModelCrestSetup;
|
||||
}
|
||||
|
||||
private void OnCreatedCharacterBase(nint gameObject, string _, nint drawObject)
|
||||
|
|
@ -639,8 +698,9 @@ public class StateListener : IDisposable
|
|||
if (_creatingState == null)
|
||||
return;
|
||||
|
||||
_applier.ChangeHatState(new ActorData(gameObject, _creatingIdentifier.ToName()), _creatingState.ModelData.IsHatVisible());
|
||||
_applier.ChangeWeaponState(new ActorData(gameObject, _creatingIdentifier.ToName()), _creatingState.ModelData.IsWeaponVisible());
|
||||
_applier.ChangeWetness(new ActorData(gameObject, _creatingIdentifier.ToName()), _creatingState.ModelData.IsWet());
|
||||
var data = new ActorData(gameObject, _creatingIdentifier.ToName());
|
||||
_applier.ChangeHatState(data, _creatingState.ModelData.IsHatVisible());
|
||||
_applier.ChangeWeaponState(data, _creatingState.ModelData.IsWeaponVisible());
|
||||
_applier.ChangeWetness(data, _creatingState.ModelData.IsWet());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using Glamourer.Events;
|
|||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
|
@ -17,32 +18,12 @@ using Penumbra.GameData.Structs;
|
|||
|
||||
namespace Glamourer.State;
|
||||
|
||||
public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
||||
public class StateManager(ActorService _actors, ItemManager _items, StateChanged _event, StateApplier _applier, StateEditor _editor,
|
||||
HumanModelList _humans, ICondition _condition, IClientState _clientState)
|
||||
: IReadOnlyDictionary<ActorIdentifier, ActorState>
|
||||
{
|
||||
private readonly ActorService _actors;
|
||||
private readonly ItemManager _items;
|
||||
private readonly HumanModelList _humans;
|
||||
private readonly StateChanged _event;
|
||||
private readonly StateApplier _applier;
|
||||
private readonly StateEditor _editor;
|
||||
private readonly ICondition _condition;
|
||||
private readonly IClientState _clientState;
|
||||
|
||||
private readonly Dictionary<ActorIdentifier, ActorState> _states = new();
|
||||
|
||||
public StateManager(ActorService actors, ItemManager items, StateChanged @event, StateApplier applier, StateEditor editor,
|
||||
HumanModelList humans, ICondition condition, IClientState clientState)
|
||||
{
|
||||
_actors = actors;
|
||||
_items = items;
|
||||
_event = @event;
|
||||
_applier = applier;
|
||||
_editor = editor;
|
||||
_humans = humans;
|
||||
_condition = condition;
|
||||
_clientState = clientState;
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<ActorIdentifier, ActorState>> GetEnumerator()
|
||||
=> _states.GetEnumerator();
|
||||
|
||||
|
|
@ -83,7 +64,7 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
|||
// and the draw objects data for the model data (where possible).
|
||||
state = new ActorState(identifier)
|
||||
{
|
||||
ModelData = FromActor(actor, true, false),
|
||||
ModelData = FromActor(actor, true, false),
|
||||
BaseData = FromActor(actor, false, false),
|
||||
LastJob = (byte)(actor.IsCharacter ? actor.AsCharacter->CharacterData.ClassJob : 0),
|
||||
LastTerritory = _clientState.TerritoryType,
|
||||
|
|
@ -162,6 +143,9 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
|||
|
||||
// Visor state is a flag on the game object, but we can see the actual state on the draw object.
|
||||
ret.SetVisor(VisorService.GetVisorState(model));
|
||||
|
||||
foreach (var slot in CrestExtensions.AllRelevantSet)
|
||||
ret.SetCrest(slot, CrestService.GetModelCrest(actor, slot));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -180,6 +164,9 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
|||
off = actor.GetOffhand();
|
||||
FistWeaponHack(ref ret, ref main, ref off);
|
||||
ret.SetVisor(actor.AsCharacter->DrawData.IsVisorToggled);
|
||||
|
||||
foreach (var slot in CrestExtensions.AllRelevantSet)
|
||||
ret.SetCrest(slot, actor.GetCrest(slot));
|
||||
}
|
||||
|
||||
// Set the weapons regardless of source.
|
||||
|
|
@ -206,7 +193,7 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
|||
if (mainhand.Set.Id is < 1601 or >= 1651)
|
||||
return;
|
||||
|
||||
var gauntlets = _items.Identify(EquipSlot.Hands, offhand.Set, (Variant) offhand.Type.Id);
|
||||
var gauntlets = _items.Identify(EquipSlot.Hands, offhand.Set, (Variant)offhand.Type.Id);
|
||||
offhand.Set = (SetId)(mainhand.Set.Id + 50);
|
||||
offhand.Variant = mainhand.Variant;
|
||||
offhand.Type = mainhand.Type;
|
||||
|
|
@ -304,6 +291,18 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
|||
_event.Invoke(StateChanged.Type.Stain, source, state, actors, (old, stain, slot));
|
||||
}
|
||||
|
||||
/// <summary> Change the crest of an equipment piece. </summary>
|
||||
public void ChangeCrest(ActorState state, CrestFlag slot, bool crest, StateChanged.Source source, uint key = 0)
|
||||
{
|
||||
if (!_editor.ChangeCrest(state, slot, crest, source, out var old, key))
|
||||
return;
|
||||
|
||||
var actors = _applier.ChangeCrests(state, source is StateChanged.Source.Manual or StateChanged.Source.Ipc);
|
||||
Glamourer.Log.Verbose(
|
||||
$"Set {slot.ToLabel()} crest in state {state.Identifier.Incognito(null)} from {old} to {crest}. [Affecting {actors.ToLazyString("nothing")}.]");
|
||||
_event.Invoke(StateChanged.Type.Crest, source, state, actors, (old, crest, slot));
|
||||
}
|
||||
|
||||
/// <summary> Change hat visibility. </summary>
|
||||
public void ChangeHatState(ActorState state, bool value, StateChanged.Source source, uint key = 0)
|
||||
{
|
||||
|
|
@ -356,19 +355,8 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
|||
|
||||
public void ApplyDesign(DesignBase design, ActorState state, StateChanged.Source source, uint key = 0)
|
||||
{
|
||||
void HandleEquip(EquipSlot slot, bool applyPiece, bool applyStain)
|
||||
{
|
||||
var unused = (applyPiece, applyStain) switch
|
||||
{
|
||||
(false, false) => false,
|
||||
(true, false) => _editor.ChangeItem(state, slot, design.DesignData.Item(slot), source, out _, key),
|
||||
(false, true) => _editor.ChangeStain(state, slot, design.DesignData.Stain(slot), source, out _, key),
|
||||
(true, true) => _editor.ChangeEquip(state, slot, design.DesignData.Item(slot), design.DesignData.Stain(slot), source, out _,
|
||||
out _, key),
|
||||
};
|
||||
}
|
||||
|
||||
if (!_editor.ChangeModelId(state, design.DesignData.ModelId, design.DesignData.Customize, design.GetDesignDataRef().GetEquipmentPtr(), source,
|
||||
if (!_editor.ChangeModelId(state, design.DesignData.ModelId, design.DesignData.Customize, design.GetDesignDataRef().GetEquipmentPtr(),
|
||||
source,
|
||||
out var oldModelId, key))
|
||||
return;
|
||||
|
||||
|
|
@ -393,12 +381,28 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
|||
|
||||
foreach (var slot in EquipSlotExtensions.FullSlots)
|
||||
HandleEquip(slot, design.DoApplyEquip(slot), design.DoApplyStain(slot));
|
||||
|
||||
foreach (var slot in CrestExtensions.AllRelevantSet.Where(design.DoApplyCrest))
|
||||
_editor.ChangeCrest(state, slot, design.DesignData.Crest(slot), source, out _, key);
|
||||
}
|
||||
|
||||
var actors = ApplyAll(state, redraw, false);
|
||||
Glamourer.Log.Verbose(
|
||||
$"Applied design to {state.Identifier.Incognito(null)}. [Affecting {actors.ToLazyString("nothing")}.]");
|
||||
_event.Invoke(StateChanged.Type.Design, state[ActorState.MetaIndex.Wetness], state, actors, design);
|
||||
return;
|
||||
|
||||
void HandleEquip(EquipSlot slot, bool applyPiece, bool applyStain)
|
||||
{
|
||||
var unused = (applyPiece, applyStain) switch
|
||||
{
|
||||
(false, false) => false,
|
||||
(true, false) => _editor.ChangeItem(state, slot, design.DesignData.Item(slot), source, out _, key),
|
||||
(false, true) => _editor.ChangeStain(state, slot, design.DesignData.Stain(slot), source, out _, key),
|
||||
(true, true) => _editor.ChangeEquip(state, slot, design.DesignData.Item(slot), design.DesignData.Stain(slot), source, out _,
|
||||
out _, key),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private ActorData ApplyAll(ActorState state, bool redraw, bool withLock)
|
||||
|
|
@ -430,6 +434,7 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
|||
_applier.ChangeHatState(actors, state.ModelData.IsHatVisible());
|
||||
_applier.ChangeWeaponState(actors, state.ModelData.IsWeaponVisible());
|
||||
_applier.ChangeVisor(actors, state.ModelData.IsVisorToggled());
|
||||
_applier.ChangeCrests(actors, state.ModelData.CrestVisibility);
|
||||
}
|
||||
|
||||
return actors;
|
||||
|
|
@ -453,10 +458,13 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
|||
state[slot, true] = StateChanged.Source.Game;
|
||||
state[slot, false] = StateChanged.Source.Game;
|
||||
}
|
||||
|
||||
|
||||
foreach (var type in Enum.GetValues<ActorState.MetaIndex>())
|
||||
state[type] = StateChanged.Source.Game;
|
||||
|
||||
foreach (var slot in CrestExtensions.AllRelevantSet)
|
||||
state[slot] = StateChanged.Source.Game;
|
||||
|
||||
var actors = ActorData.Invalid;
|
||||
if (source is StateChanged.Source.Manual or StateChanged.Source.Ipc)
|
||||
actors = ApplyAll(state, redraw, true);
|
||||
|
|
@ -491,6 +499,15 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
|||
}
|
||||
}
|
||||
|
||||
foreach (var slot in CrestExtensions.AllRelevantSet)
|
||||
{
|
||||
if (state[slot] is StateChanged.Source.Fixed)
|
||||
{
|
||||
state[slot] = StateChanged.Source.Game;
|
||||
state.ModelData.SetCrest(slot, state.BaseData.Crest(slot));
|
||||
}
|
||||
}
|
||||
|
||||
if (state[ActorState.MetaIndex.HatState] is StateChanged.Source.Fixed)
|
||||
{
|
||||
state[ActorState.MetaIndex.HatState] = StateChanged.Source.Game;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue