Reworked all of the meta, made StateIndex its own thing.

This commit is contained in:
Ottermandias 2024-01-23 18:02:53 +01:00
parent 70e4833fb5
commit 1ad70541d3
36 changed files with 747 additions and 657 deletions

View file

@ -3,6 +3,7 @@ using Dalamud.Plugin;
using Glamourer.Designs;
using Glamourer.Events;
using Glamourer.Interop.Structs;
using Glamourer.State;
using Penumbra.Api.Helpers;
using Penumbra.GameData.Actors;
@ -130,7 +131,7 @@ public partial class GlamourerIpc
if ((hasModelId || state.ModelData.ModelId == 0) && state.CanUnlock(lockCode))
{
_stateManager.ApplyDesign(design, state, StateChanged.Source.Ipc, lockCode);
_stateManager.ApplyDesign(design, state, StateSource.Ipc, lockCode);
state.Lock(lockCode);
}
}

View file

@ -15,7 +15,7 @@ public partial class GlamourerIpc
private readonly EventProvider<StateChanged.Type, nint, Lazy<string>> _stateChangedProvider;
private readonly EventProvider<bool> _gPoseChangedProvider;
private void OnStateChanged(StateChanged.Type type, StateChanged.Source source, ActorState state, ActorData actors, object? data = null)
private void OnStateChanged(StateChanged.Type type, StateSource source, ActorState state, ActorData actors, object? data = null)
{
foreach (var actor in actors.Objects)
_stateChangedProvider.Invoke(type, actor.Address, new Lazy<string>(() => _designConverter.ShareBase64(state)));

View file

@ -1,6 +1,7 @@
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Plugin;
using Glamourer.Events;
using Glamourer.State;
using Penumbra.Api.Helpers;
using Penumbra.GameData.Actors;
@ -82,7 +83,7 @@ public partial class GlamourerIpc
foreach (var id in actors)
{
if (_stateManager.TryGetValue(id, out var state))
_stateManager.ResetState(state, StateChanged.Source.Ipc, lockCode);
_stateManager.ResetState(state, StateSource.Ipc, lockCode);
}
}

View file

@ -2,6 +2,7 @@
using Dalamud.Plugin;
using Glamourer.Events;
using Glamourer.Services;
using Glamourer.State;
using Penumbra.Api.Helpers;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
@ -55,7 +56,7 @@ public partial class GlamourerIpc
if (!state.ModelData.IsHuman)
return GlamourerErrorCode.ActorNotHuman;
_stateManager.ChangeEquip(state, slot, item, stainId, StateChanged.Source.Ipc, key);
_stateManager.ChangeEquip(state, slot, item, stainId, StateSource.Ipc, key);
return GlamourerErrorCode.Success;
}
@ -82,7 +83,7 @@ public partial class GlamourerIpc
if (!state.ModelData.IsHuman)
return GlamourerErrorCode.ActorNotHuman;
_stateManager.ChangeEquip(state, slot, item, stainId, StateChanged.Source.Ipc, key);
_stateManager.ChangeEquip(state, slot, item, stainId, StateSource.Ipc, key);
found = true;
}

View file

@ -18,9 +18,8 @@ public enum ApplicationType : byte
public static class ApplicationTypeExtensions
{
public static (EquipFlag Equip, CustomizeFlag Customize, CrestFlag Crest, CustomizeParameterFlag Parameters, bool ApplyHat, bool ApplyVisor,
bool
ApplyWeapon, bool ApplyWet) ApplyWhat(this ApplicationType type, DesignBase? design)
public static (EquipFlag Equip, CustomizeFlag Customize, CrestFlag Crest, CustomizeParameterFlag Parameters, MetaFlag Meta) ApplyWhat(
this ApplicationType type, DesignBase? design)
{
var equipFlags = (type.HasFlag(ApplicationType.Weapons) ? WeaponFlags : 0)
| (type.HasFlag(ApplicationType.Armor) ? ArmorFlags : 0)
@ -29,18 +28,15 @@ public static class ApplicationTypeExtensions
var customizeFlags = type.HasFlag(ApplicationType.Customizations) ? CustomizeFlagExtensions.All : 0;
var parameterFlags = type.HasFlag(ApplicationType.Customizations) ? CustomizeParameterExtensions.All : 0;
var crestFlag = type.HasFlag(ApplicationType.GearCustomization) ? CrestExtensions.AllRelevant : 0;
var metaFlag = (type.HasFlag(ApplicationType.Armor) ? MetaFlag.HatState | MetaFlag.VisorState : 0)
| (type.HasFlag(ApplicationType.Weapons) ? MetaFlag.WeaponState : 0)
| (type.HasFlag(ApplicationType.Customizations) ? MetaFlag.Wetness : 0);
if (design == null)
return (equipFlags, customizeFlags, crestFlag, parameterFlags, type.HasFlag(ApplicationType.Armor),
type.HasFlag(ApplicationType.Armor),
type.HasFlag(ApplicationType.Weapons), type.HasFlag(ApplicationType.Customizations));
return (equipFlags, customizeFlags, crestFlag, parameterFlags, metaFlag);
return (equipFlags & design!.ApplyEquip, customizeFlags & design.ApplyCustomize, crestFlag & design.ApplyCrest,
parameterFlags & design.ApplyParameters,
type.HasFlag(ApplicationType.Armor) && design.DoApplyHatVisible(),
type.HasFlag(ApplicationType.Armor) && design.DoApplyVisorToggle(),
type.HasFlag(ApplicationType.Weapons) && design.DoApplyWeaponVisible(),
type.HasFlag(ApplicationType.Customizations) && design.DoApplyWetness());
parameterFlags & design.ApplyParameters, metaFlag & design.ApplyMeta);
}
public const EquipFlag WeaponFlags = EquipFlag.Mainhand | EquipFlag.Offhand;

View file

@ -68,7 +68,6 @@ public class AutoDesign
return ret;
}
public (EquipFlag Equip, CustomizeFlag Customize, CrestFlag Crest, CustomizeParameterFlag Parameters, bool ApplyHat, bool ApplyVisor, bool
ApplyWeapon, bool ApplyWet) ApplyWhat()
public (EquipFlag Equip, CustomizeFlag Customize, CrestFlag Crest, CustomizeParameterFlag Parameters, MetaFlag Meta) ApplyWhat()
=> Type.ApplyWhat(Design);
}

View file

@ -35,7 +35,7 @@ public sealed class AutoDesignApplier : IDisposable
private readonly IClientState _clientState;
private ActorState? _jobChangeState;
private readonly Dictionary<FullEquipType, (EquipItem, StateChanged.Source)> _jobChange = [];
private readonly Dictionary<FullEquipType, (EquipItem, StateSource)> _jobChange = [];
private void ResetJobChange()
{
@ -183,7 +183,7 @@ public sealed class AutoDesignApplier : IDisposable
}
else if (_state.TryGetValue(id, out var state))
{
state.Source.RemoveFixedDesignSources();
state.Sources.RemoveFixedDesignSources();
}
}
}
@ -197,9 +197,9 @@ public sealed class AutoDesignApplier : IDisposable
{
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.Source.RemoveFixedDesignSources();
state.Sources.RemoveFixedDesignSources();
else if (_state.TryGetValue(id, out var state))
state.Source.RemoveFixedDesignSources();
state.Sources.RemoveFixedDesignSources();
}
}
}
@ -256,13 +256,13 @@ public sealed class AutoDesignApplier : IDisposable
else if (!GetPlayerSet(identifier, out set!))
{
if (state.UpdateTerritory(_clientState.TerritoryType) && _config.RevertManualChangesOnZoneChange)
_state.ResetState(state, StateChanged.Source.Game);
_state.ResetState(state, StateSource.Game);
return true;
}
var respectManual = !state.UpdateTerritory(_clientState.TerritoryType) || !_config.RevertManualChangesOnZoneChange;
if (!respectManual)
_state.ResetState(state, StateChanged.Source.Game);
_state.ResetState(state, StateSource.Game);
Reduce(actor, state, set, respectManual, false);
return true;
}
@ -272,13 +272,13 @@ public sealed class AutoDesignApplier : IDisposable
if (set.BaseState == AutoDesignSet.Base.Game)
_state.ResetStateFixed(state, respectManual);
else if (!respectManual)
state.Source.RemoveFixedDesignSources();
state.Sources.RemoveFixedDesignSources();
if (!_humans.IsHuman((uint)actor.AsCharacter->CharacterData.ModelCharaId))
return;
var mergedDesign = _designMerger.Merge(set.Designs.Where(d => d.IsActive(actor)).Select(d => ((DesignBase?) d.Design, d.Type)), state.ModelData, true);
ApplyToState(state, mergedDesign, respectManual, fromJobChange, StateChanged.Source.Fixed);
var mergedDesign = _designMerger.Merge(set.Designs.Where(d => d.IsActive(actor)).Select(d => ((DesignBase?) d.Design, d.Type)), state.ModelData, true, false);
ApplyToState(state, mergedDesign, respectManual, fromJobChange, StateSource.Fixed);
}
/// <summary> Get world-specific first and all-world afterward. </summary>
@ -304,27 +304,27 @@ public sealed class AutoDesignApplier : IDisposable
}
}
private void ApplyToState(ActorState state, MergedDesign mergedDesign, bool respectManual, bool fromJobChange, StateChanged.Source source)
private void ApplyToState(ActorState state, MergedDesign mergedDesign, bool respectManual, bool fromJobChange, StateSource source)
{
foreach (var slot in CrestExtensions.AllRelevantSet.Where(mergedDesign.Design.DoApplyCrest))
if (!respectManual || state.Source[slot] is not StateChanged.Source.Manual)
if (!respectManual || state.Sources[slot] is not StateSource.Manual)
_state.ChangeCrest(state, slot, mergedDesign.Design.DesignData.Crest(slot), mergedDesign.GetSource(slot, source));
foreach (var parameter in mergedDesign.Design.ApplyParameters.Iterate())
if (!respectManual || state.Source[parameter] is not StateChanged.Source.Manual and not StateChanged.Source.Pending)
if (!respectManual || state.Sources[parameter] is not StateSource.Manual and not StateSource.Pending)
_state.ChangeCustomizeParameter(state, parameter, mergedDesign.Design.DesignData.Parameters[parameter], mergedDesign.GetSource(parameter, source));
foreach (var slot in EquipSlotExtensions.EqdpSlots)
{
if (mergedDesign.Design.DoApplyEquip(slot))
{
if (!respectManual || state.Source[slot, false] is not StateChanged.Source.Manual)
if (!respectManual || state.Sources[slot, false] is not StateSource.Manual)
_state.ChangeItem(state, slot, mergedDesign.Design.DesignData.Item(slot), mergedDesign.GetSource(slot, false, source));
}
if (mergedDesign.Design.DoApplyStain(slot))
{
if (!respectManual || state.Source[slot, true] is not StateChanged.Source.Manual)
if (!respectManual || state.Sources[slot, true] is not StateSource.Manual)
_state.ChangeStain(state, slot, mergedDesign.Design.DesignData.Stain(slot), mergedDesign.GetSource(slot, true, source));
}
}
@ -333,14 +333,14 @@ public sealed class AutoDesignApplier : IDisposable
{
if (mergedDesign.Design.DoApplyStain(weaponSlot))
{
if (!respectManual || state.Source[weaponSlot, true] is not StateChanged.Source.Manual)
if (!respectManual || state.Sources[weaponSlot, true] is not StateSource.Manual)
_state.ChangeStain(state, weaponSlot, mergedDesign.Design.DesignData.Stain(weaponSlot), mergedDesign.GetSource(weaponSlot, true, source));
}
if (!mergedDesign.Design.DoApplyEquip(weaponSlot))
continue;
if (respectManual && state.Source[weaponSlot, false] is StateChanged.Source.Manual)
if (respectManual && state.Sources[weaponSlot, false] is StateSource.Manual)
continue;
var currentType = state.ModelData.Item(weaponSlot).Type;
@ -359,7 +359,7 @@ public sealed class AutoDesignApplier : IDisposable
}
private void ReduceEquip(ActorState state, in DesignData design, EquipFlag equipFlags, ref EquipFlag totalEquipFlags, bool respectManual,
StateChanged.Source source, bool fromJobChange)
StateSource source, bool fromJobChange)
{
equipFlags &= ~totalEquipFlags;
if (equipFlags == 0)
@ -373,7 +373,7 @@ public sealed class AutoDesignApplier : IDisposable
var item = design.Item(slot);
if (!_config.UnlockedItemMode || _itemUnlocks.IsUnlocked(item.Id, out _))
{
if (!respectManual || state.Source[slot, false] is not StateChanged.Source.Manual)
if (!respectManual || state.Sources[slot, false] is not StateSource.Manual)
_state.ChangeItem(state, slot, item, source);
totalEquipFlags |= flag;
}
@ -382,7 +382,7 @@ public sealed class AutoDesignApplier : IDisposable
var stainFlag = slot.ToStainFlag();
if (equipFlags.HasFlag(stainFlag))
{
if (!respectManual || state.Source[slot, true] is not StateChanged.Source.Manual)
if (!respectManual || state.Sources[slot, true] is not StateSource.Manual)
_state.ChangeStain(state, slot, design.Stain(slot), source);
totalEquipFlags |= stainFlag;
}
@ -392,7 +392,7 @@ public sealed class AutoDesignApplier : IDisposable
{
var item = design.Item(EquipSlot.MainHand);
var checkUnlock = !_config.UnlockedItemMode || _itemUnlocks.IsUnlocked(item.Id, out _);
var checkState = !respectManual || state.Source[EquipSlot.MainHand, false] is not StateChanged.Source.Manual;
var checkState = !respectManual || state.Sources[EquipSlot.MainHand, false] is not StateSource.Manual;
if (checkUnlock && checkState)
{
if (fromJobChange)
@ -412,7 +412,7 @@ public sealed class AutoDesignApplier : IDisposable
{
var item = design.Item(EquipSlot.OffHand);
var checkUnlock = !_config.UnlockedItemMode || _itemUnlocks.IsUnlocked(item.Id, out _);
var checkState = !respectManual || state.Source[EquipSlot.OffHand, false] is not StateChanged.Source.Manual;
var checkState = !respectManual || state.Sources[EquipSlot.OffHand, false] is not StateSource.Manual;
if (checkUnlock && checkState)
{
if (fromJobChange)
@ -430,21 +430,21 @@ public sealed class AutoDesignApplier : IDisposable
if (equipFlags.HasFlag(EquipFlag.MainhandStain))
{
if (!respectManual || state.Source[EquipSlot.MainHand, true] is not StateChanged.Source.Manual)
if (!respectManual || state.Sources[EquipSlot.MainHand, true] is not StateSource.Manual)
_state.ChangeStain(state, EquipSlot.MainHand, design.Stain(EquipSlot.MainHand), source);
totalEquipFlags |= EquipFlag.MainhandStain;
}
if (equipFlags.HasFlag(EquipFlag.OffhandStain))
{
if (!respectManual || state.Source[EquipSlot.OffHand, true] is not StateChanged.Source.Manual)
if (!respectManual || state.Sources[EquipSlot.OffHand, true] is not StateSource.Manual)
_state.ChangeStain(state, EquipSlot.OffHand, design.Stain(EquipSlot.OffHand), source);
totalEquipFlags |= EquipFlag.OffhandStain;
}
}
private void ReduceCustomize(ActorState state, in DesignData design, CustomizeFlag customizeFlags, ref CustomizeFlag totalCustomizeFlags,
bool respectManual, StateChanged.Source source)
bool respectManual, StateSource source)
{
customizeFlags &= ~totalCustomizeFlags;
if (customizeFlags == 0)
@ -459,7 +459,7 @@ public sealed class AutoDesignApplier : IDisposable
if (customizeFlags.HasFlag(CustomizeFlag.Clan))
{
if (!respectManual || state.Source[CustomizeIndex.Clan] is not StateChanged.Source.Manual)
if (!respectManual || state.Sources[CustomizeIndex.Clan] is not StateSource.Manual)
fixFlags |= _customizations.ChangeClan(ref customize, design.Customize.Clan);
customizeFlags &= ~(CustomizeFlag.Clan | CustomizeFlag.Race);
totalCustomizeFlags |= CustomizeFlag.Clan | CustomizeFlag.Race;
@ -467,7 +467,7 @@ public sealed class AutoDesignApplier : IDisposable
if (customizeFlags.HasFlag(CustomizeFlag.Gender))
{
if (!respectManual || state.Source[CustomizeIndex.Gender] is not StateChanged.Source.Manual)
if (!respectManual || state.Sources[CustomizeIndex.Gender] is not StateSource.Manual)
fixFlags |= _customizations.ChangeGender(ref customize, design.Customize.Gender);
customizeFlags &= ~CustomizeFlag.Gender;
totalCustomizeFlags |= CustomizeFlag.Gender;
@ -478,7 +478,7 @@ public sealed class AutoDesignApplier : IDisposable
if (customizeFlags.HasFlag(CustomizeFlag.Face))
{
if (!respectManual || state.Source[CustomizeIndex.Face] is not StateChanged.Source.Manual)
if (!respectManual || state.Sources[CustomizeIndex.Face] is not StateSource.Manual)
_state.ChangeCustomize(state, CustomizeIndex.Face, design.Customize.Face, source);
customizeFlags &= ~CustomizeFlag.Face;
totalCustomizeFlags |= CustomizeFlag.Face;
@ -498,42 +498,21 @@ public sealed class AutoDesignApplier : IDisposable
if (data.HasValue && _config.UnlockedItemMode && !_customizeUnlocks.IsUnlocked(data.Value, out _))
continue;
if (!respectManual || state.Source[index] is not StateChanged.Source.Manual)
if (!respectManual || state.Sources[index] is not StateSource.Manual)
_state.ChangeCustomize(state, index, value, source);
totalCustomizeFlags |= flag;
}
}
}
private void ReduceMeta(ActorState state, in DesignData design, bool applyHat, bool applyVisor, bool applyWeapon, bool applyWet,
ref byte totalMetaFlags, bool respectManual, StateChanged.Source source)
private void ReduceMeta(ActorState state, in DesignData design, MetaFlag apply, ref MetaFlag totalMetaFlags, bool respectManual, StateSource source)
{
if (applyHat && (totalMetaFlags & 0x01) == 0)
apply &= ~totalMetaFlags;
foreach (var index in MetaExtensions.AllRelevant)
{
if (!respectManual || state.Source[MetaIndex.HatState] is not StateChanged.Source.Manual)
_state.ChangeHatState(state, design.IsHatVisible(), source);
totalMetaFlags |= 0x01;
}
if (applyVisor && (totalMetaFlags & 0x02) == 0)
{
if (!respectManual || state.Source[MetaIndex.VisorState] is not StateChanged.Source.Manual)
_state.ChangeVisorState(state, design.IsVisorToggled(), source);
totalMetaFlags |= 0x02;
}
if (applyWeapon && (totalMetaFlags & 0x04) == 0)
{
if (!respectManual || state.Source[MetaIndex.WeaponState] is not StateChanged.Source.Manual)
_state.ChangeWeaponState(state, design.IsWeaponVisible(), source);
totalMetaFlags |= 0x04;
}
if (applyWet && (totalMetaFlags & 0x08) == 0)
{
if (!respectManual || state.Source[MetaIndex.Wetness] is not StateChanged.Source.Manual)
_state.ChangeWetness(state, design.IsWet(), source);
totalMetaFlags |= 0x08;
if (!respectManual || state.Sources[index] is not StateSource.Manual)
_state.ChangeMeta(state, index, design.GetMeta(index), source);
totalMetaFlags |= index.ToFlag();
}
}

View file

@ -163,16 +163,15 @@ public class DesignBase64Migration
}
}
public static unsafe string CreateOldBase64(in DesignData save, EquipFlag equipFlags, CustomizeFlag customizeFlags,
bool setHat, bool setVisor, bool setWeapon, bool writeProtected, float alpha = 1.0f)
public static unsafe string CreateOldBase64(in DesignData save, EquipFlag equipFlags, CustomizeFlag customizeFlags, MetaFlag meta, bool writeProtected, float alpha = 1.0f)
{
var data = stackalloc byte[Base64SizeV4];
data[0] = 5;
data[1] = (byte)((customizeFlags == CustomizeFlagExtensions.All ? 0x01 : 0)
| (save.IsWet() ? 0x02 : 0)
| (setHat ? 0x04 : 0)
| (setWeapon ? 0x08 : 0)
| (setVisor ? 0x10 : 0)
| (meta.HasFlag(MetaFlag.HatState) ? 0x04 : 0)
| (meta.HasFlag(MetaFlag.WeaponState) ? 0x08 : 0)
| (meta.HasFlag(MetaFlag.VisorState) ? 0x10 : 0)
| (writeProtected ? 0x20 : 0));
data[2] = (byte)((equipFlags.HasFlag(EquipFlag.Mainhand) ? 0x01 : 0)
| (equipFlags.HasFlag(EquipFlag.Offhand) ? 0x02 : 0)

View file

@ -55,10 +55,10 @@ public class DesignConverter(ItemManager _items, DesignManager _designs, Customi
design.ApplyCustomize = customizeFlags & CustomizeFlagExtensions.AllRelevant;
design.ApplyCrest = crestFlags & CrestExtensions.All;
design.ApplyParameters = parameterFlags & CustomizeParameterExtensions.All;
design.SetApplyHatVisible(design.DoApplyEquip(EquipSlot.Head));
design.SetApplyVisorToggle(design.DoApplyEquip(EquipSlot.Head));
design.SetApplyWeaponVisible(design.DoApplyEquip(EquipSlot.MainHand) || design.DoApplyEquip(EquipSlot.OffHand));
design.SetApplyWetness(true);
design.SetApplyMeta(MetaIndex.HatState, design.DoApplyEquip(EquipSlot.Head));
design.SetApplyMeta(MetaIndex.VisorState, design.DoApplyEquip(EquipSlot.Head));
design.SetApplyMeta(MetaIndex.WeaponState, design.DoApplyEquip(EquipSlot.MainHand) || design.DoApplyEquip(EquipSlot.OffHand));
design.SetApplyMeta(MetaIndex.Wetness, true);
design.SetDesignData(_customize, data);
return design;
}
@ -126,16 +126,14 @@ public class DesignConverter(ItemManager _items, DesignManager _designs, Customi
return null;
}
ret.SetApplyWetness(customize);
ret.SetApplyMeta(MetaIndex.Wetness, customize);
ret.ApplyCustomize = customize ? CustomizeFlagExtensions.AllRelevant : 0;
if (!equip)
{
ret.ApplyEquip = 0;
ret.ApplyCrest = 0;
ret.SetApplyHatVisible(false);
ret.SetApplyWeaponVisible(false);
ret.SetApplyVisorToggle(false);
ret.ApplyMeta &= ~(MetaFlag.HatState | MetaFlag.WeaponState | MetaFlag.VisorState);
}
return ret;

View file

@ -523,15 +523,7 @@ public class DesignManager
/// <summary> Change the application value of one of the meta flags. </summary>
public void ChangeApplyMeta(Design design, MetaIndex metaIndex, bool value)
{
var change = metaIndex switch
{
MetaIndex.Wetness => design.SetApplyWetness(value),
MetaIndex.HatState => design.SetApplyHatVisible(value),
MetaIndex.VisorState => design.SetApplyVisorToggle(value),
MetaIndex.WeaponState => design.SetApplyWeaponVisible(value),
_ => throw new ArgumentOutOfRangeException(nameof(metaIndex), metaIndex, null),
};
if (!change)
if (!design.SetApplyMeta(metaIndex, value))
return;
design.LastEdit = DateTimeOffset.UtcNow;
@ -556,14 +548,8 @@ public class DesignManager
public void ApplyDesign(Design design, DesignBase other)
{
_undoStore[design.Identifier] = design.DesignData;
if (other.DoApplyWetness())
design.GetDesignDataRef().SetIsWet(other.DesignData.IsWet());
if (other.DoApplyHatVisible())
design.GetDesignDataRef().SetHatVisible(other.DesignData.IsHatVisible());
if (other.DoApplyVisorToggle())
design.GetDesignDataRef().SetVisor(other.DesignData.IsVisorToggled());
if (other.DoApplyWeaponVisible())
design.GetDesignDataRef().SetWeaponVisible(other.DesignData.IsWeaponVisible());
foreach (var index in MetaExtensions.AllRelevant.Where(other.DoApplyMeta))
design.GetDesignDataRef().SetMeta(index, other.DesignData.GetMeta(index));
if (design.DesignData.IsHuman)
{

View file

@ -1,5 +1,4 @@
using Glamourer.Automation;
using Glamourer.Events;
using Glamourer.GameData;
using Glamourer.Services;
using Glamourer.State;
@ -28,13 +27,13 @@ public class DesignMerger(
continue;
ref readonly var data = ref design == null ? ref baseRef : ref design.GetDesignDataRef();
var source = design == null ? StateChanged.Source.Game : StateChanged.Source.Manual;
var source = design == null ? StateSource.Game : StateSource.Manual;
if (!data.IsHuman)
continue;
var (equipFlags, customizeFlags, crestFlags, parameterFlags, applyHat, applyVisor, applyWeapon, applyWet) = type.ApplyWhat(design);
ReduceMeta(data, applyHat, applyVisor, applyWeapon, applyWet, ret, source);
var (equipFlags, customizeFlags, crestFlags, parameterFlags, applyMeta) = type.ApplyWhat(design);
ReduceMeta(data, applyMeta, ret, source);
ReduceCustomize(data, customizeFlags, ref fixFlags, ret, source, respectOwnership);
ReduceEquip(data, equipFlags, ret, source, respectOwnership);
ReduceMainhands(data, equipFlags, ret, source, respectOwnership);
@ -58,39 +57,22 @@ public class DesignMerger(
ret.AssociatedMods.TryAdd(mod, settings);
}
private static void ReduceMeta(in DesignData design, bool applyHat, bool applyVisor, bool applyWeapon, bool applyWet, MergedDesign ret,
StateChanged.Source source)
private static void ReduceMeta(in DesignData design, MetaFlag applyMeta, MergedDesign ret, StateSource source)
{
if (applyHat && !ret.Design.DoApplyHatVisible())
{
ret.Design.SetApplyHatVisible(true);
ret.Design.GetDesignDataRef().SetHatVisible(design.IsHatVisible());
ret.Source[MetaIndex.HatState] = source;
}
applyMeta &= ~ret.Design.ApplyMeta;
if (applyVisor && !ret.Design.DoApplyVisorToggle())
foreach (var index in MetaExtensions.AllRelevant)
{
ret.Design.SetApplyVisorToggle(true);
ret.Design.GetDesignDataRef().SetVisor(design.IsVisorToggled());
ret.Source[MetaIndex.VisorState] = source;
}
if (!applyMeta.HasFlag(index.ToFlag()))
continue;
if (applyWeapon && !ret.Design.DoApplyWeaponVisible())
{
ret.Design.SetApplyWeaponVisible(true);
ret.Design.GetDesignDataRef().SetWeaponVisible(design.IsWeaponVisible());
ret.Source[MetaIndex.WeaponState] = source;
}
if (applyWet && !ret.Design.DoApplyWetness())
{
ret.Design.SetApplyWetness(true);
ret.Design.GetDesignDataRef().SetIsWet(design.IsWet());
ret.Source[MetaIndex.Wetness] = source;
ret.Design.SetApplyMeta(index, true);
ret.Design.GetDesignDataRef().SetMeta(index, design.GetMeta(index));
ret.Sources[index] = source;
}
}
private static void ReduceCrests(in DesignData design, CrestFlag crestFlags, MergedDesign ret, StateChanged.Source source)
private static void ReduceCrests(in DesignData design, CrestFlag crestFlags, MergedDesign ret, StateSource source)
{
crestFlags &= ~ret.Design.ApplyCrest;
if (crestFlags == 0)
@ -103,12 +85,12 @@ public class DesignMerger(
ret.Design.GetDesignDataRef().SetCrest(slot, design.Crest(slot));
ret.Design.SetApplyCrest(slot, true);
ret.Source[slot] = source;
ret.Sources[slot] = source;
}
}
private static void ReduceParameters(in DesignData design, CustomizeParameterFlag parameterFlags, MergedDesign ret,
StateChanged.Source source)
StateSource source)
{
parameterFlags &= ~ret.Design.ApplyParameters;
if (parameterFlags == 0)
@ -121,11 +103,11 @@ public class DesignMerger(
ret.Design.GetDesignDataRef().Parameters.Set(flag, design.Parameters[flag]);
ret.Design.SetApplyParameter(flag, true);
ret.Source[flag] = source;
ret.Sources[flag] = source;
}
}
private void ReduceEquip(in DesignData design, EquipFlag equipFlags, MergedDesign ret, StateChanged.Source source,
private void ReduceEquip(in DesignData design, EquipFlag equipFlags, MergedDesign ret, StateSource source,
bool respectOwnership)
{
equipFlags &= ~ret.Design.ApplyEquip;
@ -142,7 +124,7 @@ public class DesignMerger(
if (!respectOwnership || _itemUnlocks.IsUnlocked(item.Id, out _))
ret.Design.GetDesignDataRef().SetItem(slot, item);
ret.Design.SetApplyEquip(slot, true);
ret.Source[slot, false] = source;
ret.Sources[slot, false] = source;
}
var stainFlag = slot.ToStainFlag();
@ -150,7 +132,7 @@ public class DesignMerger(
{
ret.Design.GetDesignDataRef().SetStain(slot, design.Stain(slot));
ret.Design.SetApplyStain(slot, true);
ret.Source[slot, true] = source;
ret.Sources[slot, true] = source;
}
}
@ -161,12 +143,12 @@ public class DesignMerger(
{
ret.Design.GetDesignDataRef().SetStain(slot, design.Stain(slot));
ret.Design.SetApplyStain(slot, true);
ret.Source[slot, true] = source;
ret.Sources[slot, true] = source;
}
}
}
private void ReduceMainhands(in DesignData design, EquipFlag equipFlags, MergedDesign ret, StateChanged.Source source,
private void ReduceMainhands(in DesignData design, EquipFlag equipFlags, MergedDesign ret, StateSource source,
bool respectOwnership)
{
if (!equipFlags.HasFlag(EquipFlag.Mainhand))
@ -185,7 +167,7 @@ public class DesignMerger(
ret.Weapons.TryAdd(weapon.Type, (weapon, source));
}
private void ReduceOffhands(in DesignData design, EquipFlag equipFlags, MergedDesign ret, StateChanged.Source source, bool respectOwnership)
private void ReduceOffhands(in DesignData design, EquipFlag equipFlags, MergedDesign ret, StateSource source, bool respectOwnership)
{
if (!equipFlags.HasFlag(EquipFlag.Offhand))
return;
@ -205,7 +187,7 @@ public class DesignMerger(
}
private void ReduceCustomize(in DesignData design, CustomizeFlag customizeFlags, ref CustomizeFlag fixFlags, MergedDesign ret,
StateChanged.Source source, bool respectOwnership)
StateSource source, bool respectOwnership)
{
customizeFlags &= ~ret.Design.ApplyCustomizeRaw;
if (customizeFlags == 0)
@ -222,8 +204,8 @@ public class DesignMerger(
ret.Design.SetApplyCustomize(CustomizeIndex.Clan, true);
ret.Design.SetApplyCustomize(CustomizeIndex.Race, true);
customizeFlags &= ~(CustomizeFlag.Clan | CustomizeFlag.Race);
ret.Source[CustomizeIndex.Clan] = source;
ret.Source[CustomizeIndex.Race] = source;
ret.Sources[CustomizeIndex.Clan] = source;
ret.Sources[CustomizeIndex.Race] = source;
}
if (customizeFlags.HasFlag(CustomizeFlag.Gender))
@ -231,7 +213,7 @@ public class DesignMerger(
fixFlags |= _customize.ChangeGender(ref customize, design.Customize.Gender);
ret.Design.SetApplyCustomize(CustomizeIndex.Gender, true);
customizeFlags &= ~CustomizeFlag.Gender;
ret.Source[CustomizeIndex.Gender] = source;
ret.Sources[CustomizeIndex.Gender] = source;
}
if (customizeFlags.HasFlag(CustomizeFlag.Face))
@ -239,7 +221,7 @@ public class DesignMerger(
customize[CustomizeIndex.Face] = design.Customize.Face;
ret.Design.SetApplyCustomize(CustomizeIndex.Face, true);
customizeFlags &= ~CustomizeFlag.Face;
ret.Source[CustomizeIndex.Face] = source;
ret.Sources[CustomizeIndex.Face] = source;
}
var set = ret.Design.CustomizeSet;
@ -259,7 +241,7 @@ public class DesignMerger(
customize[index] = data?.Value ?? value;
ret.Design.SetApplyCustomize(index, true);
ret.Source[index] = source;
ret.Sources[index] = source;
fixFlags &= ~flag;
}
@ -272,15 +254,15 @@ public class DesignMerger(
return;
var source = ret.Design.DoApplyCustomize(CustomizeIndex.Clan)
? ret.Source[CustomizeIndex.Clan]
: ret.Source[CustomizeIndex.Gender];
? ret.Sources[CustomizeIndex.Clan]
: ret.Sources[CustomizeIndex.Gender];
foreach (var index in Enum.GetValues<CustomizeIndex>())
{
var flag = index.ToFlag();
if (!fixFlags.HasFlag(flag))
continue;
ret.Source[index] = source;
ret.Sources[index] = source;
ret.Design.SetApplyCustomize(index, true);
}
}

View file

@ -26,14 +26,14 @@ public sealed class MergedDesign
{
var weapon = design.DesignData.Item(EquipSlot.MainHand);
if (weapon.Valid)
Weapons.TryAdd(weapon.Type, (weapon, StateChanged.Source.Manual));
Weapons.TryAdd(weapon.Type, (weapon, StateSource.Manual));
}
if (design.DoApplyEquip(EquipSlot.OffHand))
{
var weapon = design.DesignData.Item(EquipSlot.OffHand);
if (weapon.Valid)
Weapons.TryAdd(weapon.Type, (weapon, StateChanged.Source.Manual));
Weapons.TryAdd(weapon.Type, (weapon, StateSource.Manual));
}
}
@ -45,25 +45,25 @@ public sealed class MergedDesign
}
public readonly DesignBase Design;
public readonly Dictionary<FullEquipType, (EquipItem, StateChanged.Source)> Weapons = new(4);
public readonly StateSource Source = new();
public readonly Dictionary<FullEquipType, (EquipItem, StateSource)> Weapons = new(4);
public readonly SortedList<Mod, ModSettings> AssociatedMods = [];
public StateSources Sources = new();
public StateChanged.Source GetSource(EquipSlot slot, bool stain, StateChanged.Source actualSource)
=> GetSource(Source[slot, stain], actualSource);
public StateSource GetSource(EquipSlot slot, bool stain, StateSource actualSource)
=> GetSource(Sources[slot, stain], actualSource);
public StateChanged.Source GetSource(CrestFlag slot, StateChanged.Source actualSource)
=> GetSource(Source[slot], actualSource);
public StateSource GetSource(CrestFlag slot, StateSource actualSource)
=> GetSource(Sources[slot], actualSource);
public StateChanged.Source GetSource(CustomizeIndex type, StateChanged.Source actualSource)
=> GetSource(Source[type], actualSource);
public StateSource GetSource(CustomizeIndex type, StateSource actualSource)
=> GetSource(Sources[type], actualSource);
public StateChanged.Source GetSource(MetaIndex index, StateChanged.Source actualSource)
=> GetSource(Source[index], actualSource);
public StateSource GetSource(MetaIndex index, StateSource actualSource)
=> GetSource(Sources[index], actualSource);
public StateChanged.Source GetSource(CustomizeParameterFlag flag, StateChanged.Source actualSource)
=> GetSource(Source[flag], actualSource);
public StateSource GetSource(CustomizeParameterFlag flag, StateSource actualSource)
=> GetSource(Sources[flag], actualSource);
public static StateChanged.Source GetSource(StateChanged.Source given, StateChanged.Source actualSource)
=> given is StateChanged.Source.Game ? StateChanged.Source.Game : actualSource;
public static StateSource GetSource(StateSource given, StateSource actualSource)
=> given is StateSource.Game ? StateSource.Game : actualSource;
}

View file

@ -1,14 +1,14 @@
using Penumbra.GameData.Enums;
using Glamourer.State;
namespace Glamourer.State;
namespace Glamourer.Designs;
public enum MetaIndex
{
Wetness = EquipFlagExtensions.NumEquipFlags + CustomizationExtensions.NumIndices,
HatState,
VisorState,
WeaponState,
ModelId,
Wetness = StateIndex.MetaWetness,
HatState = StateIndex.MetaHatState,
VisorState = StateIndex.MetaVisorState,
WeaponState = StateIndex.MetaWeaponState,
ModelId = StateIndex.MetaModelId,
}
[Flags]
@ -36,4 +36,24 @@ public static class MetaExtensions
MetaIndex.WeaponState => MetaFlag.WeaponState,
_ => (MetaFlag)byte.MaxValue,
};
public static string ToName(this MetaIndex index)
=> index switch
{
MetaIndex.HatState => "Hat Visible",
MetaIndex.VisorState => "Visor Toggled",
MetaIndex.WeaponState => "Weapon Visible",
MetaIndex.Wetness => "Force Wetness",
_ => "Unknown Meta",
};
public static string ToTooltip(this MetaIndex index)
=> index switch
{
MetaIndex.HatState => "Hide or show the characters head gear.",
MetaIndex.VisorState => "Toggle the visor state of the characters head gear.",
MetaIndex.WeaponState => "Hide or show the characters weapons when not drawn.",
MetaIndex.Wetness => "Force the character to be wet or not.",
_ => string.Empty,
};
}

View file

@ -2,8 +2,8 @@ using Glamourer.Interop.Structs;
using Glamourer.State;
using OtterGui.Classes;
namespace Glamourer.Events;
namespace Glamourer.Events
{
/// <summary>
/// Triggered when a Design is edited in any way.
/// <list type="number">
@ -14,7 +14,7 @@ namespace Glamourer.Events;
/// </list>
/// </summary>
public sealed class StateChanged()
: EventWrapper<StateChanged.Type, StateChanged.Source, ActorState, ActorData, object?, StateChanged.Priority>(nameof(StateChanged))
: EventWrapper<StateChanged.Type, StateSource, ActorState, ActorData, object?, StateChanged.Priority>(nameof(StateChanged))
{
public enum Type
{
@ -52,18 +52,9 @@ public sealed class StateChanged()
Other,
}
public enum Source : byte
{
Game,
Manual,
Fixed,
Ipc,
// Only used for CustomizeParameters.
Pending,
}
public enum Priority
{
GlamourerIpc = int.MinValue,
}
}
}

View file

@ -33,7 +33,7 @@ public ref struct CustomizeParameterDrawData(CustomizeParameterFlag flag, in Des
{
Locked = state.IsLocked,
DisplayApplication = false,
ValueSetter = v => manager.ChangeCustomizeParameter(state, flag, v, StateChanged.Source.Manual),
ValueSetter = v => manager.ChangeCustomizeParameter(state, flag, v, StateSource.Manual),
GameValue = state.BaseData.Parameters[flag],
AllowRevert = true,
};

View file

@ -163,7 +163,7 @@ public sealed class DesignQuickBar : Window, IDisposable
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
using var _ = design!.TemporarilyRestrictApplication(applyGear, applyCustomize, applyCrest, applyParameters);
_stateManager.ApplyDesign(design, state, StateChanged.Source.Manual);
_stateManager.ApplyDesign(design, state, StateSource.Manual);
}
public void DrawRevertButton(Vector2 buttonSize)
@ -189,7 +189,7 @@ public sealed class DesignQuickBar : Window, IDisposable
var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.UndoAlt, buttonSize, tooltip, available);
if (clicked)
_stateManager.ResetState(state!, StateChanged.Source.Manual);
_stateManager.ResetState(state!, StateSource.Manual);
}
public void DrawRevertAutomationButton(Vector2 buttonSize)
@ -257,7 +257,7 @@ public sealed class DesignQuickBar : Window, IDisposable
ImGui.SameLine();
var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.Palette, buttonSize, tooltip, available);
if (clicked)
_stateManager.ResetAdvancedState(state!, StateChanged.Source.Manual);
_stateManager.ResetAdvancedState(state!, StateSource.Manual);
}
private (bool, ActorIdentifier, ActorData, ActorState?) ResolveTarget(FontAwesomeIcon icon, Vector2 buttonSize, string tooltip,

View file

@ -46,8 +46,8 @@ public ref struct EquipDrawData(EquipSlot slot, in DesignData designData)
public static EquipDrawData FromState(StateManager manager, ActorState state, EquipSlot slot)
=> new(slot, state.ModelData)
{
ItemSetter = i => manager.ChangeItem(state, slot, i, StateChanged.Source.Manual),
StainSetter = i => manager.ChangeStain(state, slot, i, StateChanged.Source.Manual),
ItemSetter = i => manager.ChangeItem(state, slot, i, StateSource.Manual),
StainSetter = i => manager.ChangeStain(state, slot, i, StateSource.Manual),
Locked = state.IsLocked,
DisplayApplication = false,
GameItem = state.BaseData.Item(slot),

View file

@ -113,22 +113,22 @@ public class PenumbraChangedItemTooltip : IDisposable
case (false, false):
Glamourer.Log.Information($"Applying {item.Name} to Right Finger.");
SetLastItem(EquipSlot.RFinger, item, state);
_stateManager.ChangeItem(state, EquipSlot.RFinger, item, StateChanged.Source.Manual);
_stateManager.ChangeItem(state, EquipSlot.RFinger, item, StateSource.Manual);
break;
case (false, true):
Glamourer.Log.Information($"Applying {item.Name} to Left Finger.");
SetLastItem(EquipSlot.LFinger, item, state);
_stateManager.ChangeItem(state, EquipSlot.LFinger, item, StateChanged.Source.Manual);
_stateManager.ChangeItem(state, EquipSlot.LFinger, item, StateSource.Manual);
break;
case (true, false) when last.Valid:
Glamourer.Log.Information($"Re-Applying {last.Name} to Right Finger.");
SetLastItem(EquipSlot.RFinger, default, state);
_stateManager.ChangeItem(state, EquipSlot.RFinger, last, StateChanged.Source.Manual);
_stateManager.ChangeItem(state, EquipSlot.RFinger, last, StateSource.Manual);
break;
case (true, true) when _lastItems[EquipSlot.LFinger.ToIndex()].Valid:
Glamourer.Log.Information($"Re-Applying {last.Name} to Left Finger.");
SetLastItem(EquipSlot.LFinger, default, state);
_stateManager.ChangeItem(state, EquipSlot.LFinger, last, StateChanged.Source.Manual);
_stateManager.ChangeItem(state, EquipSlot.LFinger, last, StateSource.Manual);
break;
}
@ -138,13 +138,13 @@ public class PenumbraChangedItemTooltip : IDisposable
{
Glamourer.Log.Information($"Re-Applying {last.Name} to {slot.ToName()}.");
SetLastItem(slot, default, state);
_stateManager.ChangeItem(state, slot, last, StateChanged.Source.Manual);
_stateManager.ChangeItem(state, slot, last, StateSource.Manual);
}
else
{
Glamourer.Log.Information($"Applying {item.Name} to {slot.ToName()}.");
SetLastItem(slot, item, state);
_stateManager.ChangeItem(state, slot, item, StateChanged.Source.Manual);
_stateManager.ChangeItem(state, slot, item, StateSource.Manual);
}
return;

View file

@ -61,13 +61,13 @@ public class ActorPanel(
if (_importService.CreateDatTarget(out var dat))
{
_stateManager.ChangeCustomize(_state!, dat.Customize, CustomizeApplicationFlags, StateChanged.Source.Manual);
_stateManager.ChangeCustomize(_state!, dat.Customize, CustomizeApplicationFlags, StateSource.Manual);
Glamourer.Messager.NotificationMessage($"Applied games .dat file {dat.Description} customizations to {_state.Identifier}.",
NotificationType.Success, false);
}
else if (_importService.CreateCharaTarget(out var designBase, out var name))
{
_stateManager.ApplyDesign(designBase, _state!, StateChanged.Source.Manual);
_stateManager.ApplyDesign(designBase, _state!, StateSource.Manual);
Glamourer.Messager.NotificationMessage($"Applied Anamnesis .chara file {name} to {_state.Identifier}.", NotificationType.Success,
false);
}
@ -139,7 +139,7 @@ public class ActorPanel(
return;
if (_customizationDrawer.Draw(_state!.ModelData.Customize, _state.IsLocked, _lockedRedraw))
_stateManager.ChangeCustomize(_state, _customizationDrawer.Customize, _customizationDrawer.Changed, StateChanged.Source.Manual);
_stateManager.ChangeCustomize(_state, _customizationDrawer.Customize, _customizationDrawer.Changed, StateSource.Manual);
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(MetaIndex.Wetness, _stateManager, _state));
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
@ -159,7 +159,7 @@ public class ActorPanel(
var data = EquipDrawData.FromState(_stateManager, _state!, slot);
_equipmentDrawer.DrawEquip(data);
if (usedAllStain)
_stateManager.ChangeStain(_state, slot, newAllStain, StateChanged.Source.Manual);
_stateManager.ChangeStain(_state, slot, newAllStain, StateSource.Manual);
}
var mainhand = EquipDrawData.FromState(_stateManager, _state, EquipSlot.MainHand);
@ -264,7 +264,7 @@ public class ActorPanel(
}
if (turnHuman)
_stateManager.TurnHuman(_state, StateChanged.Source.Manual);
_stateManager.TurnHuman(_state, StateSource.Manual);
}
private HeaderDrawer.Button SetFromClipboardButton()
@ -340,7 +340,7 @@ public class ActorPanel(
var text = ImGui.GetClipboardText();
var design = _converter.FromBase64(text, applyCustomize, applyGear, out _)
?? throw new Exception("The clipboard did not contain valid data.");
_stateManager.ApplyDesign(design, _state!, StateChanged.Source.Manual);
_stateManager.ApplyDesign(design, _state!, StateSource.Manual);
}
catch (Exception ex)
{
@ -368,7 +368,7 @@ public class ActorPanel(
{
if (ImGuiUtil.DrawDisabledButton("Revert to Game", Vector2.Zero, "Revert the character to its actual state in the game.",
_state!.IsLocked))
_stateManager.ResetState(_state!, StateChanged.Source.Manual);
_stateManager.ResetState(_state!, StateSource.Manual);
ImGui.SameLine();
if (ImGuiUtil.DrawDisabledButton("Reapply State", Vector2.Zero, "Try to reapply the configured state if something went wrong.",
@ -396,7 +396,7 @@ public class ActorPanel(
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
if (_stateManager.GetOrCreate(id, data.Objects[0], out var state))
_stateManager.ApplyDesign(_converter.Convert(_state!, applyGear, applyCustomize, applyCrest, applyParameters), state,
StateChanged.Source.Manual);
StateSource.Manual);
}
private void DrawApplyToTarget()
@ -414,6 +414,6 @@ public class ActorPanel(
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
if (_stateManager.GetOrCreate(id, data.Objects[0], out var state))
_stateManager.ApplyDesign(_converter.Convert(_state!, applyGear, applyCustomize, applyCrest, applyParameters), state,
StateChanged.Source.Manual);
StateSource.Manual);
}
}

View file

@ -264,7 +264,7 @@ public class SetPanel(
var size = new Vector2(ImGui.GetFrameHeight());
size.X += ImGuiHelpers.GlobalScale;
var (equipFlags, customizeFlags, _, _, _, _, _, _) = design.ApplyWhat();
var (equipFlags, customizeFlags, _, _, _) = design.ApplyWhat();
var sb = new StringBuilder();
foreach (var slot in EquipSlotExtensions.EqdpSlots.Append(EquipSlot.MainHand).Append(EquipSlot.OffHand))
{

View file

@ -52,11 +52,11 @@ public class ActiveStatePanel(StateManager _stateManager, ObjectManager _objectM
ImGuiUtil.DrawTableColumn(state.Identifier.ToString());
ImGui.TableNextColumn();
if (ImGui.Button("Reset"))
stateManager.ResetState(state, StateChanged.Source.Manual);
stateManager.ResetState(state, StateSource.Manual);
ImGui.TableNextRow();
static void PrintRow<T>(string label, T actor, T model, StateChanged.Source source) where T : notnull
static void PrintRow<T>(string label, T actor, T model, StateSource source) where T : notnull
{
ImGuiUtil.DrawTableColumn(label);
ImGuiUtil.DrawTableColumn(actor.ToString()!);
@ -70,44 +70,44 @@ public class ActiveStatePanel(StateManager _stateManager, ObjectManager _objectM
return $"{item.Name} ({item.PrimaryId.Id}{(item.SecondaryId != 0 ? $"-{item.SecondaryId.Id}" : string.Empty)}-{item.Variant})";
}
PrintRow("Model ID", state.BaseData.ModelId, state.ModelData.ModelId, state.Source[MetaIndex.ModelId]);
PrintRow("Model ID", state.BaseData.ModelId, state.ModelData.ModelId, state.Sources[MetaIndex.ModelId]);
ImGui.TableNextRow();
PrintRow("Wetness", state.BaseData.IsWet(), state.ModelData.IsWet(), state.Source[MetaIndex.Wetness]);
PrintRow("Wetness", state.BaseData.IsWet(), state.ModelData.IsWet(), state.Sources[MetaIndex.Wetness]);
ImGui.TableNextRow();
if (state.BaseData.IsHuman && state.ModelData.IsHuman)
{
PrintRow("Hat Visible", state.BaseData.IsHatVisible(), state.ModelData.IsHatVisible(), state.Source[MetaIndex.HatState]);
PrintRow("Hat Visible", state.BaseData.IsHatVisible(), state.ModelData.IsHatVisible(), state.Sources[MetaIndex.HatState]);
ImGui.TableNextRow();
PrintRow("Visor Toggled", state.BaseData.IsVisorToggled(), state.ModelData.IsVisorToggled(),
state.Source[MetaIndex.VisorState]);
state.Sources[MetaIndex.VisorState]);
ImGui.TableNextRow();
PrintRow("Weapon Visible", state.BaseData.IsWeaponVisible(), state.ModelData.IsWeaponVisible(),
state.Source[MetaIndex.WeaponState]);
state.Sources[MetaIndex.WeaponState]);
ImGui.TableNextRow();
foreach (var slot in EquipSlotExtensions.EqdpSlots.Prepend(EquipSlot.OffHand).Prepend(EquipSlot.MainHand))
{
PrintRow(slot.ToName(), ItemString(state.BaseData, slot), ItemString(state.ModelData, slot), state.Source[slot, false]);
PrintRow(slot.ToName(), ItemString(state.BaseData, slot), ItemString(state.ModelData, slot), state.Sources[slot, false]);
ImGuiUtil.DrawTableColumn(state.BaseData.Stain(slot).Id.ToString());
ImGuiUtil.DrawTableColumn(state.ModelData.Stain(slot).Id.ToString());
ImGuiUtil.DrawTableColumn(state.Source[slot, true].ToString());
ImGuiUtil.DrawTableColumn(state.Sources[slot, true].ToString());
}
foreach (var type in Enum.GetValues<CustomizeIndex>())
{
PrintRow(type.ToDefaultName(), state.BaseData.Customize[type].Value, state.ModelData.Customize[type].Value, state.Source[type]);
PrintRow(type.ToDefaultName(), state.BaseData.Customize[type].Value, state.ModelData.Customize[type].Value, state.Sources[type]);
ImGui.TableNextRow();
}
foreach (var crest in CrestExtensions.AllRelevantSet)
{
PrintRow(crest.ToLabel(), state.BaseData.Crest(crest), state.ModelData.Crest(crest), state.Source[crest]);
PrintRow(crest.ToLabel(), state.BaseData.Crest(crest), state.ModelData.Crest(crest), state.Sources[crest]);
ImGui.TableNextRow();
}
foreach (var flag in CustomizeParameterExtensions.AllFlags)
{
PrintRow(flag.ToString(), state.BaseData.Parameters[flag], state.ModelData.Parameters[flag], state.Source[flag]);
PrintRow(flag.ToString(), state.BaseData.Parameters[flag], state.ModelData.Parameters[flag], state.Sources[flag]);
ImGui.TableNextRow();
}
}

View file

@ -25,9 +25,8 @@ public class DesignManagerPanel(DesignManager _designManager, DesignFileSystem _
continue;
DrawDesign(design, _designFileSystem);
var base64 = DesignBase64Migration.CreateOldBase64(design.DesignData, design.ApplyEquip, design.ApplyCustomizeRaw,
design.DoApplyHatVisible(),
design.DoApplyVisorToggle(), design.DoApplyWeaponVisible(), design.WriteProtected());
var base64 = DesignBase64Migration.CreateOldBase64(design.DesignData, design.ApplyEquip, design.ApplyCustomizeRaw, design.ApplyMeta,
design.WriteProtected());
using var font = ImRaii.PushFont(UiBuilder.MonoFont);
ImGuiUtil.TextWrapped(base64);
if (ImGui.IsItemClicked())
@ -85,18 +84,12 @@ public class DesignManagerPanel(DesignManager _designManager, DesignFileSystem _
ImGuiUtil.DrawTableColumn(applyCrest ? "Apply" : "Keep");
}
ImGuiUtil.DrawTableColumn("Hat Visible");
ImGuiUtil.DrawTableColumn(design.DesignData.IsHatVisible().ToString());
ImGuiUtil.DrawTableColumn(design.DoApplyHatVisible() ? "Apply" : "Keep");
ImGui.TableNextRow();
ImGuiUtil.DrawTableColumn("Visor Toggled");
ImGuiUtil.DrawTableColumn(design.DesignData.IsVisorToggled().ToString());
ImGuiUtil.DrawTableColumn(design.DoApplyVisorToggle() ? "Apply" : "Keep");
ImGui.TableNextRow();
ImGuiUtil.DrawTableColumn("Weapon Visible");
ImGuiUtil.DrawTableColumn(design.DesignData.IsWeaponVisible().ToString());
ImGuiUtil.DrawTableColumn(design.DoApplyWeaponVisible() ? "Apply" : "Keep");
ImGui.TableNextRow();
foreach (var index in MetaExtensions.AllRelevant)
{
ImGuiUtil.DrawTableColumn(index.ToName());
ImGuiUtil.DrawTableColumn(design.DesignData.GetMeta(index).ToString());
ImGuiUtil.DrawTableColumn(design.DoApplyMeta(index) ? "Apply" : "Keep");
}
ImGuiUtil.DrawTableColumn("Model ID");
ImGuiUtil.DrawTableColumn(design.DesignData.ModelId.ToString());
@ -111,9 +104,5 @@ public class DesignManagerPanel(DesignManager _designManager, DesignFileSystem _
ImGuiUtil.DrawTableColumn(apply ? "Apply" : "Keep");
ImGui.TableNextRow();
}
ImGuiUtil.DrawTableColumn("Is Wet");
ImGuiUtil.DrawTableColumn(design.DesignData.IsWet().ToString());
ImGui.TableNextRow();
}
}

View file

@ -55,10 +55,8 @@ public class DesignTesterPanel(ItemManager _items, HumanModelList _humans) : IGa
try
{
_parse64 = DesignBase64Migration.MigrateBase64(_items, _humans, _base64, out var ef, out var cf, out var wp, out var ah,
out var av,
out var aw);
_restore = DesignBase64Migration.CreateOldBase64(in _parse64, ef, cf, ah, av, aw, wp);
_parse64 = DesignBase64Migration.MigrateBase64(_items, _humans, _base64, out var ef, out var cf, out var wp, out var meta);
_restore = DesignBase64Migration.CreateOldBase64(in _parse64, ef, cf, meta, wp);
_restoreBytes = Convert.FromBase64String(_restore);
}
catch (Exception ex)

View file

@ -67,9 +67,9 @@ public class NpcAppearancePanel(NpcCombo _npcCombo, StateManager _state, ObjectM
if (ImGuiUtil.DrawDisabledButton("Apply", Vector2.Zero, string.Empty, disabled))
{
foreach (var (slot, item, stain) in _designConverter.FromDrawData(data.Equip.ToArray(), data.Mainhand, data.Offhand, true))
_state.ChangeEquip(state!, slot, item, stain, StateChanged.Source.Manual);
_state.ChangeVisorState(state!, data.VisorToggled, StateChanged.Source.Manual);
_state.ChangeCustomize(state!, data.Customize, CustomizeFlagExtensions.All, StateChanged.Source.Manual);
_state.ChangeEquip(state!, slot, item, stain, StateSource.Manual);
_state.ChangeMeta(state!, MetaIndex.VisorState, data.VisorToggled, StateSource.Manual);
_state.ChangeCustomize(state!, data.Customize, CustomizeFlagExtensions.All, StateSource.Manual);
}
ImGui.TableNextColumn();

View file

@ -288,27 +288,24 @@ public class DesignPanel(
private void DrawMetaApplication()
{
using var id = ImRaii.PushId("Meta");
const uint all = 0x0Fu;
var flags = (_selector.Selected!.DoApplyHatVisible() ? 0x01u : 0x00)
| (_selector.Selected!.DoApplyVisorToggle() ? 0x02u : 0x00)
| (_selector.Selected!.DoApplyWeaponVisible() ? 0x04u : 0x00)
| (_selector.Selected!.DoApplyWetness() ? 0x08u : 0x00);
const uint all = (uint)MetaExtensions.All;
var flags = (uint)_selector.Selected!.ApplyMeta;
var bigChange = ImGui.CheckboxFlags("Apply All Meta Changes", ref flags, all);
var apply = bigChange ? (flags & 0x01) == 0x01 : _selector.Selected!.DoApplyHatVisible();
if (ImGui.Checkbox("Apply Hat Visibility", ref apply) || bigChange)
var labels = new[]
{
"Apply Hat Visibility",
"Apply Visor State",
"Apply Weapon Visibility",
"Apply Wetness",
};
foreach (var (index, label) in MetaExtensions.AllRelevant.Zip(labels))
{
var apply = bigChange ? ((MetaFlag)flags).HasFlag(index.ToFlag()) : _selector.Selected!.DoApplyMeta(index);
if (ImGui.Checkbox(label, ref apply) || bigChange)
_manager.ChangeApplyMeta(_selector.Selected!, MetaIndex.HatState, apply);
apply = bigChange ? (flags & 0x02) == 0x02 : _selector.Selected!.DoApplyVisorToggle();
if (ImGui.Checkbox("Apply Visor State", ref apply) || bigChange)
_manager.ChangeApplyMeta(_selector.Selected!, MetaIndex.VisorState, apply);
apply = bigChange ? (flags & 0x04) == 0x04 : _selector.Selected!.DoApplyWeaponVisible();
if (ImGui.Checkbox("Apply Weapon Visibility", ref apply) || bigChange)
_manager.ChangeApplyMeta(_selector.Selected!, MetaIndex.WeaponState, apply);
apply = bigChange ? (flags & 0x08) == 0x08 : _selector.Selected!.DoApplyWetness();
if (ImGui.Checkbox("Apply Wetness", ref apply) || bigChange)
_manager.ChangeApplyMeta(_selector.Selected!, MetaIndex.Wetness, apply);
}
}
private void DrawParameterApplication()
@ -442,7 +439,7 @@ public class DesignPanel(
{
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
using var _ = _selector.Selected!.TemporarilyRestrictApplication(applyGear, applyCustomize, applyCrest, applyParameters);
_state.ApplyDesign(_selector.Selected!, state, StateChanged.Source.Manual);
_state.ApplyDesign(_selector.Selected!, state, StateSource.Manual);
}
}
@ -461,7 +458,7 @@ public class DesignPanel(
{
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
using var _ = _selector.Selected!.TemporarilyRestrictApplication(applyGear, applyCustomize, applyCrest, applyParameters);
_state.ApplyDesign(_selector.Selected!, state, StateChanged.Source.Manual);
_state.ApplyDesign(_selector.Selected!, state, StateSource.Manual);
}
}

View file

@ -202,7 +202,7 @@ public class NpcPanel(
{
var (applyGear, applyCustomize, _, _) = UiHelpers.ConvertKeysToFlags();
var design = _converter.Convert(ToDesignData(), applyGear, applyCustomize, 0, 0);
_state.ApplyDesign(design, state, StateChanged.Source.Manual);
_state.ApplyDesign(design, state, StateSource.Manual);
}
}
@ -221,7 +221,7 @@ public class NpcPanel(
{
var (applyGear, applyCustomize, _, _) = UiHelpers.ConvertKeysToFlags();
var design = _converter.Convert(ToDesignData(), applyGear, applyCustomize, 0, 0);
_state.ApplyDesign(design, state, StateChanged.Source.Manual);
_state.ApplyDesign(design, state, StateSource.Manual);
}
}

View file

@ -1,5 +1,4 @@
using Glamourer.Designs;
using Glamourer.Events;
using Glamourer.State;
using Penumbra.GameData.Enums;
@ -23,32 +22,17 @@ public ref struct ToggleDrawData
{ }
public static ToggleDrawData FromDesign(MetaIndex index, DesignManager manager, Design design)
=> new()
{
var (label, value, apply, setValue, setApply) = index switch
{
MetaIndex.HatState => ("Hat Visible", design.DesignData.IsHatVisible(), design.DoApplyHatVisible(),
(Action<bool>)(b => manager.ChangeMeta(design, index, b)), (Action<bool>)(b => manager.ChangeApplyMeta(design, index, b))),
MetaIndex.VisorState => ("Visor Toggled", design.DesignData.IsVisorToggled(), design.DoApplyVisorToggle(),
b => manager.ChangeMeta(design, index, b), b => manager.ChangeApplyMeta(design, index, b)),
MetaIndex.WeaponState => ("Weapon Visible", design.DesignData.IsWeaponVisible(), design.DoApplyWeaponVisible(),
b => manager.ChangeMeta(design, index, b), b => manager.ChangeApplyMeta(design, index, b)),
MetaIndex.Wetness => ("Force Wetness", design.DesignData.IsWet(), design.DoApplyWetness(),
b => manager.ChangeMeta(design, index, b), b => manager.ChangeApplyMeta(design, index, b)),
_ => throw new Exception("Unsupported meta index."),
};
return new ToggleDrawData
{
Label = label,
Label = index.ToName(),
Tooltip = string.Empty,
Locked = design.WriteProtected(),
DisplayApplication = true,
CurrentValue = value,
CurrentApply = apply,
SetValue = setValue,
SetApply = setApply,
CurrentValue = design.DesignData.GetMeta(index),
CurrentApply = design.DoApplyMeta(index),
SetValue = b => manager.ChangeMeta(design, index, b),
SetApply = b => manager.ChangeApplyMeta(design, index, b),
};
}
public static ToggleDrawData CrestFromDesign(CrestFlag slot, DesignManager manager, Design design)
=> new()
@ -70,52 +54,27 @@ public ref struct ToggleDrawData
Tooltip = "Hide or show your free company crest on this piece of gear.",
Locked = state.IsLocked,
CurrentValue = state.ModelData.Crest(slot),
SetValue = v => manager.ChangeCrest(state, slot, v, StateChanged.Source.Manual),
SetValue = v => manager.ChangeCrest(state, slot, v, StateSource.Manual),
};
public static ToggleDrawData FromState(MetaIndex index, StateManager manager, ActorState state)
{
var (label, tooltip, value, setValue) = index switch
{
MetaIndex.HatState => ("Hat Visible", "Hide or show the characters head gear.", state.ModelData.IsHatVisible(),
(Action<bool>)(b => manager.ChangeHatState(state, b, StateChanged.Source.Manual))),
MetaIndex.VisorState => ("Visor Toggled", "Toggle the visor state of the characters head gear.",
state.ModelData.IsVisorToggled(),
b => manager.ChangeVisorState(state, b, StateChanged.Source.Manual)),
MetaIndex.WeaponState => ("Weapon Visible", "Hide or show the characters weapons when not drawn.",
state.ModelData.IsWeaponVisible(),
b => manager.ChangeWeaponState(state, b, StateChanged.Source.Manual)),
MetaIndex.Wetness => ("Force Wetness", "Force the character to be wet or not.", state.ModelData.IsWet(),
b => manager.ChangeWetness(state, b, StateChanged.Source.Manual)),
_ => throw new Exception("Unsupported meta index."),
};
return new ToggleDrawData
{
Label = label,
Tooltip = tooltip,
Label = index.ToName(),
Tooltip = index.ToTooltip(),
Locked = state.IsLocked,
CurrentValue = value,
SetValue = setValue,
CurrentValue = state.ModelData.GetMeta(index),
SetValue = b => manager.ChangeMeta(state, index, b, StateSource.Manual),
};
}
public static ToggleDrawData FromValue(MetaIndex index, bool value)
=> new()
{
var (label, tooltip) = index switch
{
MetaIndex.HatState => ("Hat Visible", "Hide or show the characters head gear."),
MetaIndex.VisorState => ("Visor Toggled", "Toggle the visor state of the characters head gear."),
MetaIndex.WeaponState => ("Weapon Visible", "Hide or show the characters weapons when not drawn."),
MetaIndex.Wetness => ("Force Wetness", "Force the character to be wet or not."),
_ => throw new Exception("Unsupported meta index."),
};
return new ToggleDrawData
{
Label = label,
Tooltip = tooltip,
Label = index.ToName(),
Tooltip = index.ToTooltip(),
Locked = true,
CurrentValue = value,
};
}
}

View file

@ -118,14 +118,14 @@ public class ContextMenuService : IDisposable
return;
var slot = item.Type.ToSlot();
_state.ChangeEquip(state, slot, item, 0, StateChanged.Source.Manual);
_state.ChangeEquip(state, slot, item, 0, StateSource.Manual);
if (item.Type.ValidOffhand().IsOffhandType())
{
if (item.PrimaryId.Id is > 1600 and < 1651
&& _items.ItemData.TryGetValue(item.ItemId, EquipSlot.Hands, out var gauntlets))
_state.ChangeEquip(state, EquipSlot.Hands, gauntlets, 0, StateChanged.Source.Manual);
_state.ChangeEquip(state, EquipSlot.Hands, gauntlets, 0, StateSource.Manual);
if (_items.ItemData.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand))
_state.ChangeEquip(state, EquipSlot.OffHand, offhand, 0, StateChanged.Source.Manual);
_state.ChangeEquip(state, EquipSlot.OffHand, offhand, 0, StateSource.Manual);
}
};
}
@ -142,14 +142,14 @@ public class ContextMenuService : IDisposable
return;
var slot = item.Type.ToSlot();
_state.ChangeEquip(state, slot, item, 0, StateChanged.Source.Manual);
_state.ChangeEquip(state, slot, item, 0, StateSource.Manual);
if (item.Type.ValidOffhand().IsOffhandType())
{
if (item.PrimaryId.Id is > 1600 and < 1651
&& _items.ItemData.TryGetValue(item.ItemId, EquipSlot.Hands, out var gauntlets))
_state.ChangeEquip(state, EquipSlot.Hands, gauntlets, 0, StateChanged.Source.Manual);
_state.ChangeEquip(state, EquipSlot.Hands, gauntlets, 0, StateSource.Manual);
if (_items.ItemData.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand))
_state.ChangeEquip(state, EquipSlot.OffHand, offhand, 0, StateChanged.Source.Manual);
_state.ChangeEquip(state, EquipSlot.OffHand, offhand, 0, StateSource.Manual);
}
};
}

View file

@ -333,7 +333,7 @@ public class CommandService : IDisposable
foreach (var identifier in identifiers)
{
if (_stateManager.TryGetValue(identifier, out var state))
_stateManager.ResetState(state, StateChanged.Source.Manual);
_stateManager.ResetState(state, StateSource.Manual);
}
@ -419,7 +419,7 @@ public class CommandService : IDisposable
if (!_objects.TryGetValue(identifier, out var actors))
{
if (_stateManager.TryGetValue(identifier, out var state))
_stateManager.ApplyDesign(design, state, StateChanged.Source.Manual);
_stateManager.ApplyDesign(design, state, StateSource.Manual);
}
else
{
@ -428,7 +428,7 @@ public class CommandService : IDisposable
if (_stateManager.GetOrCreate(actor.GetIdentifier(_actors), actor, out var state))
{
ApplyModSettings(design, actor, applyMods);
_stateManager.ApplyDesign(design, state, StateChanged.Source.Manual);
_stateManager.ApplyDesign(design, state, StateSource.Manual);
}
}
}

View file

@ -68,13 +68,13 @@ public class ActorState
=> Unlock(1337);
/// <summary> This contains whether a change to the base data was made by the game, the user via manual input or through automatic application. </summary>
public readonly StateSource Source = new();
public StateSources Sources = new();
internal ActorState(ActorIdentifier identifier)
=> Identifier = identifier.CreatePermanent();
public CustomizeParameterFlag OnlyChangedParameters()
=> CustomizeParameterExtensions.AllFlags.Where(f => Source[f] is not StateChanged.Source.Game)
=> CustomizeParameterExtensions.AllFlags.Where(f => Sources[f] is not StateSource.Game)
.Aggregate((CustomizeParameterFlag)0, (a, b) => a | b);
public bool UpdateTerritory(ushort territory)

View file

@ -1,4 +1,5 @@
using Glamourer.Events;
using Glamourer.Designs;
using Glamourer.Events;
using Glamourer.GameData;
using Glamourer.Interop;
using Glamourer.Interop.Penumbra;
@ -118,7 +119,7 @@ public class StateApplier(
// If the source is not IPC we do not want to apply restrictions.
var data = GetData(state);
if (apply)
ChangeArmor(data, slot, state.ModelData.Armor(slot), state.Source[slot, false] is not StateChanged.Source.Ipc,
ChangeArmor(data, slot, state.ModelData.Armor(slot), state.Sources[slot, false] is not StateSource.Ipc,
state.ModelData.IsHatVisible());
return data;
@ -200,67 +201,44 @@ public class StateApplier(
_weapon.LoadWeapon(actor, EquipSlot.OffHand, weapon.Weapon().With(stain));
}
/// <summary> Change the visor state of actors only on the draw object. </summary>
public void ChangeVisor(ActorData data, bool value)
/// <summary> Change a meta state. </summary>
public unsafe void ChangeMetaState(ActorData data, MetaIndex index, bool value)
{
foreach (var actor in data.Objects.Where(a => a.Model.IsHuman))
_visor.SetVisorState(actor.Model, value);
}
/// <inheritdoc cref="ChangeVisor(ActorData, bool)"/>
public ActorData ChangeVisor(ActorState state, bool apply)
switch (index)
{
var data = GetData(state);
if (apply)
ChangeVisor(data, state.ModelData.IsVisorToggled());
return data;
}
/// <summary> Change the forced wetness state on actors. </summary>
public unsafe void ChangeWetness(ActorData data, bool value)
case MetaIndex.Wetness:
{
foreach (var actor in data.Objects.Where(a => a.IsCharacter))
actor.AsCharacter->IsGPoseWet = value;
return;
}
/// <inheritdoc cref="ChangeWetness(ActorData, bool)"/>
public ActorData ChangeWetness(ActorState state, bool apply)
{
var data = GetData(state);
if (apply)
ChangeWetness(data, state.ModelData.IsWet());
return data;
}
/// <summary> Change the hat-visibility state on actors. </summary>
public void ChangeHatState(ActorData data, bool value)
case MetaIndex.HatState:
{
foreach (var actor in data.Objects.Where(a => a.IsCharacter))
_metaService.SetHatState(actor, value);
return;
}
/// <inheritdoc cref="ChangeHatState(ActorData, bool)"/>
public ActorData ChangeHatState(ActorState state, bool apply)
{
var data = GetData(state);
if (apply)
ChangeHatState(data, state.ModelData.IsHatVisible());
return data;
}
/// <summary> Change the weapon-visibility state on actors. </summary>
public void ChangeWeaponState(ActorData data, bool value)
case MetaIndex.WeaponState:
{
foreach (var actor in data.Objects.Where(a => a.IsCharacter))
_metaService.SetWeaponState(actor, value);
return;
}
case MetaIndex.VisorState:
{
foreach (var actor in data.Objects.Where(a => a.Model.IsHuman))
_visor.SetVisorState(actor.Model, value);
return;
}
}
}
/// <inheritdoc cref="ChangeWeaponState(ActorData, bool)"/>
public ActorData ChangeWeaponState(ActorState state, bool apply)
/// <inheritdoc cref="ChangeMetaState(ActorData, MetaIndex, bool)"/>
public ActorData ChangeMetaState(ActorState state, MetaIndex index, bool apply)
{
var data = GetData(state);
if (apply)
ChangeWeaponState(data, state.ModelData.IsWeaponVisible());
ChangeMetaState(data, index, state.ModelData.GetMeta(index));
return data;
}

View file

@ -13,7 +13,7 @@ public class StateEditor(CustomizeService customizations, HumanModelList humans,
{
/// <summary> Change the model id. If the actor is changed from a human to another human, customize and equipData are unused. </summary>
/// <remarks> We currently only allow changing things to humans, not humans to monsters. </remarks>
public bool ChangeModelId(ActorState state, uint modelId, in CustomizeArray customize, nint equipData, StateChanged.Source source,
public bool ChangeModelId(ActorState state, uint modelId, in CustomizeArray customize, nint equipData, StateSource source,
out uint oldModelId, uint key = 0)
{
oldModelId = state.ModelData.ModelId;
@ -45,21 +45,21 @@ public class StateEditor(CustomizeService customizations, HumanModelList humans,
state.ModelData.SetHatVisible(true);
state.ModelData.SetWeaponVisible(true);
state.ModelData.SetVisor(false);
state.Source[MetaIndex.ModelId] = source;
state.Source[MetaIndex.HatState] = source;
state.Source[MetaIndex.WeaponState] = source;
state.Source[MetaIndex.VisorState] = source;
state.Sources[MetaIndex.ModelId] = source;
state.Sources[MetaIndex.HatState] = source;
state.Sources[MetaIndex.WeaponState] = source;
state.Sources[MetaIndex.VisorState] = source;
foreach (var slot in EquipSlotExtensions.FullSlots)
{
state.Source[slot, true] = source;
state.Source[slot, false] = source;
state.Sources[slot, true] = source;
state.Sources[slot, false] = source;
}
state.Source[CustomizeIndex.Clan] = source;
state.Source[CustomizeIndex.Gender] = source;
state.Sources[CustomizeIndex.Clan] = source;
state.Sources[CustomizeIndex.Gender] = source;
var set = customizations.Manager.GetSet(state.ModelData.Customize.Clan, state.ModelData.Customize.Gender);
foreach (var index in Enum.GetValues<CustomizeIndex>().Where(set.IsAvailable))
state.Source[index] = source;
state.Sources[index] = source;
}
else
{
@ -67,14 +67,14 @@ public class StateEditor(CustomizeService customizations, HumanModelList humans,
return false;
state.ModelData.LoadNonHuman(modelId, customize, equipData);
state.Source[MetaIndex.ModelId] = source;
state.Sources[MetaIndex.ModelId] = source;
}
return true;
}
/// <summary> Change a customization value. </summary>
public bool ChangeCustomize(ActorState state, CustomizeIndex idx, CustomizeValue value, StateChanged.Source source,
public bool ChangeCustomize(ActorState state, CustomizeIndex idx, CustomizeValue value, StateSource source,
out CustomizeValue old, uint key = 0)
{
old = state.ModelData.Customize[idx];
@ -82,12 +82,12 @@ public class StateEditor(CustomizeService customizations, HumanModelList humans,
return false;
state.ModelData.Customize[idx] = value;
state.Source[idx] = source;
state.Sources[idx] = source;
return true;
}
/// <summary> Change an entire customization array according to flags. </summary>
public bool ChangeHumanCustomize(ActorState state, in CustomizeArray customizeInput, CustomizeFlag applyWhich, StateChanged.Source source,
public bool ChangeHumanCustomize(ActorState state, in CustomizeArray customizeInput, CustomizeFlag applyWhich, StateSource source,
out CustomizeArray old, out CustomizeFlag changed, uint key = 0)
{
old = state.ModelData.Customize;
@ -104,14 +104,14 @@ public class StateEditor(CustomizeService customizations, HumanModelList humans,
foreach (var type in Enum.GetValues<CustomizeIndex>())
{
if (applied.HasFlag(type.ToFlag()))
state.Source[type] = source;
state.Sources[type] = source;
}
return true;
}
/// <summary> Change a single piece of equipment without stain. </summary>
public bool ChangeItem(ActorState state, EquipSlot slot, EquipItem item, StateChanged.Source source, out EquipItem oldItem, uint key = 0)
public bool ChangeItem(ActorState state, EquipSlot slot, EquipItem item, StateSource source, out EquipItem oldItem, uint key = 0)
{
oldItem = state.ModelData.Item(slot);
if (!state.CanUnlock(key))
@ -128,17 +128,17 @@ public class StateEditor(CustomizeService customizations, HumanModelList humans,
gPose.AddActionOnLeave(() =>
{
if (old.Type == state.BaseData.Item(slot).Type)
ChangeItem(state, slot, old, state.Source[slot, false], out _, key);
ChangeItem(state, slot, old, state.Sources[slot, false], out _, key);
});
}
state.ModelData.SetItem(slot, item);
state.Source[slot, false] = source;
state.Sources[slot, false] = source;
return true;
}
/// <summary> Change a single piece of equipment including stain. </summary>
public bool ChangeEquip(ActorState state, EquipSlot slot, EquipItem item, StainId stain, StateChanged.Source source, out EquipItem oldItem,
public bool ChangeEquip(ActorState state, EquipSlot slot, EquipItem item, StainId stain, StateSource source, out EquipItem oldItem,
out StainId oldStain, uint key = 0)
{
oldItem = state.ModelData.Item(slot);
@ -158,43 +158,43 @@ public class StateEditor(CustomizeService customizations, HumanModelList humans,
gPose.AddActionOnLeave(() =>
{
if (old.Type == state.BaseData.Item(slot).Type)
ChangeEquip(state, slot, old, oldS, state.Source[slot, false], out _, out _, key);
ChangeEquip(state, slot, old, oldS, state.Sources[slot, false], out _, out _, key);
});
}
state.ModelData.SetItem(slot, item);
state.ModelData.SetStain(slot, stain);
state.Source[slot, false] = source;
state.Source[slot, true] = source;
state.Sources[slot, false] = source;
state.Sources[slot, true] = source;
return true;
}
/// <summary> Change only the stain of an equipment piece. </summary>
public bool ChangeStain(ActorState state, EquipSlot slot, StainId stain, StateChanged.Source source, out StainId oldStain, uint key = 0)
public bool ChangeStain(ActorState state, EquipSlot slot, StainId stain, StateSource source, out StainId oldStain, uint key = 0)
{
oldStain = state.ModelData.Stain(slot);
if (!state.CanUnlock(key))
return false;
state.ModelData.SetStain(slot, stain);
state.Source[slot, true] = source;
state.Sources[slot, true] = source;
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)
public bool ChangeCrest(ActorState state, CrestFlag slot, bool crest, StateSource source, out bool oldCrest, uint key = 0)
{
oldCrest = state.ModelData.Crest(slot);
if (!state.CanUnlock(key))
return false;
state.ModelData.SetCrest(slot, crest);
state.Source[slot] = source;
state.Sources[slot] = source;
return true;
}
/// <summary> Change the customize flags of a character. </summary>
public bool ChangeParameter(ActorState state, CustomizeParameterFlag flag, CustomizeParameterValue value, StateChanged.Source source,
public bool ChangeParameter(ActorState state, CustomizeParameterFlag flag, CustomizeParameterValue value, StateSource source,
out CustomizeParameterValue oldValue, uint key = 0)
{
oldValue = state.ModelData.Parameters[flag];
@ -202,29 +202,20 @@ public class StateEditor(CustomizeService customizations, HumanModelList humans,
return false;
state.ModelData.Parameters.Set(flag, value);
state.Source[flag] = source;
state.Sources[flag] = source;
return true;
}
public bool ChangeMetaState(ActorState state, MetaIndex index, bool value, StateChanged.Source source, out bool oldValue,
public bool ChangeMetaState(ActorState state, MetaIndex index, bool value, StateSource source, out bool oldValue,
uint key = 0)
{
(var setter, oldValue) = index switch
{
MetaIndex.Wetness => ((Func<bool, bool>)(v => state.ModelData.SetIsWet(v)), state.ModelData.IsWet()),
MetaIndex.HatState => ((Func<bool, bool>)(v => state.ModelData.SetHatVisible(v)), state.ModelData.IsHatVisible()),
MetaIndex.VisorState => ((Func<bool, bool>)(v => state.ModelData.SetVisor(v)), state.ModelData.IsVisorToggled()),
MetaIndex.WeaponState => ((Func<bool, bool>)(v => state.ModelData.SetWeaponVisible(v)),
state.ModelData.IsWeaponVisible()),
_ => throw new Exception("Invalid MetaIndex."),
};
oldValue = state.ModelData.GetMeta(index);
if (!state.CanUnlock(key))
return false;
setter(value);
state.Source[index] = source;
state.ModelData.SetMeta(index, value);
state.Sources[index] = source;
return true;
}
}

View file

@ -0,0 +1,235 @@
using Glamourer.Designs;
using Glamourer.GameData;
using Penumbra.GameData.Enums;
namespace Glamourer.State;
public readonly record struct StateIndex(int Value) : IEqualityOperators<StateIndex, StateIndex, bool>
{
public static readonly StateIndex Invalid = new(-1);
public static implicit operator StateIndex(EquipFlag flag)
=> flag switch
{
EquipFlag.Head => new StateIndex(EquipHead),
EquipFlag.Body => new StateIndex(EquipBody),
EquipFlag.Hands => new StateIndex(EquipHands),
EquipFlag.Legs => new StateIndex(EquipLegs),
EquipFlag.Feet => new StateIndex(EquipFeet),
EquipFlag.Ears => new StateIndex(EquipEars),
EquipFlag.Neck => new StateIndex(EquipNeck),
EquipFlag.Wrist => new StateIndex(EquipWrist),
EquipFlag.RFinger => new StateIndex(EquipRFinger),
EquipFlag.LFinger => new StateIndex(EquipLFinger),
EquipFlag.Mainhand => new StateIndex(EquipMainhand),
EquipFlag.Offhand => new StateIndex(EquipOffhand),
EquipFlag.HeadStain => new StateIndex(StainHead),
EquipFlag.BodyStain => new StateIndex(StainBody),
EquipFlag.HandsStain => new StateIndex(StainHands),
EquipFlag.LegsStain => new StateIndex(StainLegs),
EquipFlag.FeetStain => new StateIndex(StainFeet),
EquipFlag.EarsStain => new StateIndex(StainEars),
EquipFlag.NeckStain => new StateIndex(StainNeck),
EquipFlag.WristStain => new StateIndex(StainWrist),
EquipFlag.RFingerStain => new StateIndex(StainRFinger),
EquipFlag.LFingerStain => new StateIndex(StainLFinger),
EquipFlag.MainhandStain => new StateIndex(StainMainhand),
EquipFlag.OffhandStain => new StateIndex(StainOffhand),
_ => Invalid,
};
public static implicit operator StateIndex(CustomizeIndex index)
=> index switch
{
CustomizeIndex.Race => new StateIndex(CustomizeRace),
CustomizeIndex.Gender => new StateIndex(CustomizeGender),
CustomizeIndex.BodyType => new StateIndex(CustomizeBodyType),
CustomizeIndex.Height => new StateIndex(CustomizeHeight),
CustomizeIndex.Clan => new StateIndex(CustomizeClan),
CustomizeIndex.Face => new StateIndex(CustomizeFace),
CustomizeIndex.Hairstyle => new StateIndex(CustomizeHairstyle),
CustomizeIndex.Highlights => new StateIndex(CustomizeHighlights),
CustomizeIndex.SkinColor => new StateIndex(CustomizeSkinColor),
CustomizeIndex.EyeColorRight => new StateIndex(CustomizeEyeColorRight),
CustomizeIndex.HairColor => new StateIndex(CustomizeHairColor),
CustomizeIndex.HighlightsColor => new StateIndex(CustomizeHighlightsColor),
CustomizeIndex.FacialFeature1 => new StateIndex(CustomizeFacialFeature1),
CustomizeIndex.FacialFeature2 => new StateIndex(CustomizeFacialFeature2),
CustomizeIndex.FacialFeature3 => new StateIndex(CustomizeFacialFeature3),
CustomizeIndex.FacialFeature4 => new StateIndex(CustomizeFacialFeature4),
CustomizeIndex.FacialFeature5 => new StateIndex(CustomizeFacialFeature5),
CustomizeIndex.FacialFeature6 => new StateIndex(CustomizeFacialFeature6),
CustomizeIndex.FacialFeature7 => new StateIndex(CustomizeFacialFeature7),
CustomizeIndex.LegacyTattoo => new StateIndex(CustomizeLegacyTattoo),
CustomizeIndex.TattooColor => new StateIndex(CustomizeTattooColor),
CustomizeIndex.Eyebrows => new StateIndex(CustomizeEyebrows),
CustomizeIndex.EyeColorLeft => new StateIndex(CustomizeEyeColorLeft),
CustomizeIndex.EyeShape => new StateIndex(CustomizeEyeShape),
CustomizeIndex.SmallIris => new StateIndex(CustomizeSmallIris),
CustomizeIndex.Nose => new StateIndex(CustomizeNose),
CustomizeIndex.Jaw => new StateIndex(CustomizeJaw),
CustomizeIndex.Mouth => new StateIndex(CustomizeMouth),
CustomizeIndex.Lipstick => new StateIndex(CustomizeLipstick),
CustomizeIndex.LipColor => new StateIndex(CustomizeLipColor),
CustomizeIndex.MuscleMass => new StateIndex(CustomizeMuscleMass),
CustomizeIndex.TailShape => new StateIndex(CustomizeTailShape),
CustomizeIndex.BustSize => new StateIndex(CustomizeBustSize),
CustomizeIndex.FacePaint => new StateIndex(CustomizeFacePaint),
CustomizeIndex.FacePaintReversed => new StateIndex(CustomizeFacePaintReversed),
CustomizeIndex.FacePaintColor => new StateIndex(CustomizeFacePaintColor),
_ => Invalid,
};
public static implicit operator StateIndex(MetaIndex meta)
=> new((int)meta);
public static implicit operator StateIndex(CrestFlag crest)
=> crest switch
{
CrestFlag.OffHand => new StateIndex(CrestOffhand),
CrestFlag.Head => new StateIndex(CrestHead),
CrestFlag.Body => new StateIndex(CrestBody),
_ => Invalid,
};
public static implicit operator StateIndex(CustomizeParameterFlag param)
=> param switch
{
CustomizeParameterFlag.SkinDiffuse => new StateIndex(ParamSkinDiffuse),
CustomizeParameterFlag.MuscleTone => new StateIndex(ParamMuscleTone),
CustomizeParameterFlag.SkinSpecular => new StateIndex(ParamSkinSpecular),
CustomizeParameterFlag.LipDiffuse => new StateIndex(ParamLipDiffuse),
CustomizeParameterFlag.HairDiffuse => new StateIndex(ParamHairDiffuse),
CustomizeParameterFlag.HairSpecular => new StateIndex(ParamHairSpecular),
CustomizeParameterFlag.HairHighlight => new StateIndex(ParamHairHighlight),
CustomizeParameterFlag.LeftEye => new StateIndex(ParamLeftEye),
CustomizeParameterFlag.RightEye => new StateIndex(ParamRightEye),
CustomizeParameterFlag.FeatureColor => new StateIndex(ParamFeatureColor),
CustomizeParameterFlag.FacePaintUvMultiplier => new StateIndex(ParamFacePaintUvMultiplier),
CustomizeParameterFlag.FacePaintUvOffset => new StateIndex(ParamFacePaintUvOffset),
CustomizeParameterFlag.DecalColor => new StateIndex(ParamDecalColor),
_ => Invalid,
};
public const int EquipHead = 0;
public const int EquipBody = 1;
public const int EquipHands = 2;
public const int EquipLegs = 3;
public const int EquipFeet = 4;
public const int EquipEars = 5;
public const int EquipNeck = 6;
public const int EquipWrist = 7;
public const int EquipRFinger = 8;
public const int EquipLFinger = 9;
public const int EquipMainhand = 10;
public const int EquipOffhand = 11;
public const int StainHead = 12;
public const int StainBody = 13;
public const int StainHands = 14;
public const int StainLegs = 15;
public const int StainFeet = 16;
public const int StainEars = 17;
public const int StainNeck = 18;
public const int StainWrist = 19;
public const int StainRFinger = 20;
public const int StainLFinger = 21;
public const int StainMainhand = 22;
public const int StainOffhand = 23;
public const int CustomizeRace = 24;
public const int CustomizeGender = 25;
public const int CustomizeBodyType = 26;
public const int CustomizeHeight = 27;
public const int CustomizeClan = 28;
public const int CustomizeFace = 29;
public const int CustomizeHairstyle = 30;
public const int CustomizeHighlights = 31;
public const int CustomizeSkinColor = 32;
public const int CustomizeEyeColorRight = 33;
public const int CustomizeHairColor = 34;
public const int CustomizeHighlightsColor = 35;
public const int CustomizeFacialFeature1 = 36;
public const int CustomizeFacialFeature2 = 37;
public const int CustomizeFacialFeature3 = 38;
public const int CustomizeFacialFeature4 = 39;
public const int CustomizeFacialFeature5 = 40;
public const int CustomizeFacialFeature6 = 41;
public const int CustomizeFacialFeature7 = 42;
public const int CustomizeLegacyTattoo = 43;
public const int CustomizeTattooColor = 44;
public const int CustomizeEyebrows = 45;
public const int CustomizeEyeColorLeft = 46;
public const int CustomizeEyeShape = 47;
public const int CustomizeSmallIris = 48;
public const int CustomizeNose = 49;
public const int CustomizeJaw = 50;
public const int CustomizeMouth = 51;
public const int CustomizeLipstick = 52;
public const int CustomizeLipColor = 53;
public const int CustomizeMuscleMass = 54;
public const int CustomizeTailShape = 55;
public const int CustomizeBustSize = 56;
public const int CustomizeFacePaint = 57;
public const int CustomizeFacePaintReversed = 58;
public const int CustomizeFacePaintColor = 59;
public const int MetaWetness = 60;
public const int MetaHatState = 61;
public const int MetaVisorState = 62;
public const int MetaWeaponState = 63;
public const int MetaModelId = 64;
public const int CrestHead = 65;
public const int CrestBody = 66;
public const int CrestOffhand = 67;
public const int ParamSkinDiffuse = 68;
public const int ParamMuscleTone = 69;
public const int ParamSkinSpecular = 70;
public const int ParamLipDiffuse = 71;
public const int ParamHairDiffuse = 72;
public const int ParamHairSpecular = 73;
public const int ParamHairHighlight = 74;
public const int ParamLeftEye = 75;
public const int ParamRightEye = 76;
public const int ParamFeatureColor = 77;
public const int ParamFacePaintUvMultiplier = 78;
public const int ParamFacePaintUvOffset = 79;
public const int ParamDecalColor = 80;
public const int Size = 81;
}
public static class StateExtensions
{
public static StateIndex ToState(this EquipSlot slot, bool stain = false)
=> (slot, stain) switch
{
(EquipSlot.Head, true) => new StateIndex(StateIndex.EquipHead),
(EquipSlot.Body, true) => new StateIndex(StateIndex.EquipBody),
(EquipSlot.Hands, true) => new StateIndex(StateIndex.EquipHands),
(EquipSlot.Legs, true) => new StateIndex(StateIndex.EquipLegs),
(EquipSlot.Feet, true) => new StateIndex(StateIndex.EquipFeet),
(EquipSlot.Ears, true) => new StateIndex(StateIndex.EquipEars),
(EquipSlot.Neck, true) => new StateIndex(StateIndex.EquipNeck),
(EquipSlot.Wrists, true) => new StateIndex(StateIndex.EquipWrist),
(EquipSlot.RFinger, true) => new StateIndex(StateIndex.EquipRFinger),
(EquipSlot.LFinger, true) => new StateIndex(StateIndex.EquipLFinger),
(EquipSlot.MainHand, true) => new StateIndex(StateIndex.EquipMainhand),
(EquipSlot.OffHand, true) => new StateIndex(StateIndex.EquipOffhand),
(EquipSlot.Head, false) => new StateIndex(StateIndex.StainHead),
(EquipSlot.Body, false) => new StateIndex(StateIndex.StainBody),
(EquipSlot.Hands, false) => new StateIndex(StateIndex.StainHands),
(EquipSlot.Legs, false) => new StateIndex(StateIndex.StainLegs),
(EquipSlot.Feet, false) => new StateIndex(StateIndex.StainFeet),
(EquipSlot.Ears, false) => new StateIndex(StateIndex.StainEars),
(EquipSlot.Neck, false) => new StateIndex(StateIndex.StainNeck),
(EquipSlot.Wrists, false) => new StateIndex(StateIndex.StainWrist),
(EquipSlot.RFinger, false) => new StateIndex(StateIndex.StainRFinger),
(EquipSlot.LFinger, false) => new StateIndex(StateIndex.StainLFinger),
(EquipSlot.MainHand, false) => new StateIndex(StateIndex.StainMainhand),
(EquipSlot.OffHand, false) => new StateIndex(StateIndex.StainOffhand),
_ => StateIndex.Invalid,
};
}

View file

@ -164,21 +164,21 @@ public class StateListener : IDisposable
var model = state.ModelData.Customize;
if (customize.Gender != model.Gender || customize.Clan != model.Clan)
{
_manager.ChangeCustomize(state, in customize, CustomizeFlagExtensions.AllRelevant, StateChanged.Source.Game);
_manager.ChangeCustomize(state, in customize, CustomizeFlagExtensions.AllRelevant, StateSource.Game);
return;
}
var set = _customizations.Manager.GetSet(model.Clan, model.Gender);
foreach (var index in CustomizationExtensions.AllBasic)
{
if (state.Source[index] is not StateChanged.Source.Fixed)
if (state.Sources[index] is not StateSource.Fixed)
{
var newValue = customize[index];
var oldValue = model[index];
if (newValue != oldValue)
{
if (set.Validate(index, newValue, out _, model.Face))
_manager.ChangeCustomize(state, index, newValue, StateChanged.Source.Game);
_manager.ChangeCustomize(state, index, newValue, StateSource.Game);
else
customize[index] = oldValue;
}
@ -214,7 +214,7 @@ public class StateListener : IDisposable
&& _manager.TryGetValue(identifier, out var state))
{
HandleEquipSlot(actor, state, slot, ref armor);
locked = state.Source[slot, false] is StateChanged.Source.Ipc;
locked = state.Sources[slot, false] is StateSource.Ipc;
}
_funModule.ApplyFunToSlot(actor, ref armor, slot);
@ -241,10 +241,10 @@ public class StateListener : IDisposable
continue;
var changed = changedItem.Weapon(stain);
if (current.Value == changed.Value && state.Source[slot, false] is not StateChanged.Source.Fixed and not StateChanged.Source.Ipc)
if (current.Value == changed.Value && state.Sources[slot, false] is not StateSource.Fixed and not StateSource.Ipc)
{
_manager.ChangeItem(state, slot, currentItem, StateChanged.Source.Game);
_manager.ChangeStain(state, slot, current.Stain, StateChanged.Source.Game);
_manager.ChangeItem(state, slot, currentItem, StateSource.Game);
_manager.ChangeStain(state, slot, current.Stain, StateSource.Game);
switch (slot)
{
case EquipSlot.MainHand:
@ -252,7 +252,7 @@ public class StateListener : IDisposable
_applier.ChangeWeapon(objects, slot, currentItem, stain);
break;
default:
_applier.ChangeArmor(objects, slot, current.ToArmor(), state.Source[slot, false] is not StateChanged.Source.Ipc,
_applier.ChangeArmor(objects, slot, current.ToArmor(), state.Sources[slot, false] is not StateSource.Ipc,
state.ModelData.IsHatVisible());
break;
}
@ -286,13 +286,13 @@ public class StateListener : IDisposable
// Do nothing. But this usually can not happen because the hooked function also writes to game objects later.
case UpdateState.Transformed: break;
case UpdateState.Change:
if (state.Source[slot, false] is not StateChanged.Source.Fixed and not StateChanged.Source.Ipc)
_manager.ChangeItem(state, slot, state.BaseData.Item(slot), StateChanged.Source.Game);
if (state.Sources[slot, false] is not StateSource.Fixed and not StateSource.Ipc)
_manager.ChangeItem(state, slot, state.BaseData.Item(slot), StateSource.Game);
else
apply = true;
if (state.Source[slot, true] is not StateChanged.Source.Fixed and not StateChanged.Source.Ipc)
_manager.ChangeStain(state, slot, state.BaseData.Stain(slot), StateChanged.Source.Game);
if (state.Sources[slot, true] is not StateSource.Fixed and not StateSource.Ipc)
_manager.ChangeStain(state, slot, state.BaseData.Stain(slot), StateSource.Game);
else
apply = true;
break;
@ -385,13 +385,13 @@ public class StateListener : IDisposable
// Update model state if not on fixed design.
case UpdateState.Change:
var apply = false;
if (state.Source[slot, false] is not StateChanged.Source.Fixed and not StateChanged.Source.Ipc)
_manager.ChangeItem(state, slot, state.BaseData.Item(slot), StateChanged.Source.Game);
if (state.Sources[slot, false] is not StateSource.Fixed and not StateSource.Ipc)
_manager.ChangeItem(state, slot, state.BaseData.Item(slot), StateSource.Game);
else
apply = true;
if (state.Source[slot, true] is not StateChanged.Source.Fixed and not StateChanged.Source.Ipc)
_manager.ChangeStain(state, slot, state.BaseData.Stain(slot), StateChanged.Source.Game);
if (state.Sources[slot, true] is not StateSource.Fixed and not StateSource.Ipc)
_manager.ChangeStain(state, slot, state.BaseData.Stain(slot), StateSource.Game);
else
apply = true;
@ -419,8 +419,8 @@ public class StateListener : IDisposable
switch (UpdateBaseCrest(actor, state, slot, value))
{
case UpdateState.Change:
if (state.Source[slot] is not StateChanged.Source.Fixed and not StateChanged.Source.Ipc)
_manager.ChangeCrest(state, slot, state.BaseData.Crest(slot), StateChanged.Source.Game);
if (state.Sources[slot] is not StateSource.Fixed and not StateSource.Ipc)
_manager.ChangeCrest(state, slot, state.BaseData.Crest(slot), StateSource.Game);
else
value = state.ModelData.Crest(slot);
break;
@ -565,10 +565,10 @@ 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.Source[MetaIndex.VisorState] is StateChanged.Source.Fixed or StateChanged.Source.Ipc)
if (state.Sources[MetaIndex.VisorState] is StateSource.Fixed or StateSource.Ipc)
value = state.ModelData.IsVisorToggled();
else
_manager.ChangeVisorState(state, value, StateChanged.Source.Game);
_manager.ChangeMeta(state, MetaIndex.VisorState, value, StateSource.Game);
}
else
{
@ -598,10 +598,10 @@ 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.Source[MetaIndex.HatState] is StateChanged.Source.Fixed or StateChanged.Source.Ipc)
if (state.Sources[MetaIndex.HatState] is StateSource.Fixed or StateSource.Ipc)
value = state.ModelData.IsHatVisible();
else
_manager.ChangeHatState(state, value, StateChanged.Source.Game);
_manager.ChangeMeta(state, MetaIndex.HatState, value, StateSource.Game);
}
else
{
@ -631,10 +631,10 @@ 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.Source[MetaIndex.WeaponState] is StateChanged.Source.Fixed or StateChanged.Source.Ipc)
if (state.Sources[MetaIndex.WeaponState] is StateSource.Fixed or StateSource.Ipc)
value = state.ModelData.IsWeaponVisible();
else
_manager.ChangeWeaponState(state, value, StateChanged.Source.Game);
_manager.ChangeMeta(state, MetaIndex.WeaponState, value, StateSource.Game);
}
else
{
@ -700,9 +700,9 @@ public class StateListener : IDisposable
return;
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());
_applier.ChangeMetaState(data, MetaIndex.HatState, _creatingState.ModelData.IsHatVisible());
_applier.ChangeMetaState(data, MetaIndex.Wetness, _creatingState.ModelData.IsWet());
_applier.ChangeMetaState(data, MetaIndex.WeaponState, _creatingState.ModelData.IsWeaponVisible());
ApplyParameters(_creatingState, drawObject);
}
@ -733,30 +733,30 @@ public class StateListener : IDisposable
foreach (var flag in CustomizeParameterExtensions.AllFlags)
{
var newValue = data[flag];
switch (state.Source[flag])
switch (state.Sources[flag])
{
case StateChanged.Source.Game:
case StateSource.Game:
if (state.BaseData.Parameters.Set(flag, newValue))
_manager.ChangeCustomizeParameter(state, flag, newValue, StateChanged.Source.Game);
_manager.ChangeCustomizeParameter(state, flag, newValue, StateSource.Game);
break;
case StateChanged.Source.Manual:
case StateSource.Manual:
if (state.BaseData.Parameters.Set(flag, newValue))
_manager.ChangeCustomizeParameter(state, flag, newValue, StateChanged.Source.Game);
_manager.ChangeCustomizeParameter(state, flag, newValue, StateSource.Game);
else if (_config.UseAdvancedParameters)
model.ApplySingleParameterData(flag, state.ModelData.Parameters);
break;
case StateChanged.Source.Fixed:
case StateSource.Fixed:
state.BaseData.Parameters.Set(flag, newValue);
if (_config.UseAdvancedParameters)
model.ApplySingleParameterData(flag, state.ModelData.Parameters);
break;
case StateChanged.Source.Ipc:
case StateSource.Ipc:
state.BaseData.Parameters.Set(flag, newValue);
model.ApplySingleParameterData(flag, state.ModelData.Parameters);
break;
case StateChanged.Source.Pending:
case StateSource.Pending:
state.BaseData.Parameters.Set(flag, newValue);
state.Source[flag] = StateChanged.Source.Manual;
state.Sources[flag] = StateSource.Manual;
if (_config.UseAdvancedParameters)
model.ApplySingleParameterData(flag, state.ModelData.Parameters);
break;

View file

@ -207,58 +207,58 @@ public class StateManager(
#region Change Values
/// <summary> Turn an actor human. </summary>
public void TurnHuman(ActorState state, StateChanged.Source source, uint key = 0)
public void TurnHuman(ActorState state, StateSource source, uint key = 0)
=> ChangeModelId(state, 0, CustomizeArray.Default, nint.Zero, source, key);
/// <summary> Turn an actor to. </summary>
public void ChangeModelId(ActorState state, uint modelId, CustomizeArray customize, nint equipData, StateChanged.Source source,
public void ChangeModelId(ActorState state, uint modelId, CustomizeArray customize, nint equipData, StateSource source,
uint key = 0)
{
if (!_editor.ChangeModelId(state, modelId, customize, equipData, source, out var old, key))
return;
var actors = _applier.ForceRedraw(state, source is StateChanged.Source.Manual or StateChanged.Source.Ipc);
var actors = _applier.ForceRedraw(state, source is StateSource.Manual or StateSource.Ipc);
Glamourer.Log.Verbose(
$"Set model id in state {state.Identifier.Incognito(null)} from {old} to {modelId}. [Affecting {actors.ToLazyString("nothing")}.]");
_event.Invoke(StateChanged.Type.Model, source, state, actors, (old, modelId));
}
/// <summary> Change a customization value. </summary>
public void ChangeCustomize(ActorState state, CustomizeIndex idx, CustomizeValue value, StateChanged.Source source, uint key = 0)
public void ChangeCustomize(ActorState state, CustomizeIndex idx, CustomizeValue value, StateSource source, uint key = 0)
{
if (!_editor.ChangeCustomize(state, idx, value, source, out var old, key))
return;
var actors = _applier.ChangeCustomize(state, source is StateChanged.Source.Manual or StateChanged.Source.Ipc);
var actors = _applier.ChangeCustomize(state, source is StateSource.Manual or StateSource.Ipc);
Glamourer.Log.Verbose(
$"Set {idx.ToDefaultName()} customizations in state {state.Identifier.Incognito(null)} from {old.Value} to {value.Value}. [Affecting {actors.ToLazyString("nothing")}.]");
_event.Invoke(StateChanged.Type.Customize, source, state, actors, (old, value, idx));
}
/// <summary> Change an entire customization array according to flags. </summary>
public void ChangeCustomize(ActorState state, in CustomizeArray customizeInput, CustomizeFlag apply, StateChanged.Source source,
public void ChangeCustomize(ActorState state, in CustomizeArray customizeInput, CustomizeFlag apply, StateSource source,
uint key = 0)
{
if (!_editor.ChangeHumanCustomize(state, customizeInput, apply, source, out var old, out var applied, key))
return;
var actors = _applier.ChangeCustomize(state, source is StateChanged.Source.Manual or StateChanged.Source.Ipc);
var actors = _applier.ChangeCustomize(state, source is StateSource.Manual or StateSource.Ipc);
Glamourer.Log.Verbose(
$"Set {applied} customizations in state {state.Identifier.Incognito(null)} from {old} to {customizeInput}. [Affecting {actors.ToLazyString("nothing")}.]");
_event.Invoke(StateChanged.Type.EntireCustomize, source, state, actors, (old, applied));
}
/// <summary> Change a single piece of equipment without stain. </summary>
/// <remarks> Do not use this in the same frame as ChangeStain, use <see cref="ChangeEquip(ActorState,EquipSlot,EquipItem,StainId,StateChanged.Source,uint)"/> instead. </remarks>
public void ChangeItem(ActorState state, EquipSlot slot, EquipItem item, StateChanged.Source source, uint key = 0)
/// <remarks> Do not use this in the same frame as ChangeStain, use <see cref="ChangeEquip(ActorState,EquipSlot,EquipItem,StainId,StateSource,uint)"/> instead. </remarks>
public void ChangeItem(ActorState state, EquipSlot slot, EquipItem item, StateSource source, uint key = 0)
{
if (!_editor.ChangeItem(state, slot, item, source, out var old, key))
return;
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,
? _applier.ChangeArmor(state, slot, source is StateSource.Manual or StateSource.Ipc)
: _applier.ChangeWeapon(state, slot, source is StateSource.Manual or StateSource.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")}.]");
@ -266,15 +266,15 @@ public class StateManager(
}
/// <summary> Change a single piece of equipment including stain. </summary>
public void ChangeEquip(ActorState state, EquipSlot slot, EquipItem item, StainId stain, StateChanged.Source source, uint key = 0)
public void ChangeEquip(ActorState state, EquipSlot slot, EquipItem item, StainId stain, StateSource source, uint key = 0)
{
if (!_editor.ChangeEquip(state, slot, item, stain, source, out var old, out var oldStain, key))
return;
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,
? _applier.ChangeArmor(state, slot, source is StateSource.Manual or StateSource.Ipc)
: _applier.ChangeWeapon(state, slot, source is StateSource.Manual or StateSource.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.Id} to {stain.Id}. [Affecting {actors.ToLazyString("nothing")}.]");
@ -283,25 +283,25 @@ public class StateManager(
}
/// <summary> Change only the stain of an equipment piece. </summary>
/// <remarks> Do not use this in the same frame as ChangeEquip, use <see cref="ChangeEquip(ActorState,EquipSlot,EquipItem,StainId,StateChanged.Source,uint)"/> instead. </remarks>
public void ChangeStain(ActorState state, EquipSlot slot, StainId stain, StateChanged.Source source, uint key = 0)
/// <remarks> Do not use this in the same frame as ChangeEquip, use <see cref="ChangeEquip(ActorState,EquipSlot,EquipItem,StainId,StateSource,uint)"/> instead. </remarks>
public void ChangeStain(ActorState state, EquipSlot slot, StainId stain, StateSource source, uint key = 0)
{
if (!_editor.ChangeStain(state, slot, stain, source, out var old, key))
return;
var actors = _applier.ChangeStain(state, slot, source is StateChanged.Source.Manual or StateChanged.Source.Ipc);
var actors = _applier.ChangeStain(state, slot, source is StateSource.Manual or StateSource.Ipc);
Glamourer.Log.Verbose(
$"Set {slot.ToName()} stain in state {state.Identifier.Incognito(null)} from {old.Id} to {stain.Id}. [Affecting {actors.ToLazyString("nothing")}.]");
_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)
public void ChangeCrest(ActorState state, CrestFlag slot, bool crest, StateSource 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);
var actors = _applier.ChangeCrests(state, source is StateSource.Manual or StateSource.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));
@ -309,7 +309,7 @@ public class StateManager(
/// <summary> Change the crest of an equipment piece. </summary>
public void ChangeCustomizeParameter(ActorState state, CustomizeParameterFlag flag, CustomizeParameterValue value,
StateChanged.Source source, uint key = 0)
StateSource source, uint key = 0)
{
// Also apply main color to highlights when highlights is off.
if (!state.ModelData.Customize.Highlights && flag is CustomizeParameterFlag.HairDiffuse)
@ -319,63 +319,27 @@ public class StateManager(
return;
var @new = state.ModelData.Parameters[flag];
var actors = _applier.ChangeParameters(state, flag, source is StateChanged.Source.Manual or StateChanged.Source.Ipc);
var actors = _applier.ChangeParameters(state, flag, source is StateSource.Manual or StateSource.Ipc);
Glamourer.Log.Verbose(
$"Set {flag} crest in state {state.Identifier.Incognito(null)} from {old} to {@new}. [Affecting {actors.ToLazyString("nothing")}.]");
_event.Invoke(StateChanged.Type.Parameter, source, state, actors, (old, @new, flag));
}
/// <summary> Change hat visibility. </summary>
public void ChangeHatState(ActorState state, bool value, StateChanged.Source source, uint key = 0)
/// <summary> Change meta state. </summary>
public void ChangeMeta(ActorState state, MetaIndex meta, bool value, StateSource source, uint key = 0)
{
if (!_editor.ChangeMetaState(state, MetaIndex.HatState, value, source, out var old, key))
if (!_editor.ChangeMetaState(state, meta, value, source, out var old, key))
return;
var actors = _applier.ChangeHatState(state, source is StateChanged.Source.Manual or StateChanged.Source.Ipc);
var actors = _applier.ChangeMetaState(state, meta, source is StateSource.Manual or StateSource.Ipc);
Glamourer.Log.Verbose(
$"Set Head Gear Visibility in state {state.Identifier.Incognito(null)} from {old} to {value}. [Affecting {actors.ToLazyString("nothing")}.]");
_event.Invoke(StateChanged.Type.Other, source, state, actors, (old, value, MetaIndex.HatState));
}
/// <summary> Change weapon visibility. </summary>
public void ChangeWeaponState(ActorState state, bool value, StateChanged.Source source, uint key = 0)
{
if (!_editor.ChangeMetaState(state, MetaIndex.WeaponState, value, source, out var old, key))
return;
var actors = _applier.ChangeWeaponState(state, source is StateChanged.Source.Manual or StateChanged.Source.Ipc);
Glamourer.Log.Verbose(
$"Set Weapon Visibility in state {state.Identifier.Incognito(null)} from {old} to {value}. [Affecting {actors.ToLazyString("nothing")}.]");
_event.Invoke(StateChanged.Type.Other, source, state, actors, (old, value, MetaIndex.WeaponState));
}
/// <summary> Change visor state. </summary>
public void ChangeVisorState(ActorState state, bool value, StateChanged.Source source, uint key = 0)
{
if (!_editor.ChangeMetaState(state, MetaIndex.VisorState, value, source, out var old, key))
return;
var actors = _applier.ChangeVisor(state, source is StateChanged.Source.Manual or StateChanged.Source.Ipc);
Glamourer.Log.Verbose(
$"Set Visor State in state {state.Identifier.Incognito(null)} from {old} to {value}. [Affecting {actors.ToLazyString("nothing")}.]");
_event.Invoke(StateChanged.Type.Other, source, state, actors, (old, value, MetaIndex.VisorState));
}
/// <summary> Set GPose Wetness. </summary>
public void ChangeWetness(ActorState state, bool value, StateChanged.Source source, uint key = 0)
{
if (!_editor.ChangeMetaState(state, MetaIndex.Wetness, value, source, out var old, key))
return;
var actors = _applier.ChangeWetness(state, true);
Glamourer.Log.Verbose(
$"Set Wetness in state {state.Identifier.Incognito(null)} from {old} to {value}. [Affecting {actors.ToLazyString("nothing")}.]");
_event.Invoke(StateChanged.Type.Other, state.Source[MetaIndex.Wetness], state, actors, (old, value, MetaIndex.Wetness));
}
#endregion
public void ApplyDesign(DesignBase design, ActorState state, StateChanged.Source source, uint key = 0)
public void ApplyDesign(DesignBase design, ActorState state, StateSource source, uint key = 0)
{
if (!_editor.ChangeModelId(state, design.DesignData.ModelId, design.DesignData.Customize, design.GetDesignDataRef().GetEquipmentPtr(),
source,
@ -383,16 +347,16 @@ public class StateManager(
return;
var redraw = oldModelId != design.DesignData.ModelId || !design.DesignData.IsHuman;
if (design.DoApplyWetness())
if (design.DoApplyMeta(MetaIndex.Wetness))
_editor.ChangeMetaState(state, MetaIndex.Wetness, design.DesignData.IsWet(), source, out _, key);
if (state.ModelData.IsHuman)
{
if (design.DoApplyHatVisible())
if (design.DoApplyMeta(MetaIndex.HatState))
_editor.ChangeMetaState(state, MetaIndex.HatState, design.DesignData.IsHatVisible(), source, out _, key);
if (design.DoApplyWeaponVisible())
if (design.DoApplyMeta(MetaIndex.WeaponState))
_editor.ChangeMetaState(state, MetaIndex.WeaponState, design.DesignData.IsWeaponVisible(), source, out _, key);
if (design.DoApplyVisorToggle())
if (design.DoApplyMeta(MetaIndex.VisorState))
_editor.ChangeMetaState(state, MetaIndex.VisorState, design.DesignData.IsVisorToggled(), source, out _, key);
var flags = state.AllowsRedraw(_condition)
@ -407,8 +371,8 @@ public class StateManager(
foreach (var slot in CrestExtensions.AllRelevantSet.Where(design.DoApplyCrest))
_editor.ChangeCrest(state, slot, design.DesignData.Crest(slot), source, out _, key);
var paramSource = source is StateChanged.Source.Manual
? StateChanged.Source.Pending
var paramSource = source is StateSource.Manual
? StateSource.Pending
: source;
foreach (var flag in CustomizeParameterExtensions.AllFlags.Where(design.DoApplyParameter))
@ -418,13 +382,13 @@ public class StateManager(
if (!state.ModelData.Customize.Highlights)
_editor.ChangeParameter(state, CustomizeParameterFlag.HairHighlight,
state.ModelData.Parameters[CustomizeParameterFlag.HairDiffuse],
state.Source[CustomizeParameterFlag.HairDiffuse], out _, key);
state.Sources[CustomizeParameterFlag.HairDiffuse], 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.Source[MetaIndex.Wetness], state, actors, design);
_event.Invoke(StateChanged.Type.Design, state.Sources[MetaIndex.Wetness], state, actors, design);
return;
void HandleEquip(EquipSlot slot, bool applyPiece, bool applyStain)
@ -442,7 +406,7 @@ public class StateManager(
private ActorData ApplyAll(ActorState state, bool redraw, bool withLock)
{
var actors = _applier.ChangeWetness(state, true);
var actors = _applier.ChangeMetaState(state, MetaIndex.Wetness, true);
if (redraw)
{
if (withLock)
@ -454,7 +418,7 @@ public class StateManager(
_applier.ChangeCustomize(actors, state.ModelData.Customize);
foreach (var slot in EquipSlotExtensions.EqdpSlots)
{
_applier.ChangeArmor(actors, slot, state.ModelData.Armor(slot), state.Source[slot, false] is not StateChanged.Source.Ipc,
_applier.ChangeArmor(actors, slot, state.ModelData.Armor(slot), state.Sources[slot, false] is not StateSource.Ipc,
state.ModelData.IsHatVisible());
}
@ -466,9 +430,9 @@ public class StateManager(
if (state.ModelData.IsHuman)
{
_applier.ChangeHatState(actors, state.ModelData.IsHatVisible());
_applier.ChangeWeaponState(actors, state.ModelData.IsWeaponVisible());
_applier.ChangeVisor(actors, state.ModelData.IsVisorToggled());
_applier.ChangeMetaState(actors, MetaIndex.HatState, state.ModelData.IsHatVisible());
_applier.ChangeMetaState(actors, MetaIndex.WeaponState, state.ModelData.IsWeaponVisible());
_applier.ChangeMetaState(actors, MetaIndex.VisorState, state.ModelData.IsVisorToggled());
_applier.ChangeCrests(actors, state.ModelData.CrestVisibility);
_applier.ChangeParameters(actors, state.OnlyChangedParameters(), state.ModelData.Parameters, state.IsLocked);
}
@ -476,7 +440,7 @@ public class StateManager(
return actors;
}
public void ResetState(ActorState state, StateChanged.Source source, uint key = 0)
public void ResetState(ActorState state, StateSource source, uint key = 0)
{
if (!state.Unlock(key))
return;
@ -488,25 +452,25 @@ public class StateManager(
state.ModelData = state.BaseData;
state.ModelData.SetIsWet(false);
foreach (var index in Enum.GetValues<CustomizeIndex>())
state.Source[index] = StateChanged.Source.Game;
state.Sources[index] = StateSource.Game;
foreach (var slot in EquipSlotExtensions.FullSlots)
{
state.Source[slot, true] = StateChanged.Source.Game;
state.Source[slot, false] = StateChanged.Source.Game;
state.Sources[slot, true] = StateSource.Game;
state.Sources[slot, false] = StateSource.Game;
}
foreach (var type in Enum.GetValues<MetaIndex>())
state.Source[type] = StateChanged.Source.Game;
state.Sources[type] = StateSource.Game;
foreach (var slot in CrestExtensions.AllRelevantSet)
state.Source[slot] = StateChanged.Source.Game;
state.Sources[slot] = StateSource.Game;
foreach (var flag in CustomizeParameterExtensions.AllFlags)
state.Source[flag] = StateChanged.Source.Game;
state.Sources[flag] = StateSource.Game;
var actors = ActorData.Invalid;
if (source is StateChanged.Source.Manual or StateChanged.Source.Ipc)
if (source is StateSource.Manual or StateSource.Ipc)
actors = ApplyAll(state, redraw, true);
Glamourer.Log.Verbose(
@ -514,7 +478,7 @@ public class StateManager(
_event.Invoke(StateChanged.Type.Reset, source, state, actors, null);
}
public void ResetAdvancedState(ActorState state, StateChanged.Source source, uint key = 0)
public void ResetAdvancedState(ActorState state, StateSource source, uint key = 0)
{
if (!state.Unlock(key) || !state.ModelData.IsHuman)
return;
@ -522,10 +486,10 @@ public class StateManager(
state.ModelData.Parameters = state.BaseData.Parameters;
foreach (var flag in CustomizeParameterExtensions.AllFlags)
state.Source[flag] = StateChanged.Source.Game;
state.Sources[flag] = StateSource.Game;
var actors = ActorData.Invalid;
if (source is StateChanged.Source.Manual or StateChanged.Source.Ipc)
if (source is StateSource.Manual or StateSource.Ipc)
actors = _applier.ChangeParameters(state, CustomizeParameterExtensions.All, true);
Glamourer.Log.Verbose(
$"Reset advanced customization state of {state.Identifier.Incognito(null)} to game base. [Affecting {actors.ToLazyString("nothing")}.]");
@ -537,69 +501,69 @@ public class StateManager(
if (!state.Unlock(key))
return;
foreach (var index in Enum.GetValues<CustomizeIndex>().Where(i => state.Source[i] is StateChanged.Source.Fixed))
foreach (var index in Enum.GetValues<CustomizeIndex>().Where(i => state.Sources[i] is StateSource.Fixed))
{
state.Source[index] = StateChanged.Source.Game;
state.Sources[index] = StateSource.Game;
state.ModelData.Customize[index] = state.BaseData.Customize[index];
}
foreach (var slot in EquipSlotExtensions.FullSlots)
{
if (state.Source[slot, true] is StateChanged.Source.Fixed)
if (state.Sources[slot, true] is StateSource.Fixed)
{
state.Source[slot, true] = StateChanged.Source.Game;
state.Sources[slot, true] = StateSource.Game;
state.ModelData.SetStain(slot, state.BaseData.Stain(slot));
}
if (state.Source[slot, false] is StateChanged.Source.Fixed)
if (state.Sources[slot, false] is StateSource.Fixed)
{
state.Source[slot, false] = StateChanged.Source.Game;
state.Sources[slot, false] = StateSource.Game;
state.ModelData.SetItem(slot, state.BaseData.Item(slot));
}
}
foreach (var slot in CrestExtensions.AllRelevantSet)
{
if (state.Source[slot] is StateChanged.Source.Fixed)
if (state.Sources[slot] is StateSource.Fixed)
{
state.Source[slot] = StateChanged.Source.Game;
state.Sources[slot] = StateSource.Game;
state.ModelData.SetCrest(slot, state.BaseData.Crest(slot));
}
}
foreach (var flag in CustomizeParameterExtensions.AllFlags)
{
switch (state.Source[flag])
switch (state.Sources[flag])
{
case StateChanged.Source.Fixed:
case StateChanged.Source.Manual when !respectManualPalettes:
state.Source[flag] = StateChanged.Source.Game;
case StateSource.Fixed:
case StateSource.Manual when !respectManualPalettes:
state.Sources[flag] = StateSource.Game;
state.ModelData.Parameters[flag] = state.BaseData.Parameters[flag];
break;
}
}
if (state.Source[MetaIndex.HatState] is StateChanged.Source.Fixed)
if (state.Sources[MetaIndex.HatState] is StateSource.Fixed)
{
state.Source[MetaIndex.HatState] = StateChanged.Source.Game;
state.Sources[MetaIndex.HatState] = StateSource.Game;
state.ModelData.SetHatVisible(state.BaseData.IsHatVisible());
}
if (state.Source[MetaIndex.VisorState] is StateChanged.Source.Fixed)
if (state.Sources[MetaIndex.VisorState] is StateSource.Fixed)
{
state.Source[MetaIndex.VisorState] = StateChanged.Source.Game;
state.Sources[MetaIndex.VisorState] = StateSource.Game;
state.ModelData.SetVisor(state.BaseData.IsVisorToggled());
}
if (state.Source[MetaIndex.WeaponState] is StateChanged.Source.Fixed)
if (state.Sources[MetaIndex.WeaponState] is StateSource.Fixed)
{
state.Source[MetaIndex.WeaponState] = StateChanged.Source.Game;
state.Sources[MetaIndex.WeaponState] = StateSource.Game;
state.ModelData.SetWeaponVisible(state.BaseData.IsWeaponVisible());
}
if (state.Source[MetaIndex.Wetness] is StateChanged.Source.Fixed)
if (state.Sources[MetaIndex.Wetness] is StateSource.Fixed)
{
state.Source[MetaIndex.Wetness] = StateChanged.Source.Game;
state.Sources[MetaIndex.Wetness] = StateSource.Game;
state.ModelData.SetIsWet(state.BaseData.IsWet());
}
}

View file

@ -1,49 +1,75 @@
using Glamourer.GameData;
using Penumbra.GameData.Enums;
using static Glamourer.Events.StateChanged;
using Penumbra.GameData.Enums;
namespace Glamourer.State;
public readonly struct StateSource
public enum StateSource : byte
{
public static readonly int Size = EquipFlagExtensions.NumEquipFlags
+ CustomizationExtensions.NumIndices
+ 5
+ CrestExtensions.AllRelevantSet.Count
+ CustomizeParameterExtensions.AllFlags.Count;
Game,
Manual,
Fixed,
Ipc,
// Only used for CustomizeParameters.
Pending,
}
public unsafe struct StateSources
{
public const int Size = (StateIndex.Size + 1) / 2;
private fixed byte _data[Size];
private readonly Source[] _data = Enumerable.Repeat(Source.Game, Size).ToArray();
public StateSource()
public StateSources()
{ }
public ref Source this[EquipSlot slot, bool stain]
=> ref _data[slot.ToIndex() + (stain ? EquipFlagExtensions.NumEquipFlags / 2 : 0)];
public StateSource this[StateIndex index]
{
get
{
var val = _data[index.Value / 2];
return (StateSource)((index.Value & 1) == 1 ? val >> 4 : val & 0x0F);
}
set
{
var val = _data[index.Value / 2];
if ((index.Value & 1) == 1)
val = (byte)((val & 0x0F) | ((byte)value << 4));
else
val = (byte)((val & 0xF0) | (byte)value);
_data[index.Value / 2] = val;
}
}
public ref Source this[CrestFlag slot]
=> ref _data[EquipFlagExtensions.NumEquipFlags + CustomizationExtensions.NumIndices + 5 + slot.ToInternalIndex()];
public ref Source this[CustomizeIndex type]
=> ref _data[EquipFlagExtensions.NumEquipFlags + (int)type];
public ref Source this[MetaIndex index]
=> ref _data[(int)index];
public ref Source this[CustomizeParameterFlag flag]
=> ref _data[
EquipFlagExtensions.NumEquipFlags
+ CustomizationExtensions.NumIndices
+ 5
+ CrestExtensions.AllRelevantSet.Count
+ flag.ToInternalIndex()];
public StateSource this[EquipSlot slot, bool stain]
{
get => this[slot.ToState(stain)];
set => this[slot.ToState(stain)] = value;
}
public void RemoveFixedDesignSources()
{
for (var i = 0; i < _data.Length; ++i)
for (var i = 0; i < Size; ++i)
{
if (_data[i] is Source.Fixed)
_data[i] = Source.Manual;
var value = _data[i];
switch (value)
{
case (byte)StateSource.Fixed | ((byte)StateSource.Fixed << 4):
_data[i] = (byte)StateSource.Manual | ((byte)StateSource.Manual << 4);
break;
case (byte)StateSource.Game | ((byte)StateSource.Fixed << 4):
case (byte)StateSource.Manual | ((byte)StateSource.Fixed << 4):
case (byte)StateSource.Ipc | ((byte)StateSource.Fixed << 4):
case (byte)StateSource.Pending | ((byte)StateSource.Fixed << 4):
_data[i] = (byte)((value & 0x0F) | ((byte)StateSource.Manual << 4));
break;
case (byte)StateSource.Fixed:
case ((byte)StateSource.Manual << 4) | (byte)StateSource.Fixed:
case ((byte)StateSource.Ipc << 4) | (byte)StateSource.Fixed:
case ((byte)StateSource.Pending << 4) | (byte)StateSource.Fixed:
_data[i] = (byte)((value & 0xF0) | (byte)StateSource.Manual);
break;
}
}
}
}