Update API 9 and add data to items.

This commit is contained in:
Ottermandias 2023-10-02 16:56:24 +02:00
parent c98ed04bf3
commit cb0da11529
62 changed files with 524 additions and 268 deletions

View file

@ -20,7 +20,7 @@ internal class CmpFile
public bool Valid
=> _file != null;
public CmpFile(IDataManager gameData)
public CmpFile(IDataManager gameData, IPluginLog log)
{
try
{
@ -36,7 +36,7 @@ internal class CmpFile
}
catch (Exception e)
{
PluginLog.Error("READ THIS\n======== Could not obtain the human.cmp file which is necessary for color sets.\n"
log.Error("READ THIS\n======== Could not obtain the human.cmp file which is necessary for color sets.\n"
+ "======== This usually indicates an error with your index files caused by TexTools modifications.\n"
+ "======== If you have used TexTools before, you will probably need to start over in it to use Glamourer.", e);
_file = null;

View file

@ -1,4 +1,5 @@
using System.Collections.Generic;
using Dalamud.Interface.Internal;
using Dalamud.Plugin.Services;
using Penumbra.GameData.Enums;
@ -11,9 +12,9 @@ public class CustomizationManager : ICustomizationManager
private CustomizationManager()
{ }
public static ICustomizationManager Create(ITextureProvider textures, IDataManager gameData)
public static ICustomizationManager Create(ITextureProvider textures, IDataManager gameData, IPluginLog log)
{
_options ??= new CustomizationOptions(textures, gameData);
_options ??= new CustomizationOptions(textures, gameData, log);
return new CustomizationManager();
}
@ -29,7 +30,7 @@ public class CustomizationManager : ICustomizationManager
public CustomizationSet GetList(SubRace clan, Gender gender)
=> _options!.GetList(clan, gender);
public ImGuiScene.TextureWrap GetIcon(uint iconId)
public IDalamudTextureWrap GetIcon(uint iconId)
=> _options!.GetIcon(iconId);
public string GetName(CustomName name)

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Dalamud;
using Dalamud.Interface.Internal;
using Dalamud.Plugin.Services;
using Dalamud.Utility;
using Lumina.Excel;
@ -34,7 +35,7 @@ public partial class CustomizationOptions
=> _customizationSets[ToIndex(race, gender)];
// Get specific icons.
internal ImGuiScene.TextureWrap GetIcon(uint id)
internal IDalamudTextureWrap GetIcon(uint id)
=> _icons.LoadIcon(id)!;
private readonly IconStorage _icons;
@ -61,9 +62,9 @@ public partial class CustomizationOptions
public string GetName(CustomName name)
=> _names[(int)name];
internal CustomizationOptions(ITextureProvider textures, IDataManager gameData)
internal CustomizationOptions(ITextureProvider textures, IDataManager gameData, IPluginLog log)
{
var tmp = new TemporaryData(gameData, this);
var tmp = new TemporaryData(gameData, this, log);
_icons = new IconStorage(textures, gameData);
SetNames(gameData, tmp);
foreach (var race in Clans)
@ -179,10 +180,10 @@ public partial class CustomizationOptions
}
public TemporaryData(IDataManager gameData, CustomizationOptions options)
public TemporaryData(IDataManager gameData, CustomizationOptions options, IPluginLog log)
{
_options = options;
_cmpFile = new CmpFile(gameData);
_cmpFile = new CmpFile(gameData, log);
_customizeSheet = gameData.GetExcelSheet<CharaMakeCustomize>()!;
_bnpcCustomize = gameData.GetExcelSheet<BNpcCustomize>()!;
_enpcBase = gameData.GetExcelSheet<ENpcBase>()!;

View file

@ -1,4 +1,5 @@
using System.Collections.Generic;
using Dalamud.Interface.Internal;
using Penumbra.GameData.Enums;
namespace Glamourer.Customization;
@ -11,6 +12,6 @@ public interface ICustomizationManager
public CustomizationSet GetList(SubRace race, Gender gender);
public ImGuiScene.TextureWrap GetIcon(uint iconId);
public IDalamudTextureWrap GetIcon(uint iconId);
public string GetName(CustomName name);
}

View file

@ -11,6 +11,7 @@ public static class GameData
{
private static Dictionary<byte, Job>? _jobs;
private static Dictionary<ushort, JobGroup>? _jobGroups;
private static JobGroup[]? _allJobGroups;
public static IReadOnlyDictionary<byte, Job> Jobs(IDataManager dataManager)
{
@ -22,14 +23,22 @@ public static class GameData
return _jobs;
}
public static IReadOnlyList<JobGroup> AllJobGroups(IDataManager dataManager)
{
if (_allJobGroups != null)
return _allJobGroups;
var sheet = dataManager.GetExcelSheet<ClassJobCategory>()!;
var jobs = dataManager.GetExcelSheet<ClassJob>(ClientLanguage.English)!;
_allJobGroups = sheet.Select(j => new JobGroup(j, jobs)).ToArray();
return _allJobGroups;
}
public static IReadOnlyDictionary<ushort, JobGroup> JobGroups(IDataManager dataManager)
{
if (_jobGroups != null)
return _jobGroups;
var sheet = dataManager.GetExcelSheet<ClassJobCategory>()!;
var jobs = dataManager.GetExcelSheet<ClassJob>(ClientLanguage.English)!;
static bool ValidIndex(uint idx)
{
if (idx is > 0 and < 36)
@ -72,8 +81,8 @@ public static class GameData
};
}
_jobGroups = sheet.Where(j => ValidIndex(j.RowId))
.ToDictionary(j => (ushort)j.RowId, j => new JobGroup(j, jobs));
_jobGroups = AllJobGroups(dataManager).Where(j => ValidIndex(j.Id))
.ToDictionary(j => (ushort) j.Id, j => j);
return _jobGroups;
}
}

View file

@ -14,6 +14,9 @@ public readonly struct Job
public uint Id
=> Base.RowId;
public JobFlag Flag
=> (JobFlag)(1u << (int)Base.RowId);
public Job(ClassJob job)
{
Base = job;

View file

@ -1,16 +1,21 @@
using System.Diagnostics;
using System;
using System.Diagnostics;
using Lumina.Excel;
using Lumina.Excel.GeneratedSheets;
namespace Glamourer.Structs;
[Flags]
public enum JobFlag : ulong
{ }
// The game specifies different job groups that can contain specific jobs or not.
public readonly struct JobGroup
{
public readonly string Name;
public readonly int Count;
public readonly uint Id;
private readonly ulong _flags;
private readonly JobFlag _flags;
// Create a job group from a given category and the ClassJob sheet.
// It looks up the different jobs contained in the category and sets the flags appropriately.
@ -35,18 +40,22 @@ public readonly struct JobGroup
continue;
++Count;
_flags |= 1ul << (int)job.RowId;
_flags |= (JobFlag)(1ul << (int)job.RowId);
}
}
// Check if a job is contained inside this group.
public bool Fits(Job job)
=> Fits(job.Id);
=> _flags.HasFlag(job.Flag);
// Check if any of the jobs in the given flags fit this group.
public bool Fits(JobFlag flag)
=> (_flags & flag) != 0;
// Check if a job is contained inside this group.
public bool Fits(uint jobId)
{
var flag = 1ul << (int)jobId;
return (flag & _flags) != 0;
var flag = (JobFlag)(1ul << (int)jobId);
return _flags.HasFlag(flag);
}
}

View file

@ -55,18 +55,18 @@ public unsafe struct DesignData
=> slot.ToIndex() switch
{
// @formatter:off
0 => EquipItem.FromIds(_itemIds[ 0], _iconIds[ 0], (SetId)(_equipmentBytes[ 0] | (_equipmentBytes[ 1] << 8)), (WeaponType)0, _equipmentBytes[ 2], FullEquipType.Head, _nameHead ),
1 => EquipItem.FromIds(_itemIds[ 1], _iconIds[ 1], (SetId)(_equipmentBytes[ 4] | (_equipmentBytes[ 5] << 8)), (WeaponType)0, _equipmentBytes[ 6], FullEquipType.Body, _nameBody ),
2 => EquipItem.FromIds(_itemIds[ 2], _iconIds[ 2], (SetId)(_equipmentBytes[ 8] | (_equipmentBytes[ 9] << 8)), (WeaponType)0, _equipmentBytes[10], FullEquipType.Hands, _nameHands ),
3 => EquipItem.FromIds(_itemIds[ 3], _iconIds[ 3], (SetId)(_equipmentBytes[12] | (_equipmentBytes[13] << 8)), (WeaponType)0, _equipmentBytes[14], FullEquipType.Legs, _nameLegs ),
4 => EquipItem.FromIds(_itemIds[ 4], _iconIds[ 4], (SetId)(_equipmentBytes[16] | (_equipmentBytes[17] << 8)), (WeaponType)0, _equipmentBytes[18], FullEquipType.Feet, _nameFeet ),
5 => EquipItem.FromIds(_itemIds[ 5], _iconIds[ 5], (SetId)(_equipmentBytes[20] | (_equipmentBytes[21] << 8)), (WeaponType)0, _equipmentBytes[22], FullEquipType.Ears, _nameEars ),
6 => EquipItem.FromIds(_itemIds[ 6], _iconIds[ 6], (SetId)(_equipmentBytes[24] | (_equipmentBytes[25] << 8)), (WeaponType)0, _equipmentBytes[26], FullEquipType.Neck, _nameNeck ),
7 => EquipItem.FromIds(_itemIds[ 7], _iconIds[ 7], (SetId)(_equipmentBytes[28] | (_equipmentBytes[29] << 8)), (WeaponType)0, _equipmentBytes[30], FullEquipType.Wrists, _nameWrists ),
8 => EquipItem.FromIds(_itemIds[ 8], _iconIds[ 8], (SetId)(_equipmentBytes[32] | (_equipmentBytes[33] << 8)), (WeaponType)0, _equipmentBytes[34], FullEquipType.Finger, _nameRFinger ),
9 => EquipItem.FromIds(_itemIds[ 9], _iconIds[ 9], (SetId)(_equipmentBytes[36] | (_equipmentBytes[37] << 8)), (WeaponType)0, _equipmentBytes[38], FullEquipType.Finger, _nameLFinger ),
10 => EquipItem.FromIds(_itemIds[10], _iconIds[10], (SetId)(_equipmentBytes[40] | (_equipmentBytes[41] << 8)), _secondaryMainhand, _equipmentBytes[42], _typeMainhand, _nameMainhand),
11 => EquipItem.FromIds(_itemIds[11], _iconIds[11], (SetId)(_equipmentBytes[44] | (_equipmentBytes[45] << 8)), _secondaryOffhand, _equipmentBytes[46], _typeOffhand, _nameOffhand ),
0 => EquipItem.FromIds(_itemIds[ 0], _iconIds[ 0], (SetId)(_equipmentBytes[ 0] | (_equipmentBytes[ 1] << 8)), (WeaponType)0, _equipmentBytes[ 2], FullEquipType.Head, name: _nameHead ),
1 => EquipItem.FromIds(_itemIds[ 1], _iconIds[ 1], (SetId)(_equipmentBytes[ 4] | (_equipmentBytes[ 5] << 8)), (WeaponType)0, _equipmentBytes[ 6], FullEquipType.Body, name: _nameBody ),
2 => EquipItem.FromIds(_itemIds[ 2], _iconIds[ 2], (SetId)(_equipmentBytes[ 8] | (_equipmentBytes[ 9] << 8)), (WeaponType)0, _equipmentBytes[10], FullEquipType.Hands, name: _nameHands ),
3 => EquipItem.FromIds(_itemIds[ 3], _iconIds[ 3], (SetId)(_equipmentBytes[12] | (_equipmentBytes[13] << 8)), (WeaponType)0, _equipmentBytes[14], FullEquipType.Legs, name: _nameLegs ),
4 => EquipItem.FromIds(_itemIds[ 4], _iconIds[ 4], (SetId)(_equipmentBytes[16] | (_equipmentBytes[17] << 8)), (WeaponType)0, _equipmentBytes[18], FullEquipType.Feet, name: _nameFeet ),
5 => EquipItem.FromIds(_itemIds[ 5], _iconIds[ 5], (SetId)(_equipmentBytes[20] | (_equipmentBytes[21] << 8)), (WeaponType)0, _equipmentBytes[22], FullEquipType.Ears, name: _nameEars ),
6 => EquipItem.FromIds(_itemIds[ 6], _iconIds[ 6], (SetId)(_equipmentBytes[24] | (_equipmentBytes[25] << 8)), (WeaponType)0, _equipmentBytes[26], FullEquipType.Neck, name: _nameNeck ),
7 => EquipItem.FromIds(_itemIds[ 7], _iconIds[ 7], (SetId)(_equipmentBytes[28] | (_equipmentBytes[29] << 8)), (WeaponType)0, _equipmentBytes[30], FullEquipType.Wrists, name: _nameWrists ),
8 => EquipItem.FromIds(_itemIds[ 8], _iconIds[ 8], (SetId)(_equipmentBytes[32] | (_equipmentBytes[33] << 8)), (WeaponType)0, _equipmentBytes[34], FullEquipType.Finger, name: _nameRFinger ),
9 => EquipItem.FromIds(_itemIds[ 9], _iconIds[ 9], (SetId)(_equipmentBytes[36] | (_equipmentBytes[37] << 8)), (WeaponType)0, _equipmentBytes[38], FullEquipType.Finger, name: _nameLFinger ),
10 => EquipItem.FromIds(_itemIds[10], _iconIds[10], (SetId)(_equipmentBytes[40] | (_equipmentBytes[41] << 8)), _secondaryMainhand, _equipmentBytes[42], _typeMainhand, name: _nameMainhand),
11 => EquipItem.FromIds(_itemIds[11], _iconIds[11], (SetId)(_equipmentBytes[44] | (_equipmentBytes[45] << 8)), _secondaryOffhand, _equipmentBytes[46], _typeOffhand, name: _nameOffhand ),
_ => new EquipItem(),
// @formatter:on
};

View file

@ -1,14 +1,14 @@
using System;
using System.Collections.Concurrent;
using Dalamud.Game;
using Dalamud.Plugin.Services;
using OtterGui.Classes;
using FFXIVClientStructs.FFXIV.Client.Game;
namespace Glamourer.Events;
public class GPoseService : EventWrapper<Action<bool>, GPoseService.Priority>
{
private readonly Framework _framework;
private readonly IFramework _framework;
private readonly IClientState _state;
private readonly ConcurrentQueue<Action> _onLeave = new();
private readonly ConcurrentQueue<Action> _onEnter = new();
@ -19,13 +19,14 @@ public class GPoseService : EventWrapper<Action<bool>, GPoseService.Priority>
GlamourerIpc = int.MinValue,
}
public bool InGPose { get; private set; } = false;
public bool InGPose { get; private set; }
public GPoseService(Framework framework)
public GPoseService(IFramework framework, IClientState state)
: base(nameof(GPoseService))
{
_framework = framework;
InGPose = GameMain.IsInGPose();
_state = state;
InGPose = state.IsGPosing;
_framework.Update += OnFramework;
}
@ -51,9 +52,9 @@ public class GPoseService : EventWrapper<Action<bool>, GPoseService.Priority>
_onEnter.Enqueue(onEnter);
}
private void OnFramework(Framework _)
private void OnFramework(IFramework _)
{
var inGPose = GameMain.IsInGPose();
var inGPose = _state.IsGPosing;
if (InGPose == inGPose)
return;

View file

@ -89,7 +89,7 @@
<ProjectReference Include="..\Penumbra.String\Penumbra.string.csproj" />
<ProjectReference Include="..\Penumbra.GameData\Penumbra.GameData.csproj" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Dalamud.ContextMenu" Version="1.2.3" />
<PackageReference Include="Dalamud.ContextMenu" Version="1.3.1" />
</ItemGroup>
<ItemGroup>

View file

@ -5,10 +5,10 @@
"Description": "Adds functionality to change and store appearance of players, customization and equip. Requires Penumbra to be installed and activated to work. Can also add preview options to the Changed Items tab for Penumbra.",
"Tags": [ "Appearance", "Glamour", "Race", "Outfit", "Armor", "Clothes", "Skins", "Customization", "Design", "Character" ],
"InternalName": "Glamourer",
"AssemblyVersion": "1.0.0.2",
"AssemblyVersion": "1.0.1.0",
"RepoUrl": "https://github.com/Ottermandias/Glamourer",
"ApplicableVersion": "any",
"DalamudApiLevel": 8,
"DalamudApiLevel": 9,
"ImageUrls": null,
"IconUrl": "https://raw.githubusercontent.com/Ottermandias/Glamourer/master/images/icon.png"
}

View file

@ -1,6 +1,6 @@
using System;
using System.Numerics;
using System.Numerics;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using Glamourer.Customization;
using ImGuiNET;
using OtterGui.Raii;

View file

@ -1,7 +1,8 @@
using System;
using System.Numerics;
using System.Reflection;
using Dalamud.Interface;
using Dalamud.Interface.Internal;
using Dalamud.Interface.Utility;
using Dalamud.Plugin;
using Glamourer.Customization;
using Glamourer.Services;
@ -19,9 +20,9 @@ public partial class CustomizationDrawer : IDisposable
private readonly Configuration _config;
private readonly Vector4 _redTint = new(0.6f, 0.3f, 0.3f, 1f);
private readonly ImGuiScene.TextureWrap? _legacyTattoo;
private readonly IDalamudTextureWrap? _legacyTattoo;
private Exception? _terminate = null;
private Exception? _terminate;
private Customize _customize;
private CustomizationSet _set = null!;
@ -34,8 +35,8 @@ public partial class CustomizationDrawer : IDisposable
public CustomizeFlag ChangeApply { get; private set; }
private CustomizeFlag _initialApply;
private bool _locked = false;
private bool _lockedRedraw = false;
private bool _locked;
private bool _lockedRedraw;
private Vector2 _spacing;
private Vector2 _iconSize;
private Vector2 _framedIconSize;
@ -207,7 +208,7 @@ public partial class CustomizationDrawer : IDisposable
_raceSelectorWidth = _inputIntSize + _comboSelectorSize - _framedIconSize.X;
}
private static ImGuiScene.TextureWrap? GetLegacyTattooIcon(DalamudPluginInterface pi)
private static IDalamudTextureWrap? GetLegacyTattooIcon(DalamudPluginInterface pi)
{
using var resource = Assembly.GetExecutingAssembly().GetManifestResourceStream("Glamourer.LegacyTattoo.raw");
if (resource == null)

View file

@ -3,8 +3,8 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Numerics;
using Dalamud.Interface;
using Dalamud.Interface.Components;
using Dalamud.Interface.Utility;
using Dalamud.Plugin.Services;
using Glamourer.Designs;
using Glamourer.Events;
@ -47,18 +47,18 @@ public class EquipmentDrawer
_gPose = gPose;
_stainData = items.Stains;
_stainCombo = new FilterComboColors(DefaultWidth - 20,
_stainData.Data.Prepend(new KeyValuePair<byte, (string Name, uint Dye, bool Gloss)>(0, ("None", 0, false))));
_itemCombo = EquipSlotExtensions.EqdpSlots.Select(e => new ItemCombo(gameData, items, e)).ToArray();
_stainData.Data.Prepend(new KeyValuePair<byte, (string Name, uint Dye, bool Gloss)>(0, ("None", 0, false))), Glamourer.Log);
_itemCombo = EquipSlotExtensions.EqdpSlots.Select(e => new ItemCombo(gameData, items, e, Glamourer.Log)).ToArray();
_weaponCombo = new Dictionary<FullEquipType, WeaponCombo>(FullEquipTypeExtensions.WeaponTypes.Count * 2);
foreach (var type in Enum.GetValues<FullEquipType>())
{
if (type.ToSlot() is EquipSlot.MainHand)
_weaponCombo.TryAdd(type, new WeaponCombo(items, type));
_weaponCombo.TryAdd(type, new WeaponCombo(items, type, Glamourer.Log));
else if (type.ToSlot() is EquipSlot.OffHand)
_weaponCombo.TryAdd(type, new WeaponCombo(items, type));
_weaponCombo.TryAdd(type, new WeaponCombo(items, type, Glamourer.Log));
}
_weaponCombo.Add(FullEquipType.Unknown, new WeaponCombo(items, FullEquipType.Unknown));
_weaponCombo.Add(FullEquipType.Unknown, new WeaponCombo(items, FullEquipType.Unknown, Glamourer.Log));
}
private Vector2 _iconSize;

View file

@ -6,6 +6,7 @@ using ImGuiNET;
using Lumina.Excel.GeneratedSheets;
using OtterGui;
using OtterGui.Classes;
using OtterGui.Log;
using OtterGui.Raii;
using OtterGui.Widgets;
using Penumbra.GameData.Enums;
@ -19,8 +20,8 @@ public sealed class ItemCombo : FilterComboCache<EquipItem>
private ItemId _currentItem;
private float _innerWidth;
public ItemCombo(IDataManager gameData, ItemManager items, EquipSlot slot)
: base(() => GetItems(items, slot))
public ItemCombo(IDataManager gameData, ItemManager items, EquipSlot slot, Logger log)
: base(() => GetItems(items, slot), log)
{
Label = GetLabel(gameData, slot);
_currentItem = ItemManager.NothingId(slot);

View file

@ -5,6 +5,7 @@ using Glamourer.Services;
using ImGuiNET;
using OtterGui;
using OtterGui.Classes;
using OtterGui.Log;
using OtterGui.Raii;
using OtterGui.Widgets;
using Penumbra.GameData.Enums;
@ -18,8 +19,8 @@ public sealed class WeaponCombo : FilterComboCache<EquipItem>
private ItemId _currentItemId;
private float _innerWidth;
public WeaponCombo(ItemManager items, FullEquipType type)
: base(() => GetWeapons(items, type))
public WeaponCombo(ItemManager items, FullEquipType type, Logger log)
: base(() => GetWeapons(items, type), log)
{
Label = GetLabel(type);
SearchByParts = true;

View file

@ -1,5 +1,5 @@
using System.Numerics;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Windowing;
using ImGuiNET;
using OtterGui;
@ -9,7 +9,7 @@ namespace Glamourer.Gui;
public class GenericPopupWindow : Window
{
private Configuration _config;
private readonly Configuration _config;
public bool OpenFestivalPopup { get; internal set; } = false;
public GenericPopupWindow(Configuration config)

View file

@ -65,6 +65,9 @@ public class PenumbraChangedItemTooltip : IDisposable
public void CreateTooltip(EquipItem item, string prefix, bool openTooltip)
{
if (!Player())
return;
var slot = item.Type.ToSlot();
var last = _lastItems[slot.ToIndex()];
switch (slot)

View file

@ -1,9 +1,9 @@
using System;
using System.Linq;
using System.Numerics;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Interface;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game;
using Glamourer.Automation;
using Glamourer.Customization;
@ -36,7 +36,7 @@ public class ActorPanel
private readonly ObjectManager _objects;
private readonly DesignManager _designManager;
private readonly DatFileService _datFileService;
private readonly Condition _conditions;
private readonly ICondition _conditions;
private ActorIdentifier _identifier;
private string _actorName = string.Empty;
@ -48,7 +48,7 @@ public class ActorPanel
public ActorPanel(ActorSelector selector, StateManager stateManager, CustomizationDrawer customizationDrawer,
EquipmentDrawer equipmentDrawer, IdentifierService identification, AutoDesignApplier autoDesignApplier,
Configuration config, DesignConverter converter, ObjectManager objects, DesignManager designManager, DatFileService datFileService,
Condition conditions)
ICondition conditions)
{
_selector = selector;
_stateManager = stateManager;
@ -280,7 +280,8 @@ public class ActorPanel
private HeaderDrawer.Button SetFromClipboardButton()
=> new()
{
Description = "Try to apply a design from your clipboard.\nHold Control to only apply gear.\nHold Shift to only apply customizations.",
Description =
"Try to apply a design from your clipboard.\nHold Control to only apply gear.\nHold Shift to only apply customizations.",
Icon = FontAwesomeIcon.Clipboard,
OnClick = SetFromClipboard,
Visible = _state != null,
@ -290,7 +291,8 @@ public class ActorPanel
private HeaderDrawer.Button ExportToClipboardButton()
=> new()
{
Description = "Copy the current design to your clipboard.\nHold Control to disable applying of customizations for the copied design.\nHold Shift to disable applying of gear for the copied design.",
Description =
"Copy the current design to your clipboard.\nHold Control to disable applying of customizations for the copied design.\nHold Shift to disable applying of gear for the copied design.",
Icon = FontAwesomeIcon.Copy,
OnClick = ExportToClipboard,
Visible = _state?.ModelData.ModelId == 0,
@ -299,7 +301,8 @@ public class ActorPanel
private HeaderDrawer.Button SaveAsDesignButton()
=> new()
{
Description = "Save the current state as a design.\nHold Control to disable applying of customizations for the saved design.\nHold Shift to disable applying of gear for the saved design.",
Description =
"Save the current state as a design.\nHold Control to disable applying of customizations for the saved design.\nHold Shift to disable applying of gear for the saved design.",
Icon = FontAwesomeIcon.Save,
OnClick = SaveDesignOpen,
Visible = _state?.ModelData.ModelId == 0,
@ -345,7 +348,8 @@ public class ActorPanel
{
var (applyGear, applyCustomize) = UiHelpers.ConvertKeysToBool();
var text = ImGui.GetClipboardText();
var design = _converter.FromBase64(text, applyCustomize, applyGear, out _) ?? throw new Exception("The clipboard did not contain valid data.");
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);
}
catch (Exception ex)
@ -394,7 +398,8 @@ public class ActorPanel
private void DrawApplyToSelf()
{
var (id, data) = _objects.PlayerData;
if (!ImGuiUtil.DrawDisabledButton("Apply to Yourself", Vector2.Zero, "Apply the current state to your own character.\nHold Control to only apply gear.\nHold Shift to only apply customizations.",
if (!ImGuiUtil.DrawDisabledButton("Apply to Yourself", Vector2.Zero,
"Apply the current state to your own character.\nHold Control to only apply gear.\nHold Shift to only apply customizations.",
!data.Valid || id == _identifier || _state!.ModelData.ModelId != 0))
return;

View file

@ -1,5 +1,5 @@
using System;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using ImGuiNET;
using OtterGui.Widgets;

View file

@ -1,5 +1,5 @@
using System;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using ImGuiNET;
using OtterGui.Widgets;

View file

@ -1,6 +1,6 @@
using System;
using System.Linq;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using Glamourer.Automation;
using Glamourer.Customization;
using Glamourer.Designs;
@ -9,6 +9,7 @@ using Glamourer.Services;
using ImGuiNET;
using OtterGui;
using OtterGui.Classes;
using OtterGui.Log;
using OtterGui.Widgets;
namespace Glamourer.Gui.Tabs.AutomationTab;
@ -23,14 +24,14 @@ public sealed class DesignCombo : FilterComboCache<(Design, string)>
private float _innerWidth;
public DesignCombo(AutoDesignManager manager, DesignManager designs, DesignFileSystem fileSystem, TabSelected tabSelected,
ItemManager items, CustomizationService customize)
: this(manager, designs, fileSystem, tabSelected, CreateRevertDesign(customize, items))
ItemManager items, CustomizationService customize, Logger log)
: this(manager, designs, fileSystem, tabSelected, CreateRevertDesign(customize, items), log)
{ }
private DesignCombo(AutoDesignManager manager, DesignManager designs, DesignFileSystem fileSystem, TabSelected tabSelected,
Design revertDesign)
Design revertDesign, Logger log)
: base(() => designs.Designs.Select(d => (d, fileSystem.FindLeaf(d, out var l) ? l.FullName() : string.Empty)).OrderBy(d => d.Item2)
.Prepend((revertDesign, string.Empty)).ToList())
.Prepend((revertDesign, string.Empty)).ToList(), log)
{
_manager = manager;
_tabSelected = tabSelected;

View file

@ -6,6 +6,7 @@ using Dalamud.Utility;
using Glamourer.Services;
using ImGuiNET;
using OtterGui.Custom;
using OtterGui.Log;
using OtterGui.Widgets;
using Penumbra.GameData.Data;
@ -15,8 +16,8 @@ public sealed class HumanNpcCombo : FilterComboCache<(string Name, ObjectKind Ki
{
private readonly string _label;
public HumanNpcCombo(string label, IdentifierService service, HumanModelList humans)
: base(() => CreateList(service, humans))
public HumanNpcCombo(string label, IdentifierService service, HumanModelList humans, Logger log)
: base(() => CreateList(service, humans), log)
=> _label = label;
protected override string ToString((string Name, ObjectKind Kind, uint[] Ids) obj)

View file

@ -24,8 +24,8 @@ public class IdentifierDrawer
public IdentifierDrawer(ActorService actors, IdentifierService identifier, HumanModelList humans)
{
_actors = actors;
_worldCombo = new WorldCombo(actors.AwaitedService.Data.Worlds);
_humanNpcCombo = new HumanNpcCombo("##npcs", identifier, humans);
_worldCombo = new WorldCombo(actors.AwaitedService.Data.Worlds, Glamourer.Log);
_humanNpcCombo = new HumanNpcCombo("##npcs", identifier, humans, Glamourer.Log);
}
public void DrawName(float width)

View file

@ -3,6 +3,7 @@ using System.Linq;
using System.Numerics;
using System.Text;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using Glamourer.Automation;
using Glamourer.Customization;
using Glamourer.Interop;
@ -11,6 +12,7 @@ using Glamourer.Structs;
using Glamourer.Unlocks;
using ImGuiNET;
using OtterGui;
using OtterGui.Log;
using OtterGui.Raii;
using OtterGui.Widgets;
using Penumbra.GameData.Enums;
@ -48,7 +50,7 @@ public class SetPanel
_identifierDrawer = identifierDrawer;
_config = config;
_designCombo = designCombo;
_jobGroupCombo = new JobGroupCombo(manager, jobs);
_jobGroupCombo = new JobGroupCombo(manager, jobs, Glamourer.Log);
}
private AutoDesignSet Selection
@ -427,8 +429,8 @@ public class SetPanel
private readonly AutoDesignManager _manager;
private readonly JobService _jobs;
public JobGroupCombo(AutoDesignManager manager, JobService jobs)
: base(() => jobs.JobGroups.Values.ToList())
public JobGroupCombo(AutoDesignManager manager, JobService jobs, Logger log)
: base(() => jobs.JobGroups.Values.ToList(), log)
{
_manager = manager;
_jobs = jobs;

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using Glamourer.Automation;
using Glamourer.Events;
using Glamourer.Interop;
@ -12,6 +13,7 @@ using OtterGui;
using OtterGui.Classes;
using OtterGui.Raii;
using Penumbra.String;
using ImGuiClip = OtterGui.ImGuiClip;
namespace Glamourer.Gui.Tabs.AutomationTab;

View file

@ -7,6 +7,7 @@ using System.Numerics;
using System.Text;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using Dalamud.Plugin;
using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
@ -31,6 +32,7 @@ using Penumbra.Api.Enums;
using Penumbra.GameData.Data;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
using ImGuiClip = OtterGui.ImGuiClip;
namespace Glamourer.Gui.Tabs;
@ -579,14 +581,29 @@ public unsafe class DebugTab : ITab
if (table)
foreach (var (id, job) in _jobs.Jobs)
{
ImGuiUtil.DrawTableColumn(id.ToString("D2"));
ImGuiUtil.DrawTableColumn(id.ToString("D3"));
ImGuiUtil.DrawTableColumn(job.Name);
ImGuiUtil.DrawTableColumn(job.Abbreviation);
}
}
}
using (var t = ImRaii.TreeNode("Job Groups"))
using (var t = ImRaii.TreeNode("All Job Groups"))
{
if (t)
{
using var table = ImRaii.Table("##groups", 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg);
if (table)
foreach (var (group, idx) in _jobs.AllJobGroups.WithIndex())
{
ImGuiUtil.DrawTableColumn(idx.ToString("D3"));
ImGuiUtil.DrawTableColumn(group.Name);
ImGuiUtil.DrawTableColumn(group.Count.ToString());
}
}
}
using (var t = ImRaii.TreeNode("Valid Job Groups"))
{
if (t)
{
@ -594,7 +611,7 @@ public unsafe class DebugTab : ITab
if (table)
foreach (var (id, group) in _jobs.JobGroups)
{
ImGuiUtil.DrawTableColumn(id.ToString("D2"));
ImGuiUtil.DrawTableColumn(id.ToString("D3"));
ImGuiUtil.DrawTableColumn(group.Name);
ImGuiUtil.DrawTableColumn(group.Count.ToString());
}

View file

@ -1,9 +1,9 @@
using System;
using System.Linq;
using System.Numerics;
using Dalamud.Game.ClientState.Keys;
using Dalamud.Interface;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Plugin.Services;
using Glamourer.Customization;
using Glamourer.Designs;
using Glamourer.Events;
@ -12,6 +12,7 @@ using OtterGui;
using OtterGui.Classes;
using OtterGui.Filesystem;
using OtterGui.FileSystem.Selector;
using OtterGui.Log;
using OtterGui.Raii;
namespace Glamourer.Gui.Tabs.DesignTab;
@ -25,7 +26,7 @@ public sealed class DesignFileSystemSelector : FileSystemSelector<Design, Design
private readonly TabSelected _selectionEvent;
private string? _clipboardText;
private Design? _cloneDesign = null;
private Design? _cloneDesign;
private string _newName = string.Empty;
public bool IncognitoMode
@ -46,9 +47,9 @@ public sealed class DesignFileSystemSelector : FileSystemSelector<Design, Design
public ColorId Color;
}
public DesignFileSystemSelector(DesignManager designManager, DesignFileSystem fileSystem, KeyState keyState, DesignChanged @event,
Configuration config, DesignConverter converter, TabSelected selectionEvent)
: base(fileSystem, keyState, allowMultipleSelection: true)
public DesignFileSystemSelector(DesignManager designManager, DesignFileSystem fileSystem, IKeyState keyState, DesignChanged @event,
Configuration config, DesignConverter converter, TabSelected selectionEvent, Logger log)
: base(fileSystem, keyState, log, allowMultipleSelection: true)
{
_designManager = designManager;
_event = @event;

View file

@ -1,5 +1,5 @@
using System;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using ImGuiNET;
using OtterGui.Widgets;

View file

@ -1,6 +1,7 @@
using System.Numerics;
using Dalamud.Interface;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Interface.Utility;
using Dalamud.Utility;
using Glamourer.Designs;
using Glamourer.Interop.Penumbra;
@ -22,7 +23,7 @@ public class ModAssociationsTab
_penumbra = penumbra;
_selector = selector;
_manager = manager;
_modCombo = new ModCombo(penumbra);
_modCombo = new ModCombo(penumbra, Glamourer.Log);
}
public void Draw()

View file

@ -1,10 +1,10 @@
using System;
using System.Numerics;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using Glamourer.Interop.Penumbra;
using ImGuiNET;
using OtterGui;
using OtterGui.Classes;
using OtterGui.Log;
using OtterGui.Raii;
using OtterGui.Widgets;
@ -12,8 +12,8 @@ namespace Glamourer.Gui.Tabs.DesignTab;
public sealed class ModCombo : FilterComboCache<(Mod Mod, ModSettings Settings)>
{
public ModCombo(PenumbraService penumbra)
: base(penumbra.GetMods)
public ModCombo(PenumbraService penumbra, Logger log)
: base(penumbra.GetMods, log)
{
SearchByParts = false;
}

View file

@ -2,6 +2,7 @@
using System.Linq;
using System.Numerics;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;

View file

@ -3,6 +3,7 @@ using System.Numerics;
using System.Runtime.CompilerServices;
using Dalamud.Interface;
using Dalamud.Interface.Components;
using Dalamud.Interface.Utility;
using Glamourer.Gui.Tabs.DesignTab;
using Glamourer.Interop;
using Glamourer.Interop.Penumbra;

View file

@ -1,15 +1,16 @@
using System;
using System.Linq;
using System.Numerics;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using Glamourer.Customization;
using Glamourer.Interop;
using Glamourer.Services;
using Glamourer.Unlocks;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
using ImGuiClip = OtterGui.ImGuiClip;
namespace Glamourer.Gui.Tabs.UnlocksTab;
@ -22,6 +23,7 @@ public class UnlockOverview
private readonly PenumbraChangedItemTooltip _tooltip;
private readonly TextureService _textures;
private readonly CodeService _codes;
private readonly JobService _jobs;
private static readonly Vector4 UnavailableTint = new(0.3f, 0.3f, 0.3f, 1.0f);
@ -67,7 +69,8 @@ public class UnlockOverview
}
public UnlockOverview(ItemManager items, CustomizationService customizations, ItemUnlockManager itemUnlocks,
CustomizeUnlockManager customizeUnlocks, PenumbraChangedItemTooltip tooltip, TextureService textures, CodeService codes)
CustomizeUnlockManager customizeUnlocks, PenumbraChangedItemTooltip tooltip, TextureService textures, CodeService codes,
JobService jobs)
{
_items = items;
_customizations = customizations;
@ -76,6 +79,7 @@ public class UnlockOverview
_tooltip = tooltip;
_textures = textures;
_codes = codes;
_jobs = jobs;
}
public void Draw()
@ -116,7 +120,8 @@ public class UnlockOverview
var unlocked = _customizeUnlocks.IsUnlocked(customize, out var time);
var icon = _customizations.AwaitedService.GetIcon(customize.IconId);
ImGui.Image(icon.ImGuiHandle, iconSize, Vector2.Zero, Vector2.One, unlocked || _codes.EnabledShirts ? Vector4.One : UnavailableTint);
ImGui.Image(icon.ImGuiHandle, iconSize, Vector2.Zero, Vector2.One,
unlocked || _codes.EnabledShirts ? Vector4.One : UnavailableTint);
if (ImGui.IsItemHovered())
{
using var tt = ImRaii.Tooltip();
@ -184,6 +189,28 @@ public class UnlockOverview
ImGui.TextUnformatted(slot is EquipSlot.MainHand ? $"{item.Weapon()}" : $"{item.Armor()}");
ImGui.TextUnformatted(
unlocked ? time == DateTimeOffset.MinValue ? "Always Unlocked" : $"Unlocked on {time:g}" : "Not Unlocked.");
if (item.Level.Value <= 1)
{
if (item.JobRestrictions.Id <= 1 || item.JobRestrictions.Id >= _jobs.AllJobGroups.Count)
ImGui.TextUnformatted("For Everyone");
else
ImGui.TextUnformatted($"For all {_jobs.AllJobGroups[item.JobRestrictions.Id].Name}");
}
else
{
if (item.JobRestrictions.Id <= 1 || item.JobRestrictions.Id >= _jobs.AllJobGroups.Count)
ImGui.TextUnformatted($"For Everyone of at least Level {item.Level}");
else
ImGui.TextUnformatted($"For all {_jobs.AllJobGroups[item.JobRestrictions.Id].Name} of at least Level {item.Level}");
}
if (item.Flags.HasFlag(ItemFlags.IsDyable))
ImGui.TextUnformatted("Dyable");
if (item.Flags.HasFlag(ItemFlags.IsTradable))
ImGui.TextUnformatted("Tradable");
if (item.Flags.HasFlag(ItemFlags.IsCrestWorthy))
ImGui.TextUnformatted("Can apply Crest");
_tooltip.CreateTooltip(item, string.Empty, false);
}
}

View file

@ -4,7 +4,9 @@ using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using Glamourer.Events;
using Glamourer.Interop;
using Glamourer.Services;
using Glamourer.Structs;
using Glamourer.Unlocks;
@ -22,14 +24,20 @@ public class UnlockTable : Table<EquipItem>, IDisposable
private readonly ObjectUnlocked _event;
public UnlockTable(ItemManager items, TextureService textures, ItemUnlockManager itemUnlocks,
PenumbraChangedItemTooltip tooltip, ObjectUnlocked @event)
PenumbraChangedItemTooltip tooltip, ObjectUnlocked @event, JobService jobs)
: base("ItemUnlockTable", new ItemList(items),
new NameColumn(textures, tooltip) { Label = "Item Name..." },
new SlotColumn() { Label = "Equip Slot" },
new TypeColumn() { Label = "Item Type..." },
new UnlockDateColumn(itemUnlocks) { Label = "Unlocked" },
new ItemIdColumn() { Label = "Item Id..." },
new ModelDataColumn(items) { Label = "Model Data..." })
new ModelDataColumn(items) { Label = "Model Data..." },
new JobColumn(jobs) { Label = "Jobs" },
new LevelColumn() { Label = "Level..." },
new DyableColumn() { Label = "Dye" },
new CrestColumn() { Label = "Crest" },
new TradableColumn() { Label = "Trade" }
)
{
_event = @event;
Sortable = true;
@ -267,6 +275,160 @@ public class UnlockTable : Table<EquipItem>, IDisposable
}
}
private sealed class LevelColumn : ColumnString<EquipItem>
{
public override float Width
=> 70 * ImGuiHelpers.GlobalScale;
public override string ToName(EquipItem item)
=> item.Level.ToString();
public override void DrawColumn(EquipItem item, int _)
=> ImGuiUtil.RightAlign(item.Level.Value.ToString());
public override int Compare(EquipItem lhs, EquipItem rhs)
=> lhs.Level.Value.CompareTo(rhs.Level.Value);
}
private sealed class JobColumn : ColumnFlags<JobFlag, EquipItem>
{
public override float Width
=> 200 * ImGuiHelpers.GlobalScale;
private readonly JobService _jobs;
private readonly JobFlag[] _values;
private readonly string[] _names;
private JobFlag _filterValue;
public override JobFlag FilterValue
=> _filterValue;
public JobColumn(JobService jobs)
{
_jobs = jobs;
_values = _jobs.Jobs.Values.Skip(1).Select(j => j.Flag).ToArray();
_names = _jobs.Jobs.Values.Skip(1).Select(j => j.Abbreviation).ToArray();
AllFlags = _values.Aggregate((l, r) => l | r);
_filterValue = AllFlags;
}
protected override void SetValue(JobFlag value, bool enable)
=> _filterValue = enable ? _filterValue | value : _filterValue & ~value;
protected override IReadOnlyList<JobFlag> Values
=> _values;
protected override string[] Names
=> _names;
public override int Compare(EquipItem lhs, EquipItem rhs)
=> lhs.JobRestrictions.Id.CompareTo(rhs.JobRestrictions.Id);
public override bool FilterFunc(EquipItem item)
{
if (item.JobRestrictions.Id < 2)
return true;
if (item.JobRestrictions.Id >= _jobs.AllJobGroups.Count)
return false;
var group = _jobs.AllJobGroups[item.JobRestrictions.Id];
return group.Fits(FilterValue);
}
public override void DrawColumn(EquipItem item, int idx)
{
var text = $"Unknown {item.JobRestrictions.Id}";
if (item.JobRestrictions.Id < _jobs.AllJobGroups.Count)
{
var group = _jobs.AllJobGroups[Math.Max((int)item.JobRestrictions.Id, 1)];
if (group.Name.Length > 0)
text = group.Name;
}
ImGui.TextUnformatted(text);
}
}
[Flags]
private enum YesNoFlag
{
Yes = 0x01,
No = 0x02,
};
private class YesNoColumn : ColumnFlags<YesNoFlag, EquipItem>
{
public string Tooltip = string.Empty;
private YesNoFlag _filterValue;
public override YesNoFlag FilterValue
=> _filterValue;
public YesNoColumn()
{
AllFlags = YesNoFlag.Yes | YesNoFlag.No;
_filterValue = AllFlags;
}
protected override void SetValue(YesNoFlag value, bool enable)
=> _filterValue = enable ? _filterValue | value : _filterValue & ~value;
protected virtual bool GetValue(EquipItem item)
=> false;
public override float Width
=> ImGui.GetFrameHeight() * 2;
public override bool FilterFunc(EquipItem item)
=> GetValue(item)
? FilterValue.HasFlag(YesNoFlag.Yes)
: FilterValue.HasFlag(YesNoFlag.No);
public override int Compare(EquipItem lhs, EquipItem rhs)
=> GetValue(lhs).CompareTo(GetValue(rhs));
public override void DrawColumn(EquipItem item, int idx)
{
using (var font = ImRaii.PushFont(UiBuilder.IconFont))
{
ImGuiUtil.Center(GetValue(item) ? FontAwesomeIcon.Check.ToIconString() : FontAwesomeIcon.Times.ToIconString());
}
ImGuiUtil.HoverTooltip(Tooltip);
}
}
private sealed class DyableColumn : YesNoColumn
{
public DyableColumn()
=> Tooltip = "Whether the item is dyable.";
protected override bool GetValue(EquipItem item)
=> item.Flags.HasFlag(ItemFlags.IsDyable);
}
private sealed class TradableColumn : YesNoColumn
{
public TradableColumn()
=> Tooltip = "Whether the item is tradable.";
protected override bool GetValue(EquipItem item)
=> item.Flags.HasFlag(ItemFlags.IsTradable);
}
private sealed class CrestColumn : YesNoColumn
{
public CrestColumn()
=> Tooltip = "Whether a crest can be applied to the item..";
protected override bool GetValue(EquipItem item)
=> item.Flags.HasFlag(ItemFlags.IsCrestWorthy);
}
private sealed class ItemList : IReadOnlyCollection<EquipItem>
{
private readonly ItemManager _items;

View file

@ -1,6 +1,6 @@
using System;
using System.Numerics;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using Glamourer.Customization;
using Glamourer.Services;
using Glamourer.Structs;

View file

@ -1,6 +1,7 @@
using System;
using System.Threading;
using Dalamud.Hooking;
using Dalamud.Plugin.Services;
using Dalamud.Utility.Signatures;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using Glamourer.Customization;
@ -19,6 +20,7 @@ namespace Glamourer.Interop;
public unsafe class ChangeCustomizeService : EventWrapper<Action<Model, Ref<Customize>>, ChangeCustomizeService.Priority>
{
private readonly PenumbraReloaded _penumbraReloaded;
private readonly IGameInteropProvider _interop;
/// <summary> Check whether we in a manual customize update, in which case we need to not toggle certain flags. </summary>
public static readonly ThreadLocal<bool> InUpdate = new(() => false);
@ -29,10 +31,11 @@ public unsafe class ChangeCustomizeService : EventWrapper<Action<Model, Ref<Cust
StateListener = 0,
}
public ChangeCustomizeService(PenumbraReloaded penumbraReloaded)
public ChangeCustomizeService(PenumbraReloaded penumbraReloaded, IGameInteropProvider interop)
: base("ChangeCustomize")
{
_penumbraReloaded = penumbraReloaded;
_interop = interop;
_changeCustomizeHook = Create();
_penumbraReloaded.Subscribe(Restore, PenumbraReloaded.Priority.ChangeCustomizeService);
}
@ -52,7 +55,7 @@ public unsafe class ChangeCustomizeService : EventWrapper<Action<Model, Ref<Cust
private Hook<ChangeCustomizeDelegate> Create()
{
var ret = Hook<ChangeCustomizeDelegate>.FromAddress((nint)Human.MemberFunctionPointers.UpdateDrawData, ChangeCustomizeDetour);
var ret = _interop.HookFromAddress<ChangeCustomizeDelegate>((nint)Human.MemberFunctionPointers.UpdateDrawData, ChangeCustomizeDetour);
ret.Enable();
return ret;
}

View file

@ -2,6 +2,7 @@
using Dalamud.ContextMenu;
using Dalamud.Game.Text;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using Glamourer.Events;
using Glamourer.Services;
@ -17,13 +18,15 @@ public class ContextMenuService : IDisposable
public const int ChatLogContextItemId = 0x948;
private readonly ItemManager _items;
private readonly DalamudContextMenu _contextMenu = new();
private readonly DalamudContextMenu _contextMenu;
private readonly StateManager _state;
private readonly ObjectManager _objects;
private readonly IGameGui _gameGui;
public ContextMenuService(ItemManager items, StateManager state, ObjectManager objects, IGameGui gameGui, Configuration config)
public ContextMenuService(ItemManager items, StateManager state, ObjectManager objects, IGameGui gameGui, Configuration config,
DalamudPluginInterface pi)
{
_contextMenu = new DalamudContextMenu(pi);
_items = items;
_state = state;
_objects = objects;

View file

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Dalamud.Hooking;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
using Glamourer.Events;
@ -14,12 +15,12 @@ public unsafe class InventoryService : IDisposable
private readonly MovedEquipment _event;
private readonly List<(EquipSlot, uint, StainId)> _itemList = new(12);
public InventoryService(MovedEquipment @event)
public InventoryService(MovedEquipment @event, IGameInteropProvider interop)
{
_event = @event;
_moveItemHook = Hook<MoveItemDelegate>.FromAddress((nint)InventoryManager.MemberFunctionPointers.MoveItemSlot, MoveItemDetour);
_moveItemHook = interop.HookFromAddress<MoveItemDelegate>((nint)InventoryManager.MemberFunctionPointers.MoveItemSlot, MoveItemDetour);
_equipGearsetHook =
Hook<EquipGearsetDelegate>.FromAddress((nint)RaptureGearsetModule.MemberFunctionPointers.EquipGearset, EquipGearSetDetour);
interop.HookFromAddress<EquipGearsetDelegate>((nint)RaptureGearsetModule.MemberFunctionPointers.EquipGearset, EquipGearSetDetour);
_moveItemHook.Enable();
_equipGearsetHook.Enable();
}
@ -76,7 +77,7 @@ public unsafe class InventoryService : IDisposable
Add(EquipSlot.Neck, plate.ItemIds[8], plate.StainIds[8], ref entry->Neck);
Add(EquipSlot.Wrists, plate.ItemIds[9], plate.StainIds[9], ref entry->Wrists);
Add(EquipSlot.RFinger, plate.ItemIds[10], plate.StainIds[10], ref entry->RingRight);
Add(EquipSlot.LFinger, plate.ItemIds[11], plate.StainIds[11], ref entry->RightLeft);
Add(EquipSlot.LFinger, plate.ItemIds[11], plate.StainIds[11], ref entry->RingLeft);
}
else
{
@ -101,7 +102,7 @@ public unsafe class InventoryService : IDisposable
Add(EquipSlot.Neck, ref entry->Neck);
Add(EquipSlot.Wrists, ref entry->Wrists);
Add(EquipSlot.RFinger, ref entry->RingRight);
Add(EquipSlot.LFinger, ref entry->RightLeft);
Add(EquipSlot.LFinger, ref entry->RingLeft);
}
_event.Invoke(_itemList.ToArray());

View file

@ -16,14 +16,16 @@ public class JobService : IDisposable
public readonly IReadOnlyDictionary<byte, Job> Jobs;
public readonly IReadOnlyDictionary<ushort, JobGroup> JobGroups;
public readonly IReadOnlyList<JobGroup> AllJobGroups;
public event Action<Actor, Job, Job>? JobChanged;
public JobService(IDataManager gameData)
public JobService(IDataManager gameData, IGameInteropProvider interop)
{
SignatureHelper.Initialise(this);
interop.InitializeFromAttributes(this);
_characterDataOffset = Marshal.OffsetOf<Character>(nameof(Character.CharacterData));
Jobs = GameData.Jobs(gameData);
AllJobGroups = GameData.AllJobGroups(gameData);
JobGroups = GameData.JobGroups(gameData);
_changeJobHook.Enable();
}

View file

@ -1,5 +1,6 @@
using System;
using Dalamud.Hooking;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game.Character;
using Glamourer.Events;
using Glamourer.Interop.Structs;
@ -19,14 +20,18 @@ public unsafe class MetaService : IDisposable
private readonly Hook<HideWeaponsDelegate> _hideWeaponsHook;
private readonly Hook<HideWeaponsDelegate> _toggleVisorHook;
public MetaService(WeaponVisibilityChanged weaponEvent, HeadGearVisibilityChanged headGearEvent, VisorStateChanged visorEvent)
public MetaService(WeaponVisibilityChanged weaponEvent, HeadGearVisibilityChanged headGearEvent, VisorStateChanged visorEvent,
IGameInteropProvider interop)
{
_weaponEvent = weaponEvent;
_headGearEvent = headGearEvent;
_visorEvent = visorEvent;
_hideHatGearHook = Hook<HideHatGearDelegate>.FromAddress((nint)DrawDataContainer.MemberFunctionPointers.HideHeadgear, HideHatDetour);
_hideWeaponsHook = Hook<HideWeaponsDelegate>.FromAddress((nint)DrawDataContainer.MemberFunctionPointers.HideWeapons, HideWeaponsDetour);
_toggleVisorHook = Hook<HideWeaponsDelegate>.FromAddress((nint)DrawDataContainer.MemberFunctionPointers.SetVisor, ToggleVisorDetour);
_hideHatGearHook =
interop.HookFromAddress<HideHatGearDelegate>((nint)DrawDataContainer.MemberFunctionPointers.HideHeadgear, HideHatDetour);
_hideWeaponsHook =
interop.HookFromAddress<HideWeaponsDelegate>((nint)DrawDataContainer.MemberFunctionPointers.HideWeapons, HideWeaponsDetour);
_toggleVisorHook =
interop.HookFromAddress<HideWeaponsDelegate>((nint)DrawDataContainer.MemberFunctionPointers.SetVisor, ToggleVisorDetour);
_hideHatGearHook.Enable();
_hideWeaponsHook.Enable();
_toggleVisorHook.Enable();

View file

@ -1,7 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Dalamud.Game;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Plugin.Services;
using Glamourer.Interop.Structs;
@ -12,7 +11,7 @@ namespace Glamourer.Interop;
public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
{
private readonly Framework _framework;
private readonly IFramework _framework;
private readonly IClientState _clientState;
private readonly IObjectTable _objects;
private readonly ActorService _actors;
@ -21,7 +20,7 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
public IObjectTable Objects
=> _objects;
public ObjectManager(Framework framework, IClientState clientState, IObjectTable objects, ActorService actors, ITargetManager targets)
public ObjectManager(IFramework framework, IClientState clientState, IObjectTable objects, ActorService actors, ITargetManager targets)
{
_framework = framework;
_clientState = clientState;

View file

@ -236,7 +236,7 @@ public unsafe class PenumbraService : IDisposable
}
catch (Exception e)
{
PluginLog.Debug($"Failure redrawing object:\n{e}");
Glamourer.Log.Debug($"Failure redrawing object:\n{e}");
}
}
@ -249,7 +249,7 @@ public unsafe class PenumbraService : IDisposable
}
catch (Exception e)
{
PluginLog.Debug($"Failure redrawing object:\n{e}");
Glamourer.Log.Debug($"Failure redrawing object:\n{e}");
}
}

View file

@ -2,6 +2,7 @@
using System.Runtime.CompilerServices;
using Dalamud.Game.ClientState.Objects.Enums;
using Dalamud.Hooking;
using Dalamud.Plugin.Services;
using Dalamud.Utility.Signatures;
using FFXIVClientStructs.FFXIV.Client.Game.Character;
using Glamourer.Interop.Structs;
@ -9,12 +10,16 @@ using Character = FFXIVClientStructs.FFXIV.Client.Game.Character.Character;
namespace Glamourer.Interop;
// TODO: Use client structs sigs.
public unsafe class ScalingService : IDisposable
{
public ScalingService()
public ScalingService(IGameInteropProvider interop)
{
SignatureHelper.Initialise(this);
interop.InitializeFromAttributes(this);
_setupMountHook =
interop.HookFromAddress<SetupMount>((nint)Character.MountContainer.MemberFunctionPointers.SetupMount, SetupMountDetour);
_setupOrnamentHook = interop.HookFromAddress<SetupOrnament>((nint)Ornament.MemberFunctionPointers.SetupOrnament, SetupOrnamentDetour);
_calculateHeightHook =
interop.HookFromAddress<CalculateHeight>((nint)Character.MemberFunctionPointers.CalculateHeight, CalculateHeightDetour);
_setupMountHook.Enable();
_setupOrnamentHook.Enable();
_placeMinionHook.Enable();
@ -34,20 +39,16 @@ public unsafe class ScalingService : IDisposable
private delegate void PlaceMinion(Companion* character);
private delegate float CalculateHeight(Character* character);
[Signature("E8 ?? ?? ?? ?? 48 8B 43 ?? 80 B8 ?? ?? ?? ?? ?? 74 ?? 0F B6 90", DetourName = nameof(SetupMountDetour))]
private readonly Hook<SetupMount> _setupMountHook = null!;
private readonly Hook<SetupMount> _setupMountHook;
[Signature("48 89 5C 24 ?? 41 54 41 56 41 57 48 83 EC ?? 4D 8B F8", DetourName = nameof(SetupOrnamentDetour))]
private readonly Hook<SetupOrnament> _setupOrnamentHook = null!;
private readonly Hook<SetupOrnament> _setupOrnamentHook;
private readonly Hook<CalculateHeight> _calculateHeightHook;
// TODO: Use client structs sig.
[Signature("48 89 5C 24 ?? 55 57 41 57 48 8D 6C 24", DetourName = nameof(PlaceMinionDetour))]
private readonly Hook<PlaceMinion> _placeMinionHook = null!;
[Signature(global::Penumbra.GameData.Sigs.CalculateHeight, DetourName = nameof(CalculateHeightDetour))]
private readonly Hook<CalculateHeight> _calculateHeightHook = null!;
[Signature("E8 ?? ?? ?? ?? 48 85 C0 48 0F 45 F8")]
private readonly delegate* unmanaged<Ornament*, Character*> _getParentGameObject = null!;
private void SetupMountDetour(Character.MountContainer* container, short mountId, uint unk1, uint unk2, uint unk3, byte unk4)
{
@ -59,7 +60,7 @@ public unsafe class ScalingService : IDisposable
private void SetupOrnamentDetour(Ornament* ornament, uint* unk1, float* unk2)
{
var character = _getParentGameObject(ornament);
var character = ornament->Character.GetParentCharacter();
if (character == null)
{
_setupOrnamentHook.Original(ornament, unk1, unk2);

View file

@ -1,5 +1,6 @@
using System;
using Dalamud.Hooking;
using Dalamud.Plugin.Services;
using Dalamud.Utility.Signatures;
using Glamourer.Events;
using Glamourer.Interop.Structs;
@ -12,10 +13,10 @@ public unsafe class UpdateSlotService : IDisposable
{
public readonly SlotUpdating SlotUpdatingEvent;
public UpdateSlotService(SlotUpdating slotUpdating)
public UpdateSlotService(SlotUpdating slotUpdating, IGameInteropProvider interop)
{
SlotUpdatingEvent = slotUpdating;
SignatureHelper.Initialise(this);
interop.InitializeFromAttributes(this);
_flagSlotForUpdateHook.Enable();
}

View file

@ -1,7 +1,9 @@
using System;
using System.Runtime.CompilerServices;
using Dalamud.Hooking;
using Dalamud.Plugin.Services;
using Dalamud.Utility.Signatures;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using Glamourer.Events;
using Glamourer.Interop.Structs;
using Penumbra.GameData.Enums;
@ -12,10 +14,11 @@ public class VisorService : IDisposable
{
public readonly VisorStateChanged Event;
public VisorService(VisorStateChanged visorStateChanged)
public unsafe VisorService(VisorStateChanged visorStateChanged, IGameInteropProvider interop)
{
Event = visorStateChanged;
SignatureHelper.Initialise(this);
_setupVisorHook = interop.HookFromAddress<UpdateVisorDelegateInternal>((nint)Human.MemberFunctionPointers.SetupVisor, SetupVisorDetour);
interop.InitializeFromAttributes(this);
_setupVisorHook.Enable();
}
@ -30,7 +33,7 @@ public class VisorService : IDisposable
/// <param name="human"> The draw object. </param>
/// <param name="on"> The desired state (true: toggled). </param>
/// <returns> Whether the state was changed. </returns>
public unsafe bool SetVisorState(Model human, bool on)
public bool SetVisorState(Model human, bool on)
{
if (!human.IsHuman)
return false;
@ -46,8 +49,7 @@ public class VisorService : IDisposable
private delegate void UpdateVisorDelegateInternal(nint humanPtr, ushort modelId, bool on);
[Signature(global::Penumbra.GameData.Sigs.SetupVisor, DetourName = nameof(SetupVisorDetour))]
private readonly Hook<UpdateVisorDelegateInternal> _setupVisorHook = null!;
private readonly Hook<UpdateVisorDelegateInternal> _setupVisorHook;
private void SetupVisorDetour(nint human, ushort modelId, bool on)
{
@ -70,10 +72,7 @@ public class VisorService : IDisposable
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private unsafe void SetupVisorHook(Model human, ushort modelId, bool on)
{
// TODO: use client structs.
human.AsCharacterBase->UnkFlags_01 = (byte)(on
? human.AsCharacterBase->UnkFlags_01 | Offsets.DrawObjectVisorStateFlag
: human.AsCharacterBase->UnkFlags_01 & ~Offsets.DrawObjectVisorStateFlag);
human.AsCharacterBase->VisorToggled = on;
_setupVisorHook.Original(human.Address, modelId, on);
}
}

View file

@ -1,5 +1,6 @@
using System;
using Dalamud.Hooking;
using Dalamud.Plugin.Services;
using Dalamud.Utility.Signatures;
using FFXIVClientStructs.FFXIV.Client.Game.Character;
using Glamourer.Events;
@ -13,11 +14,11 @@ public unsafe class WeaponService : IDisposable
{
private readonly WeaponLoading _event;
public WeaponService(WeaponLoading @event)
public WeaponService(WeaponLoading @event, IGameInteropProvider interop)
{
_event = @event;
SignatureHelper.Initialise(this);
_loadWeaponHook = Hook<LoadWeaponDelegate>.FromAddress((nint)DrawDataContainer.MemberFunctionPointers.LoadWeapon, LoadWeaponDetour);
_loadWeaponHook =
interop.HookFromAddress<LoadWeaponDelegate>((nint)DrawDataContainer.MemberFunctionPointers.LoadWeapon, LoadWeaponDetour);
_loadWeaponHook.Enable();
}

View file

@ -2,7 +2,6 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Dalamud.Game.Command;
using Dalamud.Game.Gui;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Plugin.Services;
using Glamourer.Automation;
@ -27,7 +26,7 @@ public class CommandService : IDisposable
private readonly ICommandManager _commands;
private readonly MainWindow _mainWindow;
private readonly ChatGui _chat;
private readonly IChatGui _chat;
private readonly ActorService _actors;
private readonly ObjectManager _objects;
private readonly StateManager _stateManager;
@ -37,7 +36,7 @@ public class CommandService : IDisposable
private readonly DesignConverter _converter;
private readonly DesignFileSystem _designFileSystem;
public CommandService(ICommandManager commands, MainWindow mainWindow, ChatGui chat, ActorService actors, ObjectManager objects,
public CommandService(ICommandManager commands, MainWindow mainWindow, IChatGui chat, ActorService actors, ObjectManager objects,
AutoDesignApplier autoDesignApplier, StateManager stateManager, DesignManager designManager, DesignConverter converter,
DesignFileSystem designFileSystem, AutoDesignManager autoDesignManager)
{

View file

@ -11,8 +11,8 @@ public sealed class CustomizationService : AsyncServiceWrapper<ICustomizationMan
{
public readonly HumanModelList HumanModels;
public CustomizationService(ITextureProvider textures, IDataManager gameData, HumanModelList humanModels)
: base(nameof(CustomizationService), () => CustomizationManager.Create(textures, gameData))
public CustomizationService(ITextureProvider textures, IDataManager gameData, HumanModelList humanModels, IPluginLog log)
: base(nameof(CustomizationService), () => CustomizationManager.Create(textures, gameData, log))
=> HumanModels = humanModels;
public (Customize NewValue, CustomizeFlag Applied, CustomizeFlag Changed) Combine(Customize oldValues, Customize newValues,

View file

@ -1,8 +1,4 @@
using Dalamud.Game;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Keys;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.Gui;
using Dalamud.Interface.DragDrop;
using Dalamud.IoC;
using Dalamud.Plugin;
@ -35,6 +31,8 @@ public class DalamudServices
services.AddSingleton(PluginInterface.UiBuilder);
services.AddSingleton(DragDropManager);
services.AddSingleton(TextureProvider);
services.AddSingleton(Log);
services.AddSingleton(Interop);
}
// @formatter:off
@ -42,14 +40,16 @@ public class DalamudServices
[PluginService][RequiredVersion("1.0")] public ICommandManager Commands { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public IDataManager GameData { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public IClientState ClientState { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public Condition Condition { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public ICondition Condition { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public IGameGui GameGui { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public ChatGui Chat { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public Framework Framework { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public IChatGui Chat { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public IFramework Framework { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public ITargetManager Targets { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public IObjectTable Objects { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public KeyState KeyState { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public IKeyState KeyState { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public IDragDropManager DragDropManager { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public ITextureProvider TextureProvider { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public IPluginLog Log { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public IGameInteropProvider Interop { get; private set; } = null!;
// @formatter:on
}

View file

@ -28,14 +28,14 @@ public class ItemManager : IDisposable
public readonly EquipItem DefaultSword;
public ItemManager(Configuration config, DalamudPluginInterface pi, IDataManager gameData, IdentifierService identifierService,
ItemService itemService)
ItemService itemService, IPluginLog log)
{
_config = config;
ItemSheet = gameData.GetExcelSheet<Lumina.Excel.GeneratedSheets.Item>()!;
IdentifierService = identifierService;
Stains = new StainData(pi, gameData, gameData.Language);
Stains = new StainData(pi, gameData, gameData.Language, log);
ItemService = itemService;
RestrictedGear = new RestrictedGear(pi, gameData.Language, gameData);
RestrictedGear = new RestrictedGear(pi, gameData.Language, gameData, log);
DefaultSword = EquipItem.FromMainhand(ItemSheet.GetRow(1601)!); // Weathered Shortsword
}
@ -58,13 +58,13 @@ public class ItemManager : IDisposable
=> uint.MaxValue - 384 - (uint)type;
public static EquipItem NothingItem(EquipSlot slot)
=> new(Nothing, NothingId(slot), 0, 0, 0, 0, slot.ToEquipType());
=> new(Nothing, NothingId(slot), 0, 0, 0, 0, slot.ToEquipType(), 0, 0, 0);
public static EquipItem NothingItem(FullEquipType type)
=> new(Nothing, NothingId(type), 0, 0, 0, 0, type);
=> new(Nothing, NothingId(type), 0, 0, 0, 0, type, 0, 0, 0);
public static EquipItem SmallClothesItem(EquipSlot slot)
=> new(SmallClothesNpc, SmallclothesId(slot), 0, SmallClothesNpcModel, 0, 1, slot.ToEquipType());
=> new(SmallClothesNpc, SmallclothesId(slot), 0, SmallClothesNpcModel, 0, 1, slot.ToEquipType(), 0, 0, 0);
public EquipItem Resolve(EquipSlot slot, ItemId itemId)
{
@ -78,7 +78,7 @@ public class ItemManager : IDisposable
return EquipItem.FromId(itemId);
if (item.Type.ToSlot() != slot)
return new EquipItem(string.Intern($"Invalid #{itemId}"), itemId, item.IconId, item.ModelId, item.WeaponType, item.Variant, 0);
return new EquipItem(string.Intern($"Invalid #{itemId}"), itemId, item.IconId, item.ModelId, item.WeaponType, item.Variant, 0, 0, 0, 0);
return item;
}
@ -92,7 +92,7 @@ public class ItemManager : IDisposable
return EquipItem.FromId(itemId);
if (item.Type != type)
return new EquipItem(string.Intern($"Invalid #{itemId}"), itemId, item.IconId, item.ModelId, item.WeaponType, item.Variant, 0);
return new EquipItem(string.Intern($"Invalid #{itemId}"), itemId, item.IconId, item.ModelId, item.WeaponType, item.Variant, 0, 0, 0, 0);
return item;
}
@ -101,7 +101,7 @@ public class ItemManager : IDisposable
{
slot = slot.ToSlot();
if (slot.ToIndex() == uint.MaxValue)
return new EquipItem($"Invalid ({id.Id}-{variant})", 0, 0, id, 0, variant, 0);
return new EquipItem($"Invalid ({id.Id}-{variant})", 0, 0, id, 0, variant, 0, 0, 0, 0);
switch (id.Id)
{
@ -135,12 +135,12 @@ public class ItemManager : IDisposable
}
if (slot is not EquipSlot.MainHand and not EquipSlot.OffHand)
return new EquipItem($"Invalid ({id.Id}-{type.Id}-{variant})", 0, 0, id, type, variant, 0);
return new EquipItem($"Invalid ({id.Id}-{type.Id}-{variant})", 0, 0, id, type, variant, 0, 0, 0, 0);
var item = IdentifierService.AwaitedService.Identify(id, type, variant, slot).FirstOrDefault(i => i.Type.ToSlot() == slot);
return item.Valid
? item
: EquipItem.FromIds(0, 0, id, type, variant, slot.ToEquipType(), null);
: EquipItem.FromIds(0, 0, id, type, variant, slot.ToEquipType());
}
/// <summary> Returns whether an item id represents a valid item for a slot and gives the item. </summary>

View file

@ -2,7 +2,6 @@ using Dalamud.Plugin;
using Penumbra.GameData.Actors;
using System;
using System.Threading.Tasks;
using Dalamud.Game;
using Dalamud.Plugin.Services;
using Glamourer.Interop.Penumbra;
using Penumbra.GameData.Data;
@ -72,23 +71,23 @@ public abstract class AsyncServiceWrapper<T> : IDisposable
public sealed class IdentifierService : AsyncServiceWrapper<IObjectIdentifier>
{
public IdentifierService(DalamudPluginInterface pi, IDataManager data, ItemService itemService)
: base(nameof(IdentifierService), () => Penumbra.GameData.GameData.GetIdentifier(pi, data, itemService.AwaitedService))
public IdentifierService(DalamudPluginInterface pi, IDataManager data, ItemService itemService, IPluginLog log)
: base(nameof(IdentifierService), () => Penumbra.GameData.GameData.GetIdentifier(pi, data, itemService.AwaitedService, log))
{ }
}
public sealed class ItemService : AsyncServiceWrapper<ItemData>
{
public ItemService(DalamudPluginInterface pi, IDataManager gameData)
: base(nameof(ItemService), () => new ItemData(pi, gameData, gameData.Language))
public ItemService(DalamudPluginInterface pi, IDataManager gameData, IPluginLog log)
: base(nameof(ItemService), () => new ItemData(pi, gameData, gameData.Language, log))
{ }
}
public sealed class ActorService : AsyncServiceWrapper<ActorManager>
{
public ActorService(DalamudPluginInterface pi, IObjectTable objects, IClientState clientState, Framework framework, IDataManager gameData,
IGameGui gui, PenumbraService penumbra)
public ActorService(DalamudPluginInterface pi, IObjectTable objects, IClientState clientState, IFramework framework, IGameInteropProvider interop, IDataManager gameData,
IGameGui gui, PenumbraService penumbra, IPluginLog log)
: base(nameof(ActorService),
() => new ActorManager(pi, objects, clientState, framework, gameData, gui, idx => (short)penumbra.CutsceneParent(idx)))
() => new ActorManager(pi, objects, clientState, framework, interop, gameData, gui, idx => (short)penumbra.CutsceneParent(idx), log))
{ }
}

View file

@ -1,9 +1,8 @@
using System;
using System.Numerics;
using Dalamud.Game;
using Dalamud.Interface;
using Dalamud.Interface.Internal;
using Dalamud.Plugin.Services;
using ImGuiScene;
using OtterGui.Classes;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
@ -16,7 +15,7 @@ public sealed class TextureService : TextureCache, IDisposable
: base(dataManager, textureProvider)
=> _slotIcons = CreateSlotIcons(uiBuilder);
private readonly TextureWrap?[] _slotIcons;
private readonly IDalamudTextureWrap?[] _slotIcons;
public (nint, Vector2, bool) GetIcon(EquipItem item, EquipSlot slot)
{
@ -38,9 +37,9 @@ public sealed class TextureService : TextureCache, IDisposable
}
}
private static TextureWrap[] CreateSlotIcons(UiBuilder uiBuilder)
private static IDalamudTextureWrap[] CreateSlotIcons(UiBuilder uiBuilder)
{
var ret = new TextureWrap[12];
var ret = new IDalamudTextureWrap[12];
using var uldWrapper = uiBuilder.LoadUld("ui/uld/ArmouryBoard.uld");

View file

@ -6,6 +6,7 @@ using Penumbra.GameData.Actors;
using Penumbra.GameData.Enums;
using System.Linq;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Plugin.Services;
using CustomizeIndex = Glamourer.Customization.CustomizeIndex;
namespace Glamourer.State;
@ -23,7 +24,7 @@ public class ActorState
public readonly ActorIdentifier Identifier;
public bool AllowsRedraw(Condition condition)
public bool AllowsRedraw(ICondition condition)
=> Identifier.Type is not IdentifierType.Special && !condition[ConditionFlag.OccupiedInCutSceneEvent];
/// <summary> This should always represent the unmodified state of the draw object. </summary>

View file

@ -1,6 +1,6 @@
using System;
using System.Linq;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Plugin.Services;
using Glamourer.Customization;
using Glamourer.Events;
using Glamourer.Services;
@ -16,9 +16,9 @@ public class StateEditor
private readonly CustomizationService _customizations;
private readonly HumanModelList _humans;
private readonly GPoseService _gPose;
private readonly Condition _condition;
private readonly ICondition _condition;
public StateEditor(CustomizationService customizations, HumanModelList humans, ItemManager items, GPoseService gPose, Condition condition)
public StateEditor(CustomizationService customizations, HumanModelList humans, ItemManager items, GPoseService gPose, ICondition condition)
{
_customizations = customizations;
_humans = humans;

View file

@ -12,6 +12,7 @@ using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
using System;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Plugin.Services;
namespace Glamourer.State;
@ -41,7 +42,7 @@ public class StateListener : IDisposable
private readonly MovedEquipment _movedEquipment;
private readonly GPoseService _gPose;
private readonly ChangeCustomizeService _changeCustomizeService;
private readonly Condition _condition;
private readonly ICondition _condition;
private ActorIdentifier _creatingIdentifier = ActorIdentifier.Invalid;
private ActorState? _creatingState;
@ -57,7 +58,7 @@ public class StateListener : IDisposable
SlotUpdating slotUpdating, WeaponLoading weaponLoading, VisorStateChanged visorState, WeaponVisibilityChanged weaponVisibility,
HeadGearVisibilityChanged headGearVisibility, AutoDesignApplier autoDesignApplier, FunModule funModule, HumanModelList humans,
StateApplier applier, MovedEquipment movedEquipment, ObjectManager objects, GPoseService gPose,
ChangeCustomizeService changeCustomizeService, CustomizationService customizations, Condition condition)
ChangeCustomizeService changeCustomizeService, CustomizationService customizations, ICondition condition)
{
_manager = manager;
_items = items;

View file

@ -3,8 +3,6 @@ using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Plugin.Services;
using Glamourer.Customization;
using Glamourer.Designs;
@ -27,13 +25,13 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
private readonly StateChanged _event;
private readonly StateApplier _applier;
private readonly StateEditor _editor;
private readonly Condition _condition;
private readonly ICondition _condition;
private readonly IClientState _clientState;
private readonly Dictionary<ActorIdentifier, ActorState> _states = new();
public StateManager(ActorService actors, ItemManager items, StateChanged @event, StateApplier applier, StateEditor editor,
HumanModelList humans, Condition condition, IClientState clientState)
HumanModelList humans, ICondition condition, IClientState clientState)
{
_actors = actors;
_items = items;

View file

@ -29,23 +29,23 @@ public class CustomizeUnlockManager : IDisposable, ISavable
=> _unlocked;
public CustomizeUnlockManager(SaveService saveService, CustomizationService customizations, IDataManager gameData,
IClientState clientState, ObjectUnlocked @event)
IClientState clientState, ObjectUnlocked @event, IGameInteropProvider interop)
{
SignatureHelper.Initialise(this);
interop.InitializeFromAttributes(this);
_saveService = saveService;
_clientState = clientState;
_event = @event;
Unlockable = CreateUnlockableCustomizations(customizations, gameData);
Load();
_setUnlockLinkValueHook.Enable();
_clientState.Login += OnLogin;
_clientState.Login += Scan;
Scan();
}
public void Dispose()
{
_setUnlockLinkValueHook.Dispose();
_clientState.Login -= OnLogin;
_clientState.Login -= Scan;
}
/// <summary> Check if a customization is unlocked for Glamourer. </summary>
@ -159,9 +159,6 @@ public class CustomizeUnlockManager : IDisposable, ISavable
}
}
private void OnLogin(object? _, EventArgs _2)
=> Scan();
public string ToFilename(FilenameService fileNames)
=> fileNames.UnlockFileCustomize;

View file

@ -3,9 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Dalamud.Game;
using Dalamud.Plugin.Services;
using Dalamud.Utility.Signatures;
using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.Game.UI;
using Glamourer.Events;
@ -22,7 +20,7 @@ public class ItemUnlockManager : ISavable, IDisposable, IReadOnlyDictionary<Item
private readonly SaveService _saveService;
private readonly ItemManager _items;
private readonly IClientState _clientState;
private readonly Framework _framework;
private readonly IFramework _framework;
private readonly ObjectUnlocked _event;
private readonly IdentifierService _identifier;
@ -46,10 +44,10 @@ public class ItemUnlockManager : ISavable, IDisposable, IReadOnlyDictionary<Item
public readonly IReadOnlyDictionary<ItemId, UnlockRequirements> Unlockable;
public ItemUnlockManager(SaveService saveService, ItemManager items, IClientState clientState, IDataManager gameData, Framework framework,
ObjectUnlocked @event, IdentifierService identifier)
public ItemUnlockManager(SaveService saveService, ItemManager items, IClientState clientState, IDataManager gameData, IFramework framework,
ObjectUnlocked @event, IdentifierService identifier, IGameInteropProvider interop)
{
SignatureHelper.Initialise(this);
interop.InitializeFromAttributes(this);
_saveService = saveService;
_items = items;
_clientState = clientState;
@ -58,7 +56,7 @@ public class ItemUnlockManager : ISavable, IDisposable, IReadOnlyDictionary<Item
_identifier = identifier;
Unlockable = CreateUnlockData(gameData, items);
Load();
_clientState.Login += OnLogin;
_clientState.Login += Scan;
_framework.Update += OnFramework;
Scan();
}
@ -117,7 +115,7 @@ public class ItemUnlockManager : ISavable, IDisposable, IReadOnlyDictionary<Item
return true;
}
private unsafe void OnFramework(Framework _)
private unsafe void OnFramework(IFramework _)
{
var uiState = UIState.Instance();
if (uiState == null)
@ -240,7 +238,7 @@ public class ItemUnlockManager : ISavable, IDisposable, IReadOnlyDictionary<Item
public void Dispose()
{
_clientState.Login -= OnLogin;
_clientState.Login -= Scan;
_framework.Update -= OnFramework;
}
@ -278,9 +276,6 @@ public class ItemUnlockManager : ISavable, IDisposable, IReadOnlyDictionary<Item
UpdateModels(version);
}
private void OnLogin(object? _, EventArgs _2)
=> Scan();
private static Dictionary<ItemId, UnlockRequirements> CreateUnlockData(IDataManager gameData, ItemManager items)
{
var ret = new Dictionary<ItemId, UnlockRequirements>();

@ -1 +1 @@
Subproject commit 99047a4780991a38e42a5ea8480c947601d4b57b
Subproject commit b4092c45d9b0b885bcc08f0f81b5c4fc9ea383a7

@ -1 +1 @@
Subproject commit 64fe8c348dda8aed2e2e3c0dd1864501bfb4be85
Subproject commit acf8cf68f06e37bbe64f1100a68937da9efb762c

View file

@ -21,7 +21,7 @@
"TestingAssemblyVersion": "1.0.0.6",
"RepoUrl": "https://github.com/Ottermandias/Glamourer",
"ApplicableVersion": "any",
"DalamudApiLevel": 8,
"DalamudApiLevel": 9,
"IsHide": "False",
"IsTestingExclusive": "False",
"DownloadCount": 1,