From 8a954e6e097eecd8f866dcf783da79d36e01ae27 Mon Sep 17 00:00:00 2001 From: Aspher0 <154540490+Aspher0@users.noreply.github.com> Date: Thu, 11 Jul 2024 08:26:22 +0200 Subject: [PATCH] Stains and misc fixes ? --- Glamourer/Designs/DesignBase64Migration.cs | 8 ++--- Glamourer/Designs/DesignConverter.cs | 6 ++-- Glamourer/Designs/DesignData.cs | 34 +++++++++---------- Glamourer/GameData/CustomizeManager.cs | 7 ++-- Glamourer/GameData/CustomizeSetFactory.cs | 4 +-- Glamourer/GameData/NpcData.cs | 6 ++-- .../Gui/Customization/CustomizationDrawer.cs | 5 +-- .../Gui/Tabs/DebugTab/ModelEvaluationPanel.cs | 19 +++++++---- Glamourer/Interop/CharaFile/CmaFile.cs | 9 ++--- .../Interop/Material/MaterialValueManager.cs | 2 +- Glamourer/Interop/Material/PrepareColorSet.cs | 18 +++++----- Glamourer/Interop/ScalingService.cs | 1 + Glamourer/Interop/UpdateSlotService.cs | 10 +++--- Glamourer/Interop/WeaponService.cs | 6 ++-- Glamourer/Services/TextureService.cs | 8 ++--- Glamourer/State/FunEquipSet.cs | 4 +-- Glamourer/State/FunModule.cs | 34 ++++++++++--------- Glamourer/State/InternalStateEditor.cs | 4 +-- Glamourer/State/StateApplier.cs | 29 +++++++++------- Glamourer/State/StateEditor.cs | 33 ++++++++++-------- Glamourer/State/StateListener.cs | 28 +++++++-------- Glamourer/State/StateManager.cs | 16 +++++---- 22 files changed, 157 insertions(+), 134 deletions(-) diff --git a/Glamourer/Designs/DesignBase64Migration.cs b/Glamourer/Designs/DesignBase64Migration.cs index a8b2f7b..963c965 100644 --- a/Glamourer/Designs/DesignBase64Migration.cs +++ b/Glamourer/Designs/DesignBase64Migration.cs @@ -117,7 +117,7 @@ public class DesignBase64Migration } data.SetItem(slot, item); - data.SetStain(slot, mdl.Stain); + data.SetStain(slot, mdl.Stains); } var main = cur[0].Skeleton.Id == 0 @@ -130,7 +130,7 @@ public class DesignBase64Migration } data.SetItem(EquipSlot.MainHand, main); - data.SetStain(EquipSlot.MainHand, cur[0].Stain); + data.SetStain(EquipSlot.MainHand, cur[0].Stains); EquipItem off; // Fist weapon hack @@ -141,7 +141,7 @@ public class DesignBase64Migration if (gauntlet.Valid) { data.SetItem(EquipSlot.Hands, gauntlet); - data.SetStain(EquipSlot.Hands, cur[0].Stain); + data.SetStain(EquipSlot.Hands, cur[0].Stains); } } else @@ -158,7 +158,7 @@ public class DesignBase64Migration } data.SetItem(EquipSlot.OffHand, off); - data.SetStain(EquipSlot.OffHand, cur[1].Stain); + data.SetStain(EquipSlot.OffHand, cur[1].Stains); return data; } } diff --git a/Glamourer/Designs/DesignConverter.cs b/Glamourer/Designs/DesignConverter.cs index f3955c5..7d4eedb 100644 --- a/Glamourer/Designs/DesignConverter.cs +++ b/Glamourer/Designs/DesignConverter.cs @@ -194,7 +194,7 @@ public class DesignConverter( item = ItemManager.NothingItem(slot); } - yield return (slot, item, armor.Stain); + yield return (slot, item, armor.Stains.Stain1); // To change } var mh = _items.Identify(EquipSlot.MainHand, mainhand.Skeleton, mainhand.Weapon, mainhand.Variant); @@ -204,7 +204,7 @@ public class DesignConverter( mh = _items.DefaultSword; } - yield return (EquipSlot.MainHand, mh, mainhand.Stain); + yield return (EquipSlot.MainHand, mh, mainhand.Stains.Stain1); // To change var oh = _items.Identify(EquipSlot.OffHand, offhand.Skeleton, offhand.Weapon, offhand.Variant, mh.Type); if (!skipWarnings && !oh.Valid) @@ -215,7 +215,7 @@ public class DesignConverter( oh = ItemManager.NothingItem(FullEquipType.Shield); } - yield return (EquipSlot.OffHand, oh, offhand.Stain); + yield return (EquipSlot.OffHand, oh, offhand.Stains.Stain1); // To change } private static void ComputeMaterials(DesignMaterialManager manager, in StateMaterialManager materials, diff --git a/Glamourer/Designs/DesignData.cs b/Glamourer/Designs/DesignData.cs index 6b84768..310c54a 100644 --- a/Glamourer/Designs/DesignData.cs +++ b/Glamourer/Designs/DesignData.cs @@ -125,7 +125,7 @@ public unsafe struct DesignData return false; _itemIds[index] = item.ItemId.Id; - _iconIds[index] = item.IconId.Id; + _iconIds[index] = (ushort)item.IconId.Id; _equipmentBytes[4 * index + 0] = (byte)item.PrimaryId.Id; _equipmentBytes[4 * index + 1] = (byte)(item.PrimaryId.Id >> 8); _equipmentBytes[4 * index + 2] = item.Variant.Id; @@ -158,21 +158,21 @@ public unsafe struct DesignData return true; } - public bool SetStain(EquipSlot slot, StainId stain) + public bool SetStain(EquipSlot slot, StainIds stains) => slot.ToIndex() switch { - 0 => SetIfDifferent(ref _equipmentBytes[3], stain.Id), - 1 => SetIfDifferent(ref _equipmentBytes[7], stain.Id), - 2 => SetIfDifferent(ref _equipmentBytes[11], stain.Id), - 3 => SetIfDifferent(ref _equipmentBytes[15], stain.Id), - 4 => SetIfDifferent(ref _equipmentBytes[19], stain.Id), - 5 => SetIfDifferent(ref _equipmentBytes[23], stain.Id), - 6 => SetIfDifferent(ref _equipmentBytes[27], stain.Id), - 7 => SetIfDifferent(ref _equipmentBytes[31], stain.Id), - 8 => SetIfDifferent(ref _equipmentBytes[35], stain.Id), - 9 => SetIfDifferent(ref _equipmentBytes[39], stain.Id), - 10 => SetIfDifferent(ref _equipmentBytes[43], stain.Id), - 11 => SetIfDifferent(ref _equipmentBytes[47], stain.Id), + 0 => SetIfDifferent(ref _equipmentBytes[3], stains), + 1 => SetIfDifferent(ref _equipmentBytes[7], stains), + 2 => SetIfDifferent(ref _equipmentBytes[11], stains), + 3 => SetIfDifferent(ref _equipmentBytes[15], stains), + 4 => SetIfDifferent(ref _equipmentBytes[19], stains), + 5 => SetIfDifferent(ref _equipmentBytes[23], stains), + 6 => SetIfDifferent(ref _equipmentBytes[27], stains), + 7 => SetIfDifferent(ref _equipmentBytes[31], stains), + 8 => SetIfDifferent(ref _equipmentBytes[35], stains), + 9 => SetIfDifferent(ref _equipmentBytes[39], stains), + 10 => SetIfDifferent(ref _equipmentBytes[43], stains), + 11 => SetIfDifferent(ref _equipmentBytes[47], stains), _ => false, }; @@ -260,15 +260,15 @@ public unsafe struct DesignData foreach (var slot in EquipSlotExtensions.EqdpSlots) { SetItem(slot, ItemManager.NothingItem(slot)); - SetStain(slot, 0); + SetStain(slot, StainIds.None); SetCrest(slot.ToCrestFlag(), false); } SetItem(EquipSlot.MainHand, items.DefaultSword); - SetStain(EquipSlot.MainHand, 0); + SetStain(EquipSlot.MainHand, StainIds.None); SetCrest(CrestFlag.MainHand, false); SetItem(EquipSlot.OffHand, ItemManager.NothingItem(FullEquipType.Shield)); - SetStain(EquipSlot.OffHand, 0); + SetStain(EquipSlot.OffHand, StainIds.None); SetCrest(CrestFlag.OffHand, false); } diff --git a/Glamourer/GameData/CustomizeManager.cs b/Glamourer/GameData/CustomizeManager.cs index 37ad48f..b697cd5 100644 --- a/Glamourer/GameData/CustomizeManager.cs +++ b/Glamourer/GameData/CustomizeManager.cs @@ -1,5 +1,6 @@ using Dalamud.Interface.Internal; using Dalamud.Interface.Textures; +using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Plugin.Services; using OtterGui.Classes; using OtterGui.Services; @@ -33,7 +34,7 @@ public class CustomizeManager : IAsyncDataContainer } /// Get specific icons. - public ISharedImmediateTexture GetIcon(uint id) + public IDalamudTextureWrap GetIcon(uint id) => _icons.LoadIcon(id)!; /// Iterate over all supported genders and clans. @@ -48,7 +49,7 @@ public class CustomizeManager : IAsyncDataContainer public CustomizeManager(ITextureProvider textures, IDataManager gameData, IPluginLog log, NpcCustomizeSet npcCustomizeSet) { - _icons = new IconStorage(textures, gameData); + _icons = new TextureCache(gameData, textures); var stopwatch = new Stopwatch(); var tmpTask = Task.Run(() => { @@ -73,7 +74,7 @@ public class CustomizeManager : IAsyncDataContainer public bool Finished => Awaiter.IsCompletedSuccessfully; - private readonly IconStorage _icons; + private readonly TextureCache _icons; private static readonly int ListSize = Clans.Count * Genders.Count; private readonly CustomizeSet[] _customizationSets = new CustomizeSet[ListSize]; diff --git a/Glamourer/GameData/CustomizeSetFactory.cs b/Glamourer/GameData/CustomizeSetFactory.cs index b837034..acee7d5 100644 --- a/Glamourer/GameData/CustomizeSetFactory.cs +++ b/Glamourer/GameData/CustomizeSetFactory.cs @@ -14,11 +14,11 @@ namespace Glamourer.GameData; internal class CustomizeSetFactory( IDataManager _gameData, IPluginLog _log, - IconStorage _icons, + TextureCache _icons, NpcCustomizeSet _npcCustomizeSet, ColorParameters _colors) { - public CustomizeSetFactory(IDataManager gameData, IPluginLog log, IconStorage icons, NpcCustomizeSet npcCustomizeSet) + public CustomizeSetFactory(IDataManager gameData, IPluginLog log, TextureCache icons, NpcCustomizeSet npcCustomizeSet) : this(gameData, log, icons, npcCustomizeSet, new ColorParameters(gameData, log)) { } diff --git a/Glamourer/GameData/NpcData.cs b/Glamourer/GameData/NpcData.cs index 6b5f2bd..334ad9b 100644 --- a/Glamourer/GameData/NpcData.cs +++ b/Glamourer/GameData/NpcData.cs @@ -56,7 +56,7 @@ public unsafe struct NpcData .Append('-') .Append(span[i].Variant.Id.ToString("D3")) .Append('-') - .Append(span[i].Stain.Id.ToString("D3")) + .Append(span[i].Stains.ToString()) .Append(", "); } @@ -66,7 +66,7 @@ public unsafe struct NpcData .Append('-') .Append(Mainhand.Variant.Id.ToString("D3")) .Append('-') - .Append(Mainhand.Stain.Id.ToString("D4")) + .Append(Mainhand.Stains.ToString()) .Append(", ") .Append(Offhand.Skeleton.Id.ToString("D4")) .Append('-') @@ -74,7 +74,7 @@ public unsafe struct NpcData .Append('-') .Append(Offhand.Variant.Id.ToString("D3")) .Append('-') - .Append(Offhand.Stain.Id.ToString("D3")); + .Append(Offhand.Stains.ToString()); return sb.ToString(); } diff --git a/Glamourer/Gui/Customization/CustomizationDrawer.cs b/Glamourer/Gui/Customization/CustomizationDrawer.cs index b73abda..a8c5eb3 100644 --- a/Glamourer/Gui/Customization/CustomizationDrawer.cs +++ b/Glamourer/Gui/Customization/CustomizationDrawer.cs @@ -1,5 +1,6 @@ using Dalamud.Interface.Internal; using Dalamud.Interface.Textures; +using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Interface.Utility; using Dalamud.Plugin; using Glamourer.GameData; @@ -23,7 +24,7 @@ public partial class CustomizationDrawer( : IDisposable { private readonly Vector4 _redTint = new(0.6f, 0.3f, 0.3f, 1f); - private readonly ISharedImmediateTexture? _legacyTattoo = GetLegacyTattooIcon(pi); + private readonly IDalamudTextureWrap? _legacyTattoo = GetLegacyTattooIcon(pi); private Exception? _terminate; @@ -191,7 +192,7 @@ public partial class CustomizationDrawer( _raceSelectorWidth = _inputIntSize + _comboSelectorSize - _framedIconSize.X; } - private static ISharedImmediateTexture? GetLegacyTattooIcon(IDalamudPluginInterface pi) + private static IDalamudTextureWrap? GetLegacyTattooIcon(IDalamudPluginInterface pi) { using var resource = Assembly.GetExecutingAssembly().GetManifestResourceStream("Glamourer.LegacyTattoo.raw"); if (resource == null) diff --git a/Glamourer/Gui/Tabs/DebugTab/ModelEvaluationPanel.cs b/Glamourer/Gui/Tabs/DebugTab/ModelEvaluationPanel.cs index c557064..f6e9fd7 100644 --- a/Glamourer/Gui/Tabs/DebugTab/ModelEvaluationPanel.cs +++ b/Glamourer/Gui/Tabs/DebugTab/ModelEvaluationPanel.cs @@ -177,7 +177,8 @@ public unsafe class ModelEvaluationPanel( { using var id = ImRaii.PushId("Wetness"); ImGuiUtil.DrawTableColumn("Wetness"); - ImGuiUtil.DrawTableColumn(actor.IsCharacter ? actor.AsCharacter->IsGPoseWet ? "GPose" : "None" : "No Character"); + // ImGuiUtil.DrawTableColumn(actor.IsCharacter ? actor.AsCharacter->IsGPoseWet ? "GPose" : "None" : "No Character"); + ImGuiUtil.DrawTableColumn(actor.IsCharacter ? "None" : "No Character"); // Until IsGPoseWet is implemented in Penumbra.GameData var modelString = model.IsCharacterBase ? $"{model.AsCharacterBase->SwimmingWetness:F4} Swimming\n" + $"{model.AsCharacterBase->WeatherWetness:F4} Weather\n" @@ -190,13 +191,19 @@ public unsafe class ModelEvaluationPanel( return; if (ImGui.SmallButton("GPose On")) - actor.AsCharacter->IsGPoseWet = true; + { + // actor.AsCharacter->IsGPoseWet = true; + } ImGui.SameLine(); if (ImGui.SmallButton("GPose Off")) - actor.AsCharacter->IsGPoseWet = false; + { + // actor.AsCharacter->IsGPoseWet = false; + } ImGui.SameLine(); if (ImGui.SmallButton("GPose Toggle")) - actor.AsCharacter->IsGPoseWet = !actor.AsCharacter->IsGPoseWet; + { + // actor.AsCharacter->IsGPoseWet = !actor.AsCharacter->IsGPoseWet; + } } private void DrawEquip(Actor actor, Model model) @@ -214,10 +221,10 @@ public unsafe class ModelEvaluationPanel( if (ImGui.SmallButton("Change Piece")) _updateSlotService.UpdateArmor(model, slot, - new CharacterArmor((PrimaryId)(slot == EquipSlot.Hands ? 6064 : slot == EquipSlot.Head ? 6072 : 1), 1, 0)); + new CharacterArmor((PrimaryId)(slot == EquipSlot.Hands ? 6064 : slot == EquipSlot.Head ? 6072 : 1), 1, new())); ImGui.SameLine(); if (ImGui.SmallButton("Change Stain")) - _updateSlotService.UpdateStain(model, slot, 5); + _updateSlotService.UpdateStain(model, slot, StainIds.None); ImGui.SameLine(); if (ImGui.SmallButton("Reset")) _updateSlotService.UpdateSlot(model, slot, actor.GetArmor(slot)); diff --git a/Glamourer/Interop/CharaFile/CmaFile.cs b/Glamourer/Interop/CharaFile/CmaFile.cs index dab91ac..45d1741 100644 --- a/Glamourer/Interop/CharaFile/CmaFile.cs +++ b/Glamourer/Interop/CharaFile/CmaFile.cs @@ -3,6 +3,7 @@ using Glamourer.Services; using Newtonsoft.Json.Linq; using Penumbra.GameData.Enums; using Penumbra.GameData.Structs; +using System.Diagnostics.Tracing; namespace Glamourer.Interop.CharaFile; @@ -61,7 +62,7 @@ public sealed class CmaFile var armor = ((CharacterArmor*)ptr)[idx]; var item = items.Identify(slot, armor.Set, armor.Variant); data.SetItem(slot, item); - data.SetStain(slot, armor.Stain); + data.SetStain(slot, armor.Stains); } data.Customize.Read(ptr); @@ -74,18 +75,18 @@ public sealed class CmaFile if (mainhand == null) { data.SetItem(EquipSlot.MainHand, items.DefaultSword); - data.SetStain(EquipSlot.MainHand, 0); + data.SetStain(EquipSlot.MainHand, StainIds.None); return; } var set = mainhand["Item1"]?.ToObject() ?? items.DefaultSword.PrimaryId; var type = mainhand["Item2"]?.ToObject() ?? items.DefaultSword.SecondaryId; var variant = mainhand["Item3"]?.ToObject() ?? items.DefaultSword.Variant; - var stain = mainhand["Item4"]?.ToObject() ?? 0; + var stains = mainhand["Item4"]?.ToObject() ?? StainIds.None; var item = items.Identify(EquipSlot.MainHand, set, type, variant); data.SetItem(EquipSlot.MainHand, item.Valid ? item : items.DefaultSword); - data.SetStain(EquipSlot.MainHand, stain); + data.SetStain(EquipSlot.MainHand, stains); } private static void ParseOffHand(ItemManager items, JObject jObj, ref DesignData data) diff --git a/Glamourer/Interop/Material/MaterialValueManager.cs b/Glamourer/Interop/Material/MaterialValueManager.cs index 483e6af..ae08c71 100644 --- a/Glamourer/Interop/Material/MaterialValueManager.cs +++ b/Glamourer/Interop/Material/MaterialValueManager.cs @@ -203,7 +203,7 @@ public struct MaterialValueState( => DrawData.Skeleton == rhsData.Skeleton && DrawData.Weapon == rhsData.Weapon && DrawData.Variant == rhsData.Variant - && DrawData.Stain == rhsData.Stain + && DrawData.Stains == rhsData.Stains && Game.NearEqual(rhsRow); public readonly MaterialValueDesign Convert() diff --git a/Glamourer/Interop/Material/PrepareColorSet.cs b/Glamourer/Interop/Material/PrepareColorSet.cs index 1661037..96b37bc 100644 --- a/Glamourer/Interop/Material/PrepareColorSet.cs +++ b/Glamourer/Interop/Material/PrepareColorSet.cs @@ -54,7 +54,7 @@ public sealed unsafe class PrepareColorSet return _task.Result.Original(characterBase, material, stainId); } - public static bool TryGetColorTable(CharacterBase* characterBase, MaterialResourceHandle* material, StainId stainId, + public static bool TryGetColorTable(CharacterBase* characterBase, MaterialResourceHandle* material, StainIds stainIds, out LegacyColorTable table) { if (material->ColorTable == null) @@ -64,8 +64,8 @@ public sealed unsafe class PrepareColorSet } var newTable = *(LegacyColorTable*)material->ColorTable; - if (stainId.Id != 0) - characterBase->ReadStainingTemplate(material, stainId.Id, (Half*)(&newTable)); + if (stainIds != StainIds.None) + characterBase->ReadStainingTemplate(material, stainIds, (Half*)(&newTable)); table = newTable; return true; } @@ -84,21 +84,21 @@ public sealed unsafe class PrepareColorSet return false; } - return TryGetColorTable(model.AsCharacterBase, handle, GetStain(), out table); + return TryGetColorTable(model.AsCharacterBase, handle, GetStains(), out table); - StainId GetStain() + StainIds GetStains() { switch (index.DrawObject) { case MaterialValueIndex.DrawObjectType.Human: - return index.SlotIndex < 10 ? actor.Model.GetArmor(((uint)index.SlotIndex).ToEquipSlot()).Stain : 0; + return index.SlotIndex < 10 ? actor.Model.GetArmor(((uint)index.SlotIndex).ToEquipSlot()).Stains : new(); case MaterialValueIndex.DrawObjectType.Mainhand: var mainhand = (Model)actor.AsCharacter->DrawData.WeaponDataSpan[1].DrawObject; - return mainhand.IsWeapon ? (StainId)mainhand.AsWeapon->ModelUnknown : 0; + return mainhand.IsWeapon ? (StainId)mainhand.AsWeapon->ModelUnknown : new(); case MaterialValueIndex.DrawObjectType.Offhand: var offhand = (Model)actor.AsCharacter->DrawData.WeaponDataSpan[1].DrawObject; - return offhand.IsWeapon ? (StainId)offhand.AsWeapon->ModelUnknown : 0; - default: return 0; + return offhand.IsWeapon ? (StainId)offhand.AsWeapon->ModelUnknown : new(); + default: return new(); } } } diff --git a/Glamourer/Interop/ScalingService.cs b/Glamourer/Interop/ScalingService.cs index aabaf8f..800efb0 100644 --- a/Glamourer/Interop/ScalingService.cs +++ b/Glamourer/Interop/ScalingService.cs @@ -1,5 +1,6 @@ using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Hooking; +using Dalamud.Interface.Textures; using Dalamud.Plugin.Services; using Dalamud.Utility.Signatures; using FFXIVClientStructs.FFXIV.Client.Game.Character; diff --git a/Glamourer/Interop/UpdateSlotService.cs b/Glamourer/Interop/UpdateSlotService.cs index f2f7423..50cdc77 100644 --- a/Glamourer/Interop/UpdateSlotService.cs +++ b/Glamourer/Interop/UpdateSlotService.cs @@ -31,14 +31,14 @@ public unsafe class UpdateSlotService : IDisposable FlagSlotForUpdateInterop(drawObject, slot, data); } - public void UpdateArmor(Model drawObject, EquipSlot slot, CharacterArmor armor, StainId stain) - => UpdateSlot(drawObject, slot, armor.With(stain)); + public void UpdateArmor(Model drawObject, EquipSlot slot, CharacterArmor armor, StainIds stains) + => UpdateSlot(drawObject, slot, armor.With(stains)); public void UpdateArmor(Model drawObject, EquipSlot slot, CharacterArmor armor) - => UpdateArmor(drawObject, slot, armor, drawObject.GetArmor(slot).Stain); + => UpdateArmor(drawObject, slot, armor, drawObject.GetArmor(slot).Stains); - public void UpdateStain(Model drawObject, EquipSlot slot, StainId stain) - => UpdateArmor(drawObject, slot, drawObject.GetArmor(slot), stain); + public void UpdateStain(Model drawObject, EquipSlot slot, StainIds stains) + => UpdateArmor(drawObject, slot, drawObject.GetArmor(slot), stains); private delegate ulong FlagSlotForUpdateDelegateIntern(nint drawObject, uint slot, CharacterArmor* data); diff --git a/Glamourer/Interop/WeaponService.cs b/Glamourer/Interop/WeaponService.cs index d2aac1a..5ab2a40 100644 --- a/Glamourer/Interop/WeaponService.cs +++ b/Glamourer/Interop/WeaponService.cs @@ -70,7 +70,7 @@ public unsafe class WeaponService : IDisposable if (tmpWeapon.Value != weapon.Value) { if (tmpWeapon.Skeleton.Id == 0) - tmpWeapon.Stain = 0; + tmpWeapon.Stains = StainIds.None; _loadWeaponHook.Original(drawData, slot, tmpWeapon.Value, 1, unk2, 1, unk4); } @@ -107,12 +107,12 @@ public unsafe class WeaponService : IDisposable } } - public void LoadStain(Actor character, EquipSlot slot, StainId stain) + public void LoadStain(Actor character, EquipSlot slot, StainIds stains) { var mdl = character.Model; var (_, _, mh, oh) = mdl.GetWeapons(character); var value = slot == EquipSlot.OffHand ? oh : mh; - var weapon = value.With(value.Skeleton.Id == 0 ? 0 : stain); + var weapon = value.With(value.Skeleton.Id == 0 ? StainIds.None : stains); LoadWeapon(character, slot, weapon); } } diff --git a/Glamourer/Services/TextureService.cs b/Glamourer/Services/TextureService.cs index 4355700..1d193bb 100644 --- a/Glamourer/Services/TextureService.cs +++ b/Glamourer/Services/TextureService.cs @@ -12,7 +12,7 @@ namespace Glamourer.Services; public sealed class TextureService(UiBuilder uiBuilder, IDataManager dataManager, ITextureProvider textureProvider) : TextureCache(dataManager, textureProvider), IDisposable { - private readonly ISharedImmediateTexture?[] _slotIcons = CreateSlotIcons(uiBuilder); + private readonly IDalamudTextureWrap?[] _slotIcons = CreateSlotIcons(uiBuilder); public (nint, Vector2, bool) GetIcon(EquipItem item, EquipSlot slot) { @@ -34,9 +34,9 @@ public sealed class TextureService(UiBuilder uiBuilder, IDataManager dataManager } } - private static ISharedImmediateTexture?[] CreateSlotIcons(UiBuilder uiBuilder) + private static IDalamudTextureWrap?[] CreateSlotIcons(UiBuilder uiBuilder) { - var ret = new ISharedImmediateTexture?[12]; + var ret = new IDalamudTextureWrap?[12]; using var uldWrapper = uiBuilder.LoadUld("ui/uld/ArmouryBoard.uld"); @@ -65,7 +65,7 @@ public sealed class TextureService(UiBuilder uiBuilder, IDataManager dataManager { try { - ret[slot.ToIndex()] = (ISharedImmediateTexture?)uldWrapper.LoadTexturePart("ui/uld/ArmouryBoard_hr1.tex", index)!; + ret[slot.ToIndex()] = uldWrapper.LoadTexturePart("ui/uld/ArmouryBoard_hr1.tex", index)!; } catch (Exception ex) { diff --git a/Glamourer/State/FunEquipSet.cs b/Glamourer/State/FunEquipSet.cs index 91e6419..8610a08 100644 --- a/Glamourer/State/FunEquipSet.cs +++ b/Glamourer/State/FunEquipSet.cs @@ -21,8 +21,8 @@ internal class FunEquipSet { public Group(ushort headS, byte headV, ushort bodyS, byte bodyV, ushort handsS, byte handsV, ushort legsS, byte legsV, ushort feetS, byte feetV, StainId[]? stains = null) - : this(new CharacterArmor(headS, headV, 0), new CharacterArmor(bodyS, bodyV, 0), new CharacterArmor(handsS, handsV, 0), - new CharacterArmor(legsS, legsV, 0), new CharacterArmor(feetS, feetV, 0), stains) + : this(new CharacterArmor(headS, headV, new()), new CharacterArmor(bodyS, bodyV, new()), new CharacterArmor(handsS, handsV, new()), + new CharacterArmor(legsS, legsV, new()), new CharacterArmor(feetS, feetV, new()), stains) { } public static Group FullSetWithoutHat(ushort modelSet, byte variant, StainId[]? stains = null) diff --git a/Glamourer/State/FunModule.cs b/Glamourer/State/FunModule.cs index 0b59f5a..62efc98 100644 --- a/Glamourer/State/FunModule.cs +++ b/Glamourer/State/FunModule.cs @@ -106,7 +106,7 @@ public unsafe class FunModule : IDisposable && actor.OnlineStatus is OnlineStatus.PvEMentor or OnlineStatus.PvPMentor or OnlineStatus.TradeMentor && slot.IsEquipment()) { - armor = new CharacterArmor(6117, 1, 0); + armor = new CharacterArmor(6117, 1, new()); return; } @@ -207,8 +207,10 @@ public unsafe class FunModule : IDisposable private void SetRandomDye(ref CharacterArmor armor) { - var stainIdx = _rng.Next(0, _stains.Length - 1); - armor.Stain = _stains[stainIdx]; + var stainIdx1 = _rng.Next(0, _stains.Length - 1); + var stainIdx2 = _rng.Next(0, _stains.Length - 1); + + armor.Stains = new(_stains[stainIdx1], _stains[stainIdx2]); } private void SetRandomItem(EquipSlot slot, ref CharacterArmor armor) @@ -235,17 +237,17 @@ public unsafe class FunModule : IDisposable private static IReadOnlyList DolphinBodies => [ - new CharacterArmor(6089, 1, 4), // Toad - new CharacterArmor(6089, 1, 4), // Toad - new CharacterArmor(6089, 1, 4), // Toad - new CharacterArmor(6023, 1, 4), // Swine - new CharacterArmor(6023, 1, 4), // Swine - new CharacterArmor(6023, 1, 4), // Swine - new CharacterArmor(6133, 1, 4), // Gaja - new CharacterArmor(6182, 1, 3), // Imp - new CharacterArmor(6182, 1, 3), // Imp - new CharacterArmor(6182, 1, 4), // Imp - new CharacterArmor(6182, 1, 4), // Imp + new CharacterArmor(6089, 1, new(4, 4)), // Toad + new CharacterArmor(6089, 1, new(4, 4)), // Toad + new CharacterArmor(6089, 1, new(4, 4)), // Toad + new CharacterArmor(6023, 1, new(4, 4)), // Swine + new CharacterArmor(6023, 1, new(4, 4)), // Swine + new CharacterArmor(6023, 1, new(4, 4)), // Swine + new CharacterArmor(6133, 1, new(4, 4)), // Gaja + new CharacterArmor(6182, 1, new(3, 3)), // Imp + new CharacterArmor(6182, 1, new(3, 3)), // Imp + new CharacterArmor(6182, 1, new(4, 4)), // Imp + new CharacterArmor(6182, 1, new(4, 4)), // Imp ]; private void SetDolphin(EquipSlot slot, ref CharacterArmor armor) @@ -253,7 +255,7 @@ public unsafe class FunModule : IDisposable armor = slot switch { EquipSlot.Body => DolphinBodies[_rng.Next(0, DolphinBodies.Count - 1)], - EquipSlot.Head => new CharacterArmor(5040, 1, 0), + EquipSlot.Head => new CharacterArmor(5040, 1, new(0, 0)), _ => armor, }; } @@ -270,7 +272,7 @@ public unsafe class FunModule : IDisposable private static void SetCrown(Span armor) { - var clown = new CharacterArmor(6117, 1, 0); + var clown = new CharacterArmor(6117, 1, new()); armor[0] = clown; armor[1] = clown; armor[2] = clown; diff --git a/Glamourer/State/InternalStateEditor.cs b/Glamourer/State/InternalStateEditor.cs index eaf7c21..19a16c8 100644 --- a/Glamourer/State/InternalStateEditor.cs +++ b/Glamourer/State/InternalStateEditor.cs @@ -184,13 +184,13 @@ public class InternalStateEditor( } /// Change only the stain of an equipment piece. - public bool ChangeStain(ActorState state, EquipSlot slot, StainId stain, StateSource source, out StainId oldStain, uint key = 0) + public bool ChangeStain(ActorState state, EquipSlot slot, StainIds stains, 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.ModelData.SetStain(slot, stains); state.Sources[slot, true] = source; return true; } diff --git a/Glamourer/State/StateApplier.cs b/Glamourer/State/StateApplier.cs index 9c06ce5..c813067 100644 --- a/Glamourer/State/StateApplier.cs +++ b/Glamourer/State/StateApplier.cs @@ -130,22 +130,22 @@ public class StateApplier( /// Change the stain of a single piece of armor or weapon. /// If the offhand is empty, the stain will be fixed to 0 to prevent crashes. /// - public void ChangeStain(ActorData data, EquipSlot slot, StainId stain) + public void ChangeStain(ActorData data, EquipSlot slot, StainIds stains) { var idx = slot.ToIndex(); switch (idx) { case < 10: foreach (var actor in data.Objects.Where(a => a.Model.IsHuman)) - _updateSlot.UpdateStain(actor.Model, slot, stain); + _updateSlot.UpdateStain(actor.Model, slot, stains); break; case 10: foreach (var actor in data.Objects.Where(a => a.Model.IsHuman)) - _weapon.LoadStain(actor, EquipSlot.MainHand, stain); + _weapon.LoadStain(actor, EquipSlot.MainHand, stains); break; case 11: foreach (var actor in data.Objects.Where(a => a.Model.IsHuman)) - _weapon.LoadStain(actor, EquipSlot.OffHand, stain); + _weapon.LoadStain(actor, EquipSlot.OffHand, stains); break; } } @@ -162,12 +162,12 @@ public class StateApplier( /// Apply a weapon to the appropriate slot. - public void ChangeWeapon(ActorData data, EquipSlot slot, EquipItem item, StainId stain) + public void ChangeWeapon(ActorData data, EquipSlot slot, EquipItem item, StainIds stains) { if (slot is EquipSlot.MainHand) - ChangeMainhand(data, item, stain); + ChangeMainhand(data, item, stains); else - ChangeOffhand(data, item, stain); + ChangeOffhand(data, item, stains); } /// @@ -186,19 +186,19 @@ public class StateApplier( /// /// Apply a weapon to the mainhand. If the weapon type has no associated offhand type, apply both. /// - public void ChangeMainhand(ActorData data, EquipItem weapon, StainId stain) + public void ChangeMainhand(ActorData data, EquipItem weapon, StainIds stains) { var slot = weapon.Type.ValidOffhand() == FullEquipType.Unknown ? EquipSlot.BothHand : EquipSlot.MainHand; foreach (var actor in data.Objects.Where(a => a.Model.IsHuman)) - _weapon.LoadWeapon(actor, slot, weapon.Weapon().With(stain)); + _weapon.LoadWeapon(actor, slot, weapon.Weapon().With(stains)); } /// Apply a weapon to the offhand. - public void ChangeOffhand(ActorData data, EquipItem weapon, StainId stain) + public void ChangeOffhand(ActorData data, EquipItem weapon, StainIds stains) { - stain = weapon.PrimaryId.Id == 0 ? 0 : stain; + stains = weapon.PrimaryId.Id == 0 ? StainIds.None : stains; foreach (var actor in data.Objects.Where(a => a.Model.IsHuman)) - _weapon.LoadWeapon(actor, EquipSlot.OffHand, weapon.Weapon().With(stain)); + _weapon.LoadWeapon(actor, EquipSlot.OffHand, weapon.Weapon().With(stains)); } /// Change a meta state. @@ -209,7 +209,10 @@ public class StateApplier( case MetaIndex.Wetness: { foreach (var actor in data.Objects.Where(a => a.IsCharacter)) - actor.AsCharacter->IsGPoseWet = value; + { + // Disabled until IsGPoseWet implemented in penumbra.gamedata + // actor.AsCharacter->IsGPoseWet = value; + } return; } case MetaIndex.HatState: diff --git a/Glamourer/State/StateEditor.cs b/Glamourer/State/StateEditor.cs index c20a69d..096d3ad 100644 --- a/Glamourer/State/StateEditor.cs +++ b/Glamourer/State/StateEditor.cs @@ -90,21 +90,21 @@ public class StateEditor( } /// - public void ChangeEquip(object data, EquipSlot slot, EquipItem? item, StainId? stain, ApplySettings settings) + public void ChangeEquip(object data, EquipSlot slot, EquipItem? item, StainIds? stains, ApplySettings settings) { - switch (item.HasValue, stain.HasValue) + switch (item.HasValue, stains.HasValue) { case (false, false): return; case (true, false): ChangeItem(data, slot, item!.Value, settings); return; case (false, true): - ChangeStain(data, slot, stain!.Value, settings); + ChangeStain(data, slot, stains!.Value, settings); return; } var state = (ActorState)data; - if (!Editor.ChangeEquip(state, slot, item ?? state.ModelData.Item(slot), stain ?? state.ModelData.Stain(slot), settings.Source, + if (!Editor.ChangeEquip(state, slot, item ?? state.ModelData.Item(slot), stains ?? state.ModelData.Stain(slot), settings.Source, out var old, out var oldStain, settings.Key)) return; @@ -115,25 +115,25 @@ public class StateEditor( item!.Value.Type != (slot is EquipSlot.MainHand ? state.BaseData.MainhandType : state.BaseData.OffhandType)); if (slot is EquipSlot.MainHand) - ApplyMainhandPeriphery(state, item, stain, settings); + ApplyMainhandPeriphery(state, item, stains, settings); Glamourer.Log.Verbose( $"Set {slot.ToName()} in state {state.Identifier.Incognito(null)} from {old.Name} ({old.ItemId}) to {item!.Value.Name} ({item.Value.ItemId}) and its stain from {oldStain.Id} to {stain!.Value.Id}. [Affecting {actors.ToLazyString("nothing")}.]"); StateChanged.Invoke(type, settings.Source, state, actors, (old, item!.Value, slot)); - StateChanged.Invoke(StateChangeType.Stain, settings.Source, state, actors, (oldStain, stain!.Value, slot)); + StateChanged.Invoke(StateChangeType.Stain, settings.Source, state, actors, (oldStain, stains!.Value, slot)); } /// - public void ChangeStain(object data, EquipSlot slot, StainId stain, ApplySettings settings) + public void ChangeStain(object data, EquipSlot slot, StainIds stains, ApplySettings settings) { var state = (ActorState)data; - if (!Editor.ChangeStain(state, slot, stain, settings.Source, out var old, settings.Key)) + if (!Editor.ChangeStain(state, slot, stains, settings.Source, out var old, settings.Key)) return; var actors = Applier.ChangeStain(state, slot, settings.Source.RequiresChange()); Glamourer.Log.Verbose( - $"Set {slot.ToName()} stain in state {state.Identifier.Incognito(null)} from {old.Id} to {stain.Id}. [Affecting {actors.ToLazyString("nothing")}.]"); - StateChanged.Invoke(StateChangeType.Stain, settings.Source, state, actors, (old, stain, slot)); + $"Set {slot.ToName()} stain in state {state.Identifier.Incognito(null)} from {old.Id} to {stains.ToString()}. [Affecting {actors.ToLazyString("nothing")}.]"); + StateChanged.Invoke(StateChangeType.Stain, settings.Source, state, actors, (old, stains, slot)); } /// @@ -392,19 +392,24 @@ public class StateEditor( /// Apply offhand item and potentially gauntlets if configured. - private void ApplyMainhandPeriphery(ActorState state, EquipItem? newMainhand, StainId? newStain, ApplySettings settings) + private void ApplyMainhandPeriphery(ActorState state, EquipItem? newMainhand, StainIds? newStains, ApplySettings settings) { if (!Config.ChangeEntireItem || !settings.Source.IsManual()) return; var mh = newMainhand ?? state.ModelData.Item(EquipSlot.MainHand); var offhand = newMainhand != null ? Items.GetDefaultOffhand(mh) : state.ModelData.Item(EquipSlot.OffHand); - var stain = newStain ?? state.ModelData.Stain(EquipSlot.MainHand); + var stains = newStains ?? state.ModelData.Stain(EquipSlot.MainHand); if (offhand.Valid) - ChangeEquip(state, EquipSlot.OffHand, offhand, stain, settings); + ChangeEquip(state, EquipSlot.OffHand, offhand, stains, settings); if (mh is { Type: FullEquipType.Fists } && Items.ItemData.Tertiary.TryGetValue(mh.ItemId, out var gauntlets)) ChangeEquip(state, EquipSlot.Hands, newMainhand != null ? gauntlets : state.ModelData.Item(EquipSlot.Hands), - stain, settings); + stains, settings); + } + + public void ChangeEquip(object data, EquipSlot slot, EquipItem? item, StainId? stain, ApplySettings settings = default) + { + throw new NotImplementedException(); } } diff --git a/Glamourer/State/StateListener.cs b/Glamourer/State/StateListener.cs index f3657a7..d3f6e1e 100644 --- a/Glamourer/State/StateListener.cs +++ b/Glamourer/State/StateListener.cs @@ -250,14 +250,14 @@ public class StateListener : IDisposable && current.Weapon == changed.Weapon && !state.Sources[slot, false].IsFixed(); - var stainChanged = current.Stain == changed.Stain && !state.Sources[slot, true].IsFixed(); + var stainChanged = current.Stains == changed.Stains && !state.Sources[slot, true].IsFixed(); switch ((itemChanged, stainChanged)) { case (true, true): - _manager.ChangeEquip(state, slot, currentItem, current.Stain, ApplySettings.Game); + _manager.ChangeEquip(state, slot, currentItem, current.Stains, ApplySettings.Game); if (slot is EquipSlot.MainHand or EquipSlot.OffHand) - _applier.ChangeWeapon(objects, slot, currentItem, current.Stain); + _applier.ChangeWeapon(objects, slot, currentItem, current.Stains); else _applier.ChangeArmor(objects, slot, current.ToArmor(), !state.Sources[slot, false].IsFixed(), state.ModelData.IsHatVisible()); @@ -265,14 +265,14 @@ public class StateListener : IDisposable case (true, false): _manager.ChangeItem(state, slot, currentItem, ApplySettings.Game); if (slot is EquipSlot.MainHand or EquipSlot.OffHand) - _applier.ChangeWeapon(objects, slot, currentItem, model.Stain); + _applier.ChangeWeapon(objects, slot, currentItem, model.Stains); else - _applier.ChangeArmor(objects, slot, current.ToArmor(model.Stain), !state.Sources[slot, false].IsFixed(), + _applier.ChangeArmor(objects, slot, current.ToArmor(model.Stains), !state.Sources[slot, false].IsFixed(), state.ModelData.IsHatVisible()); break; case (false, true): - _manager.ChangeStain(state, slot, current.Stain, ApplySettings.Game); - _applier.ChangeStain(objects, slot, current.Stain); + _manager.ChangeStain(state, slot, current.Stains, ApplySettings.Game); + _applier.ChangeStain(objects, slot, current.Stains); break; } } @@ -332,7 +332,7 @@ public class StateListener : IDisposable else { if (weapon.Skeleton.Id != 0) - weapon = weapon.With(newWeapon.Stain); + weapon = weapon.With(newWeapon.Stains); // Force unlock if necessary. _manager.ChangeItem(state, slot, state.BaseData.Item(slot), ApplySettings.Game with { Key = state.Combination }); } @@ -341,7 +341,7 @@ public class StateListener : IDisposable // Fist Weapon Offhand hack. if (slot is EquipSlot.MainHand && weapon.Skeleton.Id is > 1600 and < 1651) _lastFistOffhand = new CharacterWeapon((PrimaryId)(weapon.Skeleton.Id + 50), weapon.Weapon, weapon.Variant, - weapon.Stain); + weapon.Stains); _funModule.ApplyFunToWeapon(actor, ref weapon, slot); } @@ -365,7 +365,7 @@ public class StateListener : IDisposable { var item = _items.Identify(slot, actorArmor.Set, actorArmor.Variant); state.BaseData.SetItem(EquipSlot.Head, item); - state.BaseData.SetStain(EquipSlot.Head, actorArmor.Stain); + state.BaseData.SetStain(EquipSlot.Head, actorArmor.Stains); return UpdateState.Change; } @@ -378,9 +378,9 @@ public class StateListener : IDisposable var baseData = state.BaseData.Armor(slot); var change = UpdateState.NoChange; - if (baseData.Stain != armor.Stain) + if (baseData.Stains != armor.Stains) { - state.BaseData.SetStain(slot, armor.Stain); + state.BaseData.SetStain(slot, armor.Stains); change = UpdateState.Change; } @@ -503,9 +503,9 @@ public class StateListener : IDisposable if (slot is EquipSlot.OffHand && weapon.Value == 0 && actor.GetMainhand().Skeleton.Id is > 1600 and < 1651) return UpdateState.NoChange; - if (baseData.Stain != weapon.Stain) + if (baseData.Stains != weapon.Stains) { - state.BaseData.SetStain(slot, weapon.Stain); + state.BaseData.SetStain(slot, weapon.Stains); change = UpdateState.Change; } diff --git a/Glamourer/State/StateManager.cs b/Glamourer/State/StateManager.cs index f057580..2be4770 100644 --- a/Glamourer/State/StateManager.cs +++ b/Glamourer/State/StateManager.cs @@ -141,7 +141,7 @@ public sealed class StateManager( var head = ret.IsHatVisible() || ignoreHatState ? model.GetArmor(EquipSlot.Head) : actor.GetArmor(EquipSlot.Head); var headItem = Items.Identify(EquipSlot.Head, head.Set, head.Variant); ret.SetItem(EquipSlot.Head, headItem); - ret.SetStain(EquipSlot.Head, head.Stain); + ret.SetStain(EquipSlot.Head, head.Stains); // The other slots can be used from the draw object. foreach (var slot in EquipSlotExtensions.EqdpSlots.Skip(1)) @@ -149,7 +149,7 @@ public sealed class StateManager( var armor = model.GetArmor(slot); var item = Items.Identify(slot, armor.Set, armor.Variant); ret.SetItem(slot, item); - ret.SetStain(slot, armor.Stain); + ret.SetStain(slot, armor.Stains); } // Weapons use the draw objects of the weapons, but require the game object either way. @@ -171,7 +171,7 @@ public sealed class StateManager( var armor = actor.GetArmor(slot); var item = Items.Identify(slot, armor.Set, armor.Variant); ret.SetItem(slot, item); - ret.SetStain(slot, armor.Stain); + ret.SetStain(slot, armor.Stains); } main = actor.GetMainhand(); @@ -187,13 +187,15 @@ public sealed class StateManager( var mainItem = Items.Identify(EquipSlot.MainHand, main.Skeleton, main.Weapon, main.Variant); var offItem = Items.Identify(EquipSlot.OffHand, off.Skeleton, off.Weapon, off.Variant, mainItem.Type); ret.SetItem(EquipSlot.MainHand, mainItem); - ret.SetStain(EquipSlot.MainHand, main.Stain); + ret.SetStain(EquipSlot.MainHand, main.Stains); ret.SetItem(EquipSlot.OffHand, offItem); - ret.SetStain(EquipSlot.OffHand, off.Stain); + ret.SetStain(EquipSlot.OffHand, off.Stains); // Wetness can technically only be set in GPose or via external tools. // It is only available in the game object. - ret.SetIsWet(actor.AsCharacter->IsGPoseWet); + + // Disabled until IsGPoseWet is implemented in Penumbra.GameData + // ret.SetIsWet(actor.AsCharacter->IsGPoseWet); // Weapon visibility could technically be inferred from the weapon draw objects, // but since we use hat visibility from the game object we can also use weapon visibility from it. @@ -214,7 +216,7 @@ public sealed class StateManager( offhand.Variant = mainhand.Variant; offhand.Weapon = mainhand.Weapon; ret.SetItem(EquipSlot.Hands, gauntlets); - ret.SetStain(EquipSlot.Hands, mainhand.Stain); + ret.SetStain(EquipSlot.Hands, mainhand.Stains); } /// Turn an actor human.