mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-16 05:34:25 +01:00
Add testing support for changing weapon types in gpose only.
This commit is contained in:
parent
89f2e78690
commit
73589adac9
6 changed files with 127 additions and 48 deletions
71
Glamourer/Events/GPoseService.cs
Normal file
71
Glamourer/Events/GPoseService.cs
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using Dalamud.Game;
|
||||
using OtterGui.Classes;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
|
||||
namespace Glamourer.Events;
|
||||
|
||||
public class GPoseService : EventWrapper<Action<bool>, GPoseService.Priority>
|
||||
{
|
||||
private readonly Framework _framework;
|
||||
|
||||
private readonly ConcurrentQueue<Action> _onLeave = new();
|
||||
private readonly ConcurrentQueue<Action> _onEnter = new();
|
||||
|
||||
public enum Priority
|
||||
{ }
|
||||
|
||||
public bool InGPose { get; private set; } = false;
|
||||
|
||||
public GPoseService(Framework framework)
|
||||
: base(nameof(GPoseService))
|
||||
{
|
||||
_framework = framework;
|
||||
_framework.Update += OnFramework;
|
||||
}
|
||||
|
||||
public new void Dispose()
|
||||
{
|
||||
_framework.Update -= OnFramework;
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
public void AddActionOnLeave(Action onLeave)
|
||||
{
|
||||
if (InGPose)
|
||||
_onLeave.Enqueue(onLeave);
|
||||
else
|
||||
onLeave();
|
||||
}
|
||||
|
||||
public void AddActionOnEnter(Action onEnter)
|
||||
{
|
||||
if (InGPose)
|
||||
onEnter();
|
||||
else
|
||||
_onEnter.Enqueue(onEnter);
|
||||
}
|
||||
|
||||
private void OnFramework(Framework _)
|
||||
{
|
||||
var inGPose = GameMain.IsInGPose();
|
||||
if (InGPose == inGPose)
|
||||
return;
|
||||
|
||||
InGPose = inGPose;
|
||||
Invoke(this, InGPose);
|
||||
var actions = InGPose ? _onEnter : _onLeave;
|
||||
foreach (var action in actions)
|
||||
{
|
||||
try
|
||||
{
|
||||
action();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Glamourer.Log.Error($"Error executing GPose action:\n{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OtterGui.Log;
|
||||
using Penumbra.GameData.Actors;
|
||||
|
||||
namespace Glamourer.Interop.Structs;
|
||||
|
||||
|
|
@ -36,4 +37,13 @@ public readonly struct ActorData
|
|||
? new LazyString(() => string.Join(", ", objects.Select(o => o.ToString())))
|
||||
: new LazyString(() => invalid);
|
||||
}
|
||||
|
||||
private ActorData(List<Actor> objects, string label)
|
||||
{
|
||||
Objects = objects;
|
||||
Label = label;
|
||||
}
|
||||
|
||||
public ActorData OnlyGPose()
|
||||
=> new(Objects.Where(o => o.Index is >= (int)ScreenActor.GPosePlayer and < (int)ScreenActor.CutsceneEnd).ToList(), Label);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,8 @@ public static class ServiceManager
|
|||
.AddSingleton<WeaponVisibilityChanged>()
|
||||
.AddSingleton<ObjectUnlocked>()
|
||||
.AddSingleton<TabSelected>()
|
||||
.AddSingleton<MovedEquipment>();
|
||||
.AddSingleton<MovedEquipment>()
|
||||
.AddSingleton<GPoseService>();
|
||||
|
||||
private static IServiceCollection AddData(this IServiceCollection services)
|
||||
=> services.AddSingleton<IdentifierService>()
|
||||
|
|
|
|||
|
|
@ -167,12 +167,11 @@ public class StateApplier
|
|||
public ActorData ChangeWeapon(ActorState state, EquipSlot slot, bool apply, bool onlyGPose)
|
||||
{
|
||||
var data = GetData(state);
|
||||
if (apply)
|
||||
{
|
||||
if (onlyGPose)
|
||||
data.Objects.RemoveAll(a => a.Index is < (int)ScreenActor.GPosePlayer or >= (int)ScreenActor.CutsceneEnd);
|
||||
data = data.OnlyGPose();
|
||||
|
||||
if (apply)
|
||||
ChangeWeapon(data, slot, state.ModelData.Item(slot), state.ModelData.Stain(slot));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
|
@ -187,20 +186,6 @@ public class StateApplier
|
|||
_weapon.LoadWeapon(actor, slot, weapon.Weapon().With(stain));
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ChangeMainhand(ActorData,EquipItem,StainId)"/>
|
||||
public ActorData ChangeMainhand(ActorState state, bool apply, bool onlyGPose)
|
||||
{
|
||||
var data = GetData(state);
|
||||
if (apply)
|
||||
{
|
||||
if (onlyGPose)
|
||||
data.Objects.RemoveAll(a => a.Index is < (int)ScreenActor.GPosePlayer or >= (int)ScreenActor.CutsceneEnd);
|
||||
ChangeMainhand(data, state.ModelData.Item(EquipSlot.MainHand), state.ModelData.Stain(EquipSlot.MainHand));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary> Apply a weapon to the offhand. </summary>
|
||||
public void ChangeOffhand(ActorData data, EquipItem weapon, StainId stain)
|
||||
{
|
||||
|
|
@ -209,20 +194,6 @@ public class StateApplier
|
|||
_weapon.LoadWeapon(actor, EquipSlot.OffHand, weapon.Weapon().With(stain));
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ChangeOffhand(ActorData,EquipItem,StainId)"/>
|
||||
public ActorData ChangeOffhand(ActorState state, bool apply, bool onlyGPose)
|
||||
{
|
||||
var data = GetData(state);
|
||||
if (apply)
|
||||
{
|
||||
if (onlyGPose)
|
||||
data.Objects.RemoveAll(a => a.Index is < (int)ScreenActor.GPosePlayer or >= (int)ScreenActor.CutsceneEnd);
|
||||
ChangeOffhand(data, state.ModelData.Item(EquipSlot.OffHand), state.ModelData.Stain(EquipSlot.OffHand));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary> Change the visor state of actors only on the draw object. </summary>
|
||||
public void ChangeVisor(ActorData data, bool value)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,12 +14,14 @@ public class StateEditor
|
|||
private readonly ItemManager _items;
|
||||
private readonly CustomizationService _customizations;
|
||||
private readonly HumanModelList _humans;
|
||||
private readonly GPoseService _gPose;
|
||||
|
||||
public StateEditor(CustomizationService customizations, HumanModelList humans, ItemManager items)
|
||||
public StateEditor(CustomizationService customizations, HumanModelList humans, ItemManager items, GPoseService gPose)
|
||||
{
|
||||
_customizations = customizations;
|
||||
_humans = humans;
|
||||
_items = items;
|
||||
_gPose = gPose;
|
||||
}
|
||||
|
||||
/// <summary> Change the model id. If the actor is changed from a human to another human, customize and equipData are unused. </summary>
|
||||
|
|
@ -124,9 +126,19 @@ public class StateEditor
|
|||
|
||||
// Can not change weapon type from expected type in state.
|
||||
if (slot is EquipSlot.MainHand && item.Type != state.BaseData.MainhandType
|
||||
|| slot is EquipSlot.OffHand && item.Type != state.BaseData.MainhandType.ValidOffhand())
|
||||
|| slot is EquipSlot.OffHand && item.Type != state.BaseData.OffhandType)
|
||||
{
|
||||
if (!_gPose.InGPose)
|
||||
return false;
|
||||
|
||||
var old = oldItem;
|
||||
_gPose.AddActionOnLeave(() =>
|
||||
{
|
||||
if (old.Type == state.BaseData.Item(slot).Type)
|
||||
ChangeItem(state, slot, old, state[slot, false], out _, key);
|
||||
});
|
||||
}
|
||||
|
||||
state.ModelData.SetItem(slot, item);
|
||||
state[slot, false] = source;
|
||||
return true;
|
||||
|
|
@ -143,9 +155,20 @@ public class StateEditor
|
|||
|
||||
// Can not change weapon type from expected type in state.
|
||||
if (slot is EquipSlot.MainHand && item.Type != state.BaseData.MainhandType
|
||||
|| slot is EquipSlot.OffHand && item.Type != state.BaseData.MainhandType.ValidOffhand())
|
||||
|| slot is EquipSlot.OffHand && item.Type != state.BaseData.OffhandType)
|
||||
{
|
||||
if (!_gPose.InGPose)
|
||||
return false;
|
||||
|
||||
var old = oldItem;
|
||||
var oldS = oldStain;
|
||||
_gPose.AddActionOnLeave(() =>
|
||||
{
|
||||
if (old.Type == state.BaseData.Item(slot).Type)
|
||||
ChangeEquip(state, slot, old, oldS, state[slot, false], out _, out _, key);
|
||||
});
|
||||
}
|
||||
|
||||
state.ModelData.SetItem(slot, item);
|
||||
state.ModelData.SetStain(slot, stain);
|
||||
state[slot, false] = source;
|
||||
|
|
@ -170,10 +193,11 @@ public class StateEditor
|
|||
{
|
||||
(var setter, oldValue) = index switch
|
||||
{
|
||||
ActorState.MetaIndex.Wetness => ((Func<bool, bool>) (v => state.ModelData.SetIsWet(v)), state.ModelData.IsWet()),
|
||||
ActorState.MetaIndex.HatState => ((Func<bool, bool>) (v => state.ModelData.SetHatVisible(v)), state.ModelData.IsHatVisible()),
|
||||
ActorState.MetaIndex.VisorState => ((Func<bool, bool>) (v => state.ModelData.SetVisor(v)), state.ModelData.IsVisorToggled()),
|
||||
ActorState.MetaIndex.WeaponState => ((Func<bool, bool>) (v => state.ModelData.SetWeaponVisible(v)), state.ModelData.IsWeaponVisible()),
|
||||
ActorState.MetaIndex.Wetness => ((Func<bool, bool>)(v => state.ModelData.SetIsWet(v)), state.ModelData.IsWet()),
|
||||
ActorState.MetaIndex.HatState => ((Func<bool, bool>)(v => state.ModelData.SetHatVisible(v)), state.ModelData.IsHatVisible()),
|
||||
ActorState.MetaIndex.VisorState => ((Func<bool, bool>)(v => state.ModelData.SetVisor(v)), state.ModelData.IsVisorToggled()),
|
||||
ActorState.MetaIndex.WeaponState => ((Func<bool, bool>)(v => state.ModelData.SetWeaponVisible(v)),
|
||||
state.ModelData.IsWeaponVisible()),
|
||||
_ => throw new Exception("Invalid MetaIndex."),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ using Penumbra.GameData.Actors;
|
|||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.String;
|
||||
|
||||
namespace Glamourer.State;
|
||||
|
||||
|
|
@ -258,7 +257,8 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
|||
var type = slot.ToIndex() < 10 ? StateChanged.Type.Equip : StateChanged.Type.Weapon;
|
||||
var actors = type is StateChanged.Type.Equip
|
||||
? _applier.ChangeArmor(state, slot, source is StateChanged.Source.Manual or StateChanged.Source.Ipc)
|
||||
: _applier.ChangeWeapon(state, slot, source is StateChanged.Source.Manual or StateChanged.Source.Ipc, item.Type != old.Type);
|
||||
: _applier.ChangeWeapon(state, slot, source is StateChanged.Source.Manual or StateChanged.Source.Ipc,
|
||||
item.Type != (slot is EquipSlot.MainHand ? state.BaseData.MainhandType : state.BaseData.OffhandType));
|
||||
Glamourer.Log.Verbose(
|
||||
$"Set {slot.ToName()} in state {state.Identifier.Incognito(null)} from {old.Name} ({old.ItemId}) to {item.Name} ({item.ItemId}). [Affecting {actors.ToLazyString("nothing")}.]");
|
||||
_event.Invoke(type, source, state, actors, (old, item, slot));
|
||||
|
|
@ -273,7 +273,7 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
|||
var type = slot.ToIndex() < 10 ? StateChanged.Type.Equip : StateChanged.Type.Weapon;
|
||||
var actors = type is StateChanged.Type.Equip
|
||||
? _applier.ChangeArmor(state, slot, source is StateChanged.Source.Manual or StateChanged.Source.Ipc)
|
||||
: _applier.ChangeWeapon(state, slot, source is StateChanged.Source.Manual or StateChanged.Source.Ipc, item.Type != old.Type);
|
||||
: _applier.ChangeWeapon(state, slot, source is StateChanged.Source.Manual or StateChanged.Source.Ipc, item.Type != (slot is EquipSlot.MainHand ? state.BaseData.MainhandType : state.BaseData.OffhandType));
|
||||
Glamourer.Log.Verbose(
|
||||
$"Set {slot.ToName()} in state {state.Identifier.Incognito(null)} from {old.Name} ({old.ItemId}) to {item.Name} ({item.ItemId}) and its stain from {oldStain.Value} to {stain.Value}. [Affecting {actors.ToLazyString("nothing")}.]");
|
||||
_event.Invoke(type, source, state, actors, (old, item, slot));
|
||||
|
|
@ -401,8 +401,10 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
|||
_applier.ChangeCustomize(actors, state.ModelData.Customize);
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||
_applier.ChangeArmor(actors, slot, state.ModelData.Armor(slot), state.ModelData.IsHatVisible());
|
||||
foreach (var slot in EquipSlotExtensions.WeaponSlots)
|
||||
_applier.ChangeWeapon(actors, slot, state.ModelData.Item(slot), state.ModelData.Stain(slot));
|
||||
var mainhandActors = state.ModelData.MainhandType != state.BaseData.MainhandType ? actors.OnlyGPose() : actors;
|
||||
_applier.ChangeMainhand(mainhandActors, state.ModelData.Item(EquipSlot.MainHand), state.ModelData.Stain(EquipSlot.MainHand));
|
||||
var offhandActors = state.ModelData.OffhandType != state.BaseData.OffhandType ? actors.OnlyGPose() : actors;
|
||||
_applier.ChangeOffhand(offhandActors, state.ModelData.Item(EquipSlot.OffHand), state.ModelData.Stain(EquipSlot.OffHand));
|
||||
}
|
||||
|
||||
if (state.ModelData.IsHuman)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue