mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-15 05:04:16 +01:00
Add handling for Monk fist weapon hack, remove LoadEquipment hooks, and add item movement and plate apply hooks instead.
This commit is contained in:
parent
323924fba2
commit
5874688838
19 changed files with 403 additions and 128 deletions
|
|
@ -1,31 +0,0 @@
|
||||||
using System;
|
|
||||||
using Glamourer.Interop.Structs;
|
|
||||||
using OtterGui.Classes;
|
|
||||||
using Penumbra.GameData.Enums;
|
|
||||||
using Penumbra.GameData.Structs;
|
|
||||||
|
|
||||||
namespace Glamourer.Events;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Triggered when a game object updates an equipment piece in its model data.
|
|
||||||
/// <list type="number">
|
|
||||||
/// <item>Parameter is the character updating. </item>
|
|
||||||
/// <item>Parameter is the equipment slot changed. </item>
|
|
||||||
/// <item>Parameter is the model values to change the equipment piece to. </item>
|
|
||||||
/// </list>
|
|
||||||
/// </summary>
|
|
||||||
public sealed class EquipmentLoading : EventWrapper<Action<Actor, EquipSlot, CharacterArmor>, EquipmentLoading.Priority>
|
|
||||||
{
|
|
||||||
public enum Priority
|
|
||||||
{
|
|
||||||
/// <seealso cref="State.StateListener.OnEquipmentLoading"/>
|
|
||||||
StateListener = 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
public EquipmentLoading()
|
|
||||||
: base(nameof(EquipmentLoading))
|
|
||||||
{ }
|
|
||||||
|
|
||||||
public void Invoke(Actor actor, EquipSlot slot, CharacterArmor armor)
|
|
||||||
=> Invoke(this, actor, slot, armor);
|
|
||||||
}
|
|
||||||
28
Glamourer/Events/MovedEquipment.cs
Normal file
28
Glamourer/Events/MovedEquipment.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
using System;
|
||||||
|
using OtterGui.Classes;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
|
using Penumbra.GameData.Structs;
|
||||||
|
|
||||||
|
namespace Glamourer.Events;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Triggered when a game object updates an equipment piece in its model data.
|
||||||
|
/// <list type="number">
|
||||||
|
/// <item>Parameter is an array of slots updated and corresponding item ids and stains. </item>
|
||||||
|
/// </list>
|
||||||
|
/// </summary>
|
||||||
|
public sealed class MovedEquipment : EventWrapper<Action<(EquipSlot, uint, StainId)[]>, MovedEquipment.Priority>
|
||||||
|
{
|
||||||
|
public enum Priority
|
||||||
|
{
|
||||||
|
/// <seealso cref="State.StateListener.OnMovedEquipment"/>
|
||||||
|
StateListener = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
public MovedEquipment()
|
||||||
|
: base(nameof(MovedEquipment))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public void Invoke((EquipSlot, uint, StainId)[] items)
|
||||||
|
=> Invoke(this, items);
|
||||||
|
}
|
||||||
|
|
@ -20,8 +20,7 @@ public partial class CustomizationDrawer
|
||||||
|
|
||||||
using (var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, 2 * ImGuiHelpers.GlobalScale, current < 0))
|
using (var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, 2 * ImGuiHelpers.GlobalScale, current < 0))
|
||||||
{
|
{
|
||||||
// Print 1-based index instead of 0.
|
if (ImGui.ColorButton($"{current}##color", color, ImGuiColorEditFlags.None, _framedIconSize))
|
||||||
if (ImGui.ColorButton($"{current + 1}##color", color, ImGuiColorEditFlags.None, _framedIconSize))
|
|
||||||
ImGui.OpenPopup(ColorPickerPopupName);
|
ImGui.OpenPopup(ColorPickerPopupName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,7 +64,7 @@ public partial class CustomizationDrawer
|
||||||
for (var i = 0; i < _currentCount; ++i)
|
for (var i = 0; i < _currentCount; ++i)
|
||||||
{
|
{
|
||||||
var custom = _set.Data(_currentIndex, i, _customize[CustomizeIndex.Face]);
|
var custom = _set.Data(_currentIndex, i, _customize[CustomizeIndex.Face]);
|
||||||
if (ImGui.ColorButton((i + 1).ToString(), ImGui.ColorConvertU32ToFloat4(custom.Color)))
|
if (ImGui.ColorButton(i.ToString(), ImGui.ColorConvertU32ToFloat4(custom.Color)))
|
||||||
{
|
{
|
||||||
UpdateValue(custom.Value);
|
UpdateValue(custom.Value);
|
||||||
ImGui.CloseCurrentPopup();
|
ImGui.CloseCurrentPopup();
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,9 @@ public class EquipmentDrawer
|
||||||
private readonly TextureService _textures;
|
private readonly TextureService _textures;
|
||||||
private readonly Configuration _config;
|
private readonly Configuration _config;
|
||||||
|
|
||||||
|
private float _requiredComboWidthUnscaled;
|
||||||
|
private float _requiredComboWidth;
|
||||||
|
|
||||||
public EquipmentDrawer(DataManager gameData, ItemManager items, CodeService codes, TextureService textures, Configuration config)
|
public EquipmentDrawer(DataManager gameData, ItemManager items, CodeService codes, TextureService textures, Configuration config)
|
||||||
{
|
{
|
||||||
_items = items;
|
_items = items;
|
||||||
|
|
@ -60,6 +63,13 @@ public class EquipmentDrawer
|
||||||
{
|
{
|
||||||
_iconSize = new Vector2(2 * ImGui.GetFrameHeight() + ImGui.GetStyle().ItemSpacing.Y);
|
_iconSize = new Vector2(2 * ImGui.GetFrameHeight() + ImGui.GetStyle().ItemSpacing.Y);
|
||||||
_comboLength = DefaultWidth * ImGuiHelpers.GlobalScale;
|
_comboLength = DefaultWidth * ImGuiHelpers.GlobalScale;
|
||||||
|
if (_requiredComboWidthUnscaled == 0)
|
||||||
|
{
|
||||||
|
_requiredComboWidthUnscaled = _items.ItemService.AwaitedService.AllItems(true).Concat(_items.ItemService.AwaitedService.AllItems(false))
|
||||||
|
.Max(i => ImGui.CalcTextSize($"{i.Item2.Name} ({i.Item2.ModelString})").X) / ImGuiHelpers.GlobalScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
_requiredComboWidth = _requiredComboWidthUnscaled * ImGuiHelpers.GlobalScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool VerifyRestrictedGear(EquipSlot slot, EquipItem gear, Gender gender, Race race)
|
private bool VerifyRestrictedGear(EquipSlot slot, EquipItem gear, Gender gender, Race race)
|
||||||
|
|
@ -171,7 +181,7 @@ public class EquipmentDrawer
|
||||||
|
|
||||||
label = combo.Label;
|
label = combo.Label;
|
||||||
using var disabled = ImRaii.Disabled(locked);
|
using var disabled = ImRaii.Disabled(locked);
|
||||||
if (!combo.Draw(weapon.Name, weapon.ItemId, small ? _comboLength - ImGui.GetFrameHeight() : _comboLength))
|
if (!combo.Draw(weapon.Name, weapon.ItemId, small ? _comboLength - ImGui.GetFrameHeight() : _comboLength, _requiredComboWidth))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
weapon = combo.CurrentSelection;
|
weapon = combo.CurrentSelection;
|
||||||
|
|
@ -189,7 +199,7 @@ public class EquipmentDrawer
|
||||||
|
|
||||||
label = combo.Label;
|
label = combo.Label;
|
||||||
using var disabled = ImRaii.Disabled(locked);
|
using var disabled = ImRaii.Disabled(locked);
|
||||||
var change = combo.Draw(weapon.Name, weapon.ItemId, small ? _comboLength - ImGui.GetFrameHeight() : _comboLength);
|
var change = combo.Draw(weapon.Name, weapon.ItemId, small ? _comboLength - ImGui.GetFrameHeight() : _comboLength, _requiredComboWidth);
|
||||||
if (change)
|
if (change)
|
||||||
weapon = combo.CurrentSelection;
|
weapon = combo.CurrentSelection;
|
||||||
|
|
||||||
|
|
@ -225,7 +235,7 @@ public class EquipmentDrawer
|
||||||
label = combo.Label;
|
label = combo.Label;
|
||||||
armor = current;
|
armor = current;
|
||||||
using var disabled = ImRaii.Disabled(locked);
|
using var disabled = ImRaii.Disabled(locked);
|
||||||
var change = combo.Draw(armor.Name, armor.ItemId, small ? _comboLength - ImGui.GetFrameHeight() : _comboLength);
|
var change = combo.Draw(armor.Name, armor.ItemId, small ? _comboLength - ImGui.GetFrameHeight() : _comboLength, _requiredComboWidth);
|
||||||
if (change)
|
if (change)
|
||||||
armor = combo.CurrentSelection;
|
armor = combo.CurrentSelection;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ public sealed class ItemCombo : FilterComboCache<EquipItem>
|
||||||
|
|
||||||
public readonly string Label;
|
public readonly string Label;
|
||||||
private uint _currentItem;
|
private uint _currentItem;
|
||||||
|
private float _innerWidth;
|
||||||
|
|
||||||
public ItemCombo(DataManager gameData, ItemManager items, EquipSlot slot, TextureService textures)
|
public ItemCombo(DataManager gameData, ItemManager items, EquipSlot slot, TextureService textures)
|
||||||
: base(() => GetItems(items, slot))
|
: base(() => GetItems(items, slot))
|
||||||
|
|
@ -46,12 +47,16 @@ public sealed class ItemCombo : FilterComboCache<EquipItem>
|
||||||
return base.UpdateCurrentSelected(CurrentSelectionIdx);
|
return base.UpdateCurrentSelected(CurrentSelectionIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Draw(string previewName, uint previewIdx, float width)
|
public bool Draw(string previewName, uint previewIdx, float width, float innerWidth)
|
||||||
{
|
{
|
||||||
|
_innerWidth = innerWidth;
|
||||||
_currentItem = previewIdx;
|
_currentItem = previewIdx;
|
||||||
return Draw($"##{Label}", previewName, string.Empty, width, ImGui.GetTextLineHeightWithSpacing());
|
return Draw($"##{Label}", previewName, string.Empty, width, ImGui.GetTextLineHeightWithSpacing());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override float GetFilterWidth()
|
||||||
|
=> _innerWidth - 2 * ImGui.GetStyle().FramePadding.X;
|
||||||
|
|
||||||
protected override bool DrawSelectable(int globalIdx, bool selected)
|
protected override bool DrawSelectable(int globalIdx, bool selected)
|
||||||
{
|
{
|
||||||
var obj = Items[globalIdx];
|
var obj = Items[globalIdx];
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ public sealed class WeaponCombo : FilterComboCache<EquipItem>
|
||||||
{
|
{
|
||||||
public readonly string Label;
|
public readonly string Label;
|
||||||
private uint _currentItemId;
|
private uint _currentItemId;
|
||||||
|
private float _innerWidth;
|
||||||
|
|
||||||
public WeaponCombo(ItemManager items, FullEquipType type)
|
public WeaponCombo(ItemManager items, FullEquipType type)
|
||||||
: base(() => GetWeapons(items, type))
|
: base(() => GetWeapons(items, type))
|
||||||
|
|
@ -41,9 +42,13 @@ public sealed class WeaponCombo : FilterComboCache<EquipItem>
|
||||||
return base.UpdateCurrentSelected(CurrentSelectionIdx);
|
return base.UpdateCurrentSelected(CurrentSelectionIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Draw(string previewName, uint previewId, float width)
|
protected override float GetFilterWidth()
|
||||||
|
=> _innerWidth - 2 * ImGui.GetStyle().FramePadding.X;
|
||||||
|
|
||||||
|
public bool Draw(string previewName, uint previewId, float width, float innerWidth)
|
||||||
{
|
{
|
||||||
_currentItemId = previewId;
|
_currentItemId = previewId;
|
||||||
|
_innerWidth = innerWidth;
|
||||||
return Draw($"##{Label}", previewName, string.Empty, width, ImGui.GetTextLineHeightWithSpacing());
|
return Draw($"##{Label}", previewName, string.Empty, width, ImGui.GetTextLineHeightWithSpacing());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ public class PenumbraChangedItemTooltip : IDisposable
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case ChangedItemType.Item:
|
case ChangedItemType.Item:
|
||||||
if (!_items.ItemService.AwaitedService.TryGetValue(id, out var item))
|
if (!_items.ItemService.AwaitedService.TryGetValue(id, EquipSlot.MainHand, out var item))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CreateTooltip(item, "[Glamourer] ", false);
|
CreateTooltip(item, "[Glamourer] ", false);
|
||||||
|
|
@ -192,7 +192,7 @@ public class PenumbraChangedItemTooltip : IDisposable
|
||||||
if (!Player(out var state))
|
if (!Player(out var state))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_items.ItemService.AwaitedService.TryGetValue(id, out var item))
|
if (!_items.ItemService.AwaitedService.TryGetValue(id, EquipSlot.MainHand, out var item))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ApplyItem(state, item);
|
ApplyItem(state, item);
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ using Dalamud.Game.ClientState.Objects;
|
||||||
using Dalamud.Game.ClientState.Objects.Types;
|
using Dalamud.Game.ClientState.Objects.Types;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||||
using Glamourer.Api;
|
using Glamourer.Api;
|
||||||
using Glamourer.Automation;
|
using Glamourer.Automation;
|
||||||
|
|
@ -42,6 +43,7 @@ public unsafe class DebugTab : ITab
|
||||||
private readonly UpdateSlotService _updateSlotService;
|
private readonly UpdateSlotService _updateSlotService;
|
||||||
private readonly WeaponService _weaponService;
|
private readonly WeaponService _weaponService;
|
||||||
private readonly MetaService _metaService;
|
private readonly MetaService _metaService;
|
||||||
|
private readonly InventoryService _inventoryService;
|
||||||
private readonly PenumbraService _penumbra;
|
private readonly PenumbraService _penumbra;
|
||||||
private readonly ObjectTable _objects;
|
private readonly ObjectTable _objects;
|
||||||
private readonly ObjectManager _objectManager;
|
private readonly ObjectManager _objectManager;
|
||||||
|
|
@ -76,7 +78,7 @@ public unsafe class DebugTab : ITab
|
||||||
DesignFileSystem designFileSystem, DesignManager designManager, StateManager state, Configuration config,
|
DesignFileSystem designFileSystem, DesignManager designManager, StateManager state, Configuration config,
|
||||||
PenumbraChangedItemTooltip penumbraTooltip, MetaService metaService, GlamourerIpc ipc, DalamudPluginInterface pluginInterface,
|
PenumbraChangedItemTooltip penumbraTooltip, MetaService metaService, GlamourerIpc ipc, DalamudPluginInterface pluginInterface,
|
||||||
AutoDesignManager autoDesignManager, JobService jobs, CodeService code, CustomizeUnlockManager customizeUnlocks,
|
AutoDesignManager autoDesignManager, JobService jobs, CodeService code, CustomizeUnlockManager customizeUnlocks,
|
||||||
ItemUnlockManager itemUnlocks, DesignConverter designConverter, DatFileService datFileService)
|
ItemUnlockManager itemUnlocks, DesignConverter designConverter, DatFileService datFileService, InventoryService inventoryService)
|
||||||
{
|
{
|
||||||
_changeCustomizeService = changeCustomizeService;
|
_changeCustomizeService = changeCustomizeService;
|
||||||
_visorService = visorService;
|
_visorService = visorService;
|
||||||
|
|
@ -103,6 +105,7 @@ public unsafe class DebugTab : ITab
|
||||||
_itemUnlocks = itemUnlocks;
|
_itemUnlocks = itemUnlocks;
|
||||||
_designConverter = designConverter;
|
_designConverter = designConverter;
|
||||||
_datFileService = datFileService;
|
_datFileService = datFileService;
|
||||||
|
_inventoryService = inventoryService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlySpan<byte> Label
|
public ReadOnlySpan<byte> Label
|
||||||
|
|
@ -120,6 +123,7 @@ public unsafe class DebugTab : ITab
|
||||||
DrawDesigns();
|
DrawDesigns();
|
||||||
DrawState();
|
DrawState();
|
||||||
DrawAutoDesigns();
|
DrawAutoDesigns();
|
||||||
|
DrawInventory();
|
||||||
DrawUnlocks();
|
DrawUnlocks();
|
||||||
DrawIpc();
|
DrawIpc();
|
||||||
}
|
}
|
||||||
|
|
@ -860,7 +864,7 @@ public unsafe class DebugTab : ITab
|
||||||
if (!table)
|
if (!table)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach(var (index, value) in set.NpcOptions)
|
foreach (var (index, value) in set.NpcOptions)
|
||||||
{
|
{
|
||||||
ImGuiUtil.DrawTableColumn(index.ToString());
|
ImGuiUtil.DrawTableColumn(index.ToString());
|
||||||
ImGuiUtil.DrawTableColumn(value.Value.ToString());
|
ImGuiUtil.DrawTableColumn(value.Value.ToString());
|
||||||
|
|
@ -980,6 +984,7 @@ public unsafe class DebugTab : ITab
|
||||||
|
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.NewLine();
|
ImGui.NewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -996,6 +1001,7 @@ public unsafe class DebugTab : ITab
|
||||||
|
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.NewLine();
|
ImGui.NewLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1442,7 +1448,7 @@ public unsafe class DebugTab : ITab
|
||||||
var remainder = ImGuiClip.ClippedDraw(_itemUnlocks.Unlocked, skips, t =>
|
var remainder = ImGuiClip.ClippedDraw(_itemUnlocks.Unlocked, skips, t =>
|
||||||
{
|
{
|
||||||
ImGuiUtil.DrawTableColumn(t.Key.ToString());
|
ImGuiUtil.DrawTableColumn(t.Key.ToString());
|
||||||
if (_items.ItemService.AwaitedService.TryGetValue(t.Key, out var equip))
|
if (_items.ItemService.AwaitedService.TryGetValue(t.Key, EquipSlot.MainHand, out var equip))
|
||||||
{
|
{
|
||||||
ImGuiUtil.DrawTableColumn(equip.Name);
|
ImGuiUtil.DrawTableColumn(equip.Name);
|
||||||
ImGuiUtil.DrawTableColumn(equip.Type.ToName());
|
ImGuiUtil.DrawTableColumn(equip.Type.ToName());
|
||||||
|
|
@ -1489,7 +1495,7 @@ public unsafe class DebugTab : ITab
|
||||||
var remainder = ImGuiClip.ClippedDraw(_itemUnlocks.Unlockable, skips, t =>
|
var remainder = ImGuiClip.ClippedDraw(_itemUnlocks.Unlockable, skips, t =>
|
||||||
{
|
{
|
||||||
ImGuiUtil.DrawTableColumn(t.Key.ToString());
|
ImGuiUtil.DrawTableColumn(t.Key.ToString());
|
||||||
if (_items.ItemService.AwaitedService.TryGetValue(t.Key, out var equip))
|
if (_items.ItemService.AwaitedService.TryGetValue(t.Key, EquipSlot.MainHand, out var equip))
|
||||||
{
|
{
|
||||||
ImGuiUtil.DrawTableColumn(equip.Name);
|
ImGuiUtil.DrawTableColumn(equip.Name);
|
||||||
ImGuiUtil.DrawTableColumn(equip.Type.ToName());
|
ImGuiUtil.DrawTableColumn(equip.Type.ToName());
|
||||||
|
|
@ -1514,6 +1520,50 @@ public unsafe class DebugTab : ITab
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Inventory
|
||||||
|
|
||||||
|
private void DrawInventory()
|
||||||
|
{
|
||||||
|
if (!ImGui.CollapsingHeader("Inventory"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var inventory = InventoryManager.Instance();
|
||||||
|
if (inventory == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGuiUtil.CopyOnClickSelectable($"0x{(ulong)inventory:X}");
|
||||||
|
|
||||||
|
var equip = inventory->GetInventoryContainer(InventoryType.EquippedItems);
|
||||||
|
if (equip == null || equip->Loaded == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGuiUtil.CopyOnClickSelectable($"0x{(ulong)equip:X}");
|
||||||
|
|
||||||
|
using var table = ImRaii.Table("items", 4, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit);
|
||||||
|
if (!table)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (var i = 0; i < equip->Size; ++i)
|
||||||
|
{
|
||||||
|
ImGuiUtil.DrawTableColumn(i.ToString());
|
||||||
|
var item = equip->GetInventorySlot(i);
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
ImGuiUtil.DrawTableColumn("NULL");
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGuiUtil.DrawTableColumn(item->ItemID.ToString());
|
||||||
|
ImGuiUtil.DrawTableColumn(item->GlamourID.ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGuiUtil.CopyOnClickSelectable($"0x{(ulong)item:X}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region IPC
|
#region IPC
|
||||||
|
|
||||||
private string _gameObjectName = string.Empty;
|
private string _gameObjectName = string.Empty;
|
||||||
|
|
|
||||||
|
|
@ -179,7 +179,7 @@ public class UnlockOverview
|
||||||
ImGui.TextUnformatted($"{item.Type.ToName()} ({slot.ToName()})");
|
ImGui.TextUnformatted($"{item.Type.ToName()} ({slot.ToName()})");
|
||||||
if (item.Type.ValidOffhand().IsOffhandType())
|
if (item.Type.ValidOffhand().IsOffhandType())
|
||||||
ImGui.TextUnformatted(
|
ImGui.TextUnformatted(
|
||||||
$"{item.Weapon()}{(_items.ItemService.AwaitedService.TryGetValue(item.ItemId, false, out var offhand) ? $" | {offhand.Weapon()}" : string.Empty)}");
|
$"{item.Weapon()}{(_items.ItemService.AwaitedService.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand) ? $" | {offhand.Weapon()}" : string.Empty)}");
|
||||||
else
|
else
|
||||||
ImGui.TextUnformatted(slot is EquipSlot.MainHand ? $"{item.Weapon()}" : $"{item.Armor()}");
|
ImGui.TextUnformatted(slot is EquipSlot.MainHand ? $"{item.Weapon()}" : $"{item.Armor()}");
|
||||||
ImGui.TextUnformatted(
|
ImGui.TextUnformatted(
|
||||||
|
|
|
||||||
|
|
@ -242,7 +242,7 @@ public class UnlockTable : Table<EquipItem>, IDisposable
|
||||||
ImGuiUtil.RightAlign(item.ModelString);
|
ImGuiUtil.RightAlign(item.ModelString);
|
||||||
if (ImGui.IsItemHovered()
|
if (ImGui.IsItemHovered()
|
||||||
&& item.Type.ValidOffhand().IsOffhandType()
|
&& item.Type.ValidOffhand().IsOffhandType()
|
||||||
&& _items.ItemService.AwaitedService.TryGetValue(item.ItemId, false, out var offhand))
|
&& _items.ItemService.AwaitedService.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand))
|
||||||
{
|
{
|
||||||
using var tt = ImRaii.Tooltip();
|
using var tt = ImRaii.Tooltip();
|
||||||
ImGui.TextUnformatted("Offhand: " + offhand.ModelString);
|
ImGui.TextUnformatted("Offhand: " + offhand.ModelString);
|
||||||
|
|
@ -260,7 +260,7 @@ public class UnlockTable : Table<EquipItem>, IDisposable
|
||||||
if (FilterRegex?.IsMatch(item.ModelString) ?? item.ModelString.Contains(FilterValue, StringComparison.OrdinalIgnoreCase))
|
if (FilterRegex?.IsMatch(item.ModelString) ?? item.ModelString.Contains(FilterValue, StringComparison.OrdinalIgnoreCase))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (item.Type.ValidOffhand().IsOffhandType() && _items.ItemService.AwaitedService.TryGetValue(item.ItemId, false, out var offhand))
|
if (item.Type.ValidOffhand().IsOffhandType() && _items.ItemService.AwaitedService.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand))
|
||||||
return FilterRegex?.IsMatch(offhand.ModelString)
|
return FilterRegex?.IsMatch(offhand.ModelString)
|
||||||
?? offhand.ModelString.Contains(FilterValue, StringComparison.OrdinalIgnoreCase);
|
?? offhand.ModelString.Contains(FilterValue, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
|
|
||||||
202
Glamourer/Interop/InventoryService.cs
Normal file
202
Glamourer/Interop/InventoryService.cs
Normal file
|
|
@ -0,0 +1,202 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Dalamud.Hooking;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
||||||
|
using Glamourer.Events;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
|
using Penumbra.GameData.Structs;
|
||||||
|
|
||||||
|
namespace Glamourer.Interop;
|
||||||
|
|
||||||
|
public unsafe class InventoryService : IDisposable
|
||||||
|
{
|
||||||
|
private readonly MovedEquipment _event;
|
||||||
|
private readonly List<(EquipSlot, uint, StainId)> _itemList = new(12);
|
||||||
|
|
||||||
|
public InventoryService(MovedEquipment @event)
|
||||||
|
{
|
||||||
|
_event = @event;
|
||||||
|
_moveItemHook = Hook<MoveItemDelegate>.FromAddress((nint)InventoryManager.MemberFunctionPointers.MoveItemSlot, MoveItemDetour);
|
||||||
|
_equipGearsetHook =
|
||||||
|
Hook<EquipGearsetDelegate>.FromAddress((nint)RaptureGearsetModule.MemberFunctionPointers.EquipGearset, EquipGearSetDetour);
|
||||||
|
_moveItemHook.Enable();
|
||||||
|
_equipGearsetHook.Enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_moveItemHook.Dispose();
|
||||||
|
_equipGearsetHook.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private delegate int EquipGearsetDelegate(RaptureGearsetModule* module, int gearsetId, byte glamourPlateId);
|
||||||
|
|
||||||
|
private readonly Hook<EquipGearsetDelegate> _equipGearsetHook;
|
||||||
|
|
||||||
|
private int EquipGearSetDetour(RaptureGearsetModule* module, int gearsetId, byte glamourPlateId)
|
||||||
|
{
|
||||||
|
var ret = _equipGearsetHook.Original(module, gearsetId, glamourPlateId);
|
||||||
|
Glamourer.Log.Excessive($"[InventoryService] Applied gear set {gearsetId} with glamour plate {glamourPlateId} (Returned {ret})");
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
var entry = module->GetGearset(gearsetId);
|
||||||
|
if (entry == null)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (glamourPlateId == 0)
|
||||||
|
glamourPlateId = entry->GlamourSetLink;
|
||||||
|
|
||||||
|
_itemList.Clear();
|
||||||
|
|
||||||
|
|
||||||
|
if (glamourPlateId != 0)
|
||||||
|
{
|
||||||
|
void Add(EquipSlot slot, uint glamourId, StainId glamourStain, ref RaptureGearsetModule.GearsetItem item)
|
||||||
|
{
|
||||||
|
if (item.ItemID == 0)
|
||||||
|
_itemList.Add((slot, 0, 0));
|
||||||
|
else if (glamourId != 0)
|
||||||
|
_itemList.Add((slot, glamourId, glamourStain));
|
||||||
|
else if (item.GlamourId != 0)
|
||||||
|
_itemList.Add((slot, item.GlamourId, item.Stain));
|
||||||
|
else
|
||||||
|
_itemList.Add((slot, item.ItemID, item.Stain));
|
||||||
|
}
|
||||||
|
|
||||||
|
var plate = MirageManager.Instance()->GlamourPlatesSpan[glamourPlateId - 1];
|
||||||
|
Add(EquipSlot.MainHand, plate.ItemIds[0], plate.StainIds[0], ref entry->MainHand);
|
||||||
|
Add(EquipSlot.OffHand, plate.ItemIds[1], plate.StainIds[10], ref entry->OffHand);
|
||||||
|
Add(EquipSlot.Head, plate.ItemIds[2], plate.StainIds[2], ref entry->Head);
|
||||||
|
Add(EquipSlot.Body, plate.ItemIds[3], plate.StainIds[3], ref entry->Body);
|
||||||
|
Add(EquipSlot.Hands, plate.ItemIds[4], plate.StainIds[4], ref entry->Hands);
|
||||||
|
Add(EquipSlot.Legs, plate.ItemIds[5], plate.StainIds[5], ref entry->Legs);
|
||||||
|
Add(EquipSlot.Feet, plate.ItemIds[6], plate.StainIds[6], ref entry->Feet);
|
||||||
|
Add(EquipSlot.Ears, plate.ItemIds[7], plate.StainIds[7], ref entry->Ears);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
void Add(EquipSlot slot, ref RaptureGearsetModule.GearsetItem item)
|
||||||
|
{
|
||||||
|
if (item.ItemID == 0)
|
||||||
|
_itemList.Add((slot, 0, 0));
|
||||||
|
else if (item.GlamourId != 0)
|
||||||
|
_itemList.Add((slot, item.GlamourId, item.Stain));
|
||||||
|
else
|
||||||
|
_itemList.Add((slot, item.ItemID, item.Stain));
|
||||||
|
}
|
||||||
|
|
||||||
|
Add(EquipSlot.MainHand, ref entry->MainHand);
|
||||||
|
Add(EquipSlot.OffHand, ref entry->OffHand);
|
||||||
|
Add(EquipSlot.Head, ref entry->Head);
|
||||||
|
Add(EquipSlot.Body, ref entry->Body);
|
||||||
|
Add(EquipSlot.Hands, ref entry->Hands);
|
||||||
|
Add(EquipSlot.Legs, ref entry->Legs);
|
||||||
|
Add(EquipSlot.Feet, ref entry->Feet);
|
||||||
|
Add(EquipSlot.Ears, ref entry->Ears);
|
||||||
|
Add(EquipSlot.Neck, ref entry->Neck);
|
||||||
|
Add(EquipSlot.Wrists, ref entry->Wrists);
|
||||||
|
Add(EquipSlot.RFinger, ref entry->RingRight);
|
||||||
|
Add(EquipSlot.LFinger, ref entry->RightLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
_event.Invoke(_itemList.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private delegate int MoveItemDelegate(InventoryManager* manager, InventoryType sourceContainer, ushort sourceSlot,
|
||||||
|
InventoryType targetContainer, ushort targetSlot, byte unk);
|
||||||
|
|
||||||
|
private readonly Hook<MoveItemDelegate> _moveItemHook;
|
||||||
|
|
||||||
|
private int MoveItemDetour(InventoryManager* manager, InventoryType sourceContainer, ushort sourceSlot,
|
||||||
|
InventoryType targetContainer, ushort targetSlot, byte unk)
|
||||||
|
{
|
||||||
|
var ret = _moveItemHook.Original(manager, sourceContainer, sourceSlot, targetContainer, targetSlot, unk);
|
||||||
|
Glamourer.Log.Excessive($"[InventoryService] Moved {sourceContainer} {sourceSlot} {targetContainer} {targetSlot} (Returned {ret})");
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
if (InvokeSource(sourceContainer, sourceSlot, out var source))
|
||||||
|
if (InvokeTarget(manager, targetContainer, targetSlot, out var target))
|
||||||
|
_event.Invoke(new[]
|
||||||
|
{
|
||||||
|
source,
|
||||||
|
target,
|
||||||
|
});
|
||||||
|
else
|
||||||
|
_event.Invoke(new[]
|
||||||
|
{
|
||||||
|
source,
|
||||||
|
});
|
||||||
|
else if (InvokeTarget(manager, targetContainer, targetSlot, out var target))
|
||||||
|
_event.Invoke(new[]
|
||||||
|
{
|
||||||
|
target,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool InvokeSource(InventoryType sourceContainer, uint sourceSlot, out (EquipSlot, uint, StainId) tuple)
|
||||||
|
{
|
||||||
|
tuple = default;
|
||||||
|
if (sourceContainer is not InventoryType.EquippedItems)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var slot = GetSlot(sourceSlot);
|
||||||
|
if (slot is EquipSlot.Unknown)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
tuple = (slot, 0u, 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool InvokeTarget(InventoryManager* manager, InventoryType targetContainer, uint targetSlot,
|
||||||
|
out (EquipSlot, uint, StainId) tuple)
|
||||||
|
{
|
||||||
|
tuple = default;
|
||||||
|
if (targetContainer is not InventoryType.EquippedItems)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var slot = GetSlot(targetSlot);
|
||||||
|
if (slot is EquipSlot.Unknown)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Invoked after calling Original, so the item is already moved.
|
||||||
|
var inventory = manager->GetInventoryContainer(targetContainer);
|
||||||
|
if (inventory == null || inventory->Loaded == 0 || inventory->Size <= targetSlot)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var item = inventory->GetInventorySlot((int)targetSlot);
|
||||||
|
if (item == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
tuple = (slot, item->GlamourID != 0 ? item->GlamourID : item->ItemID, item->Stain);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static EquipSlot GetSlot(uint slot)
|
||||||
|
=> slot switch
|
||||||
|
{
|
||||||
|
0 => EquipSlot.MainHand,
|
||||||
|
1 => EquipSlot.OffHand,
|
||||||
|
2 => EquipSlot.Head,
|
||||||
|
3 => EquipSlot.Body,
|
||||||
|
4 => EquipSlot.Hands,
|
||||||
|
6 => EquipSlot.Legs,
|
||||||
|
7 => EquipSlot.Feet,
|
||||||
|
8 => EquipSlot.Ears,
|
||||||
|
9 => EquipSlot.Neck,
|
||||||
|
10 => EquipSlot.Wrists,
|
||||||
|
11 => EquipSlot.RFinger,
|
||||||
|
12 => EquipSlot.LFinger,
|
||||||
|
_ => EquipSlot.Unknown,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using Dalamud.Hooking;
|
using Dalamud.Hooking;
|
||||||
using Dalamud.Utility.Signatures;
|
using Dalamud.Utility.Signatures;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
using Glamourer.Interop.Structs;
|
using Glamourer.Interop.Structs;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
|
|
@ -11,24 +10,18 @@ namespace Glamourer.Interop;
|
||||||
|
|
||||||
public unsafe class UpdateSlotService : IDisposable
|
public unsafe class UpdateSlotService : IDisposable
|
||||||
{
|
{
|
||||||
public readonly SlotUpdating SlotUpdatingEvent;
|
public readonly SlotUpdating SlotUpdatingEvent;
|
||||||
public readonly EquipmentLoading EquipmentLoadingEvent;
|
|
||||||
|
|
||||||
public UpdateSlotService(SlotUpdating slotUpdating, EquipmentLoading equipmentLoadingEvent)
|
public UpdateSlotService(SlotUpdating slotUpdating)
|
||||||
{
|
{
|
||||||
SlotUpdatingEvent = slotUpdating;
|
SlotUpdatingEvent = slotUpdating;
|
||||||
EquipmentLoadingEvent = equipmentLoadingEvent;
|
|
||||||
SignatureHelper.Initialise(this);
|
SignatureHelper.Initialise(this);
|
||||||
_flagSlotForUpdateHook.Enable();
|
_flagSlotForUpdateHook.Enable();
|
||||||
_loadEquipmentHook =
|
|
||||||
Hook<LoadEquipmentDelegateIntern>.FromAddress((nint) DrawDataContainer.MemberFunctionPointers.LoadEquipment, LoadEquipmentDetour);
|
|
||||||
_loadEquipmentHook.Enable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_flagSlotForUpdateHook.Dispose();
|
_flagSlotForUpdateHook.Dispose();
|
||||||
_loadEquipmentHook.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateSlot(Model drawObject, EquipSlot slot, CharacterArmor data)
|
public void UpdateSlot(Model drawObject, EquipSlot slot, CharacterArmor data)
|
||||||
|
|
@ -53,10 +46,6 @@ public unsafe class UpdateSlotService : IDisposable
|
||||||
[Signature(Sigs.FlagSlotForUpdate, DetourName = nameof(FlagSlotForUpdateDetour))]
|
[Signature(Sigs.FlagSlotForUpdate, DetourName = nameof(FlagSlotForUpdateDetour))]
|
||||||
private readonly Hook<FlagSlotForUpdateDelegateIntern> _flagSlotForUpdateHook = null!;
|
private readonly Hook<FlagSlotForUpdateDelegateIntern> _flagSlotForUpdateHook = null!;
|
||||||
|
|
||||||
private delegate void LoadEquipmentDelegateIntern(DrawDataContainer* drawDataContainer, uint slotIdx, CharacterArmor data, bool force);
|
|
||||||
|
|
||||||
private readonly Hook<LoadEquipmentDelegateIntern> _loadEquipmentHook = null!;
|
|
||||||
|
|
||||||
private ulong FlagSlotForUpdateDetour(nint drawObject, uint slotIdx, CharacterArmor* data)
|
private ulong FlagSlotForUpdateDetour(nint drawObject, uint slotIdx, CharacterArmor* data)
|
||||||
{
|
{
|
||||||
var slot = slotIdx.ToEquipSlot();
|
var slot = slotIdx.ToEquipSlot();
|
||||||
|
|
@ -66,14 +55,6 @@ public unsafe class UpdateSlotService : IDisposable
|
||||||
return returnValue == ulong.MaxValue ? _flagSlotForUpdateHook.Original(drawObject, slotIdx, data) : returnValue;
|
return returnValue == ulong.MaxValue ? _flagSlotForUpdateHook.Original(drawObject, slotIdx, data) : returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadEquipmentDetour(DrawDataContainer* drawDataContainer, uint slotIdx, CharacterArmor data, bool force)
|
|
||||||
{
|
|
||||||
var slot = slotIdx.ToEquipSlot();
|
|
||||||
EquipmentLoadingEvent.Invoke(drawDataContainer->Parent, slot, data);
|
|
||||||
Glamourer.Log.Excessive($"[LoadEquipment] Called with 0x{(ulong)drawDataContainer:X} for slot {slot} with {data} ({force}).");
|
|
||||||
_loadEquipmentHook.Original(drawDataContainer, slotIdx, data, force);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ulong FlagSlotForUpdateInterop(Model drawObject, EquipSlot slot, CharacterArmor armor)
|
private ulong FlagSlotForUpdateInterop(Model drawObject, EquipSlot slot, CharacterArmor armor)
|
||||||
=> _flagSlotForUpdateHook.Original(drawObject.Address, slot.ToIndex(), &armor);
|
=> _flagSlotForUpdateHook.Original(drawObject.Address, slot.ToIndex(), &armor);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,8 @@ using Dalamud.Utility.Signatures;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
using Glamourer.Interop.Structs;
|
using Glamourer.Interop.Structs;
|
||||||
using ImGuiNET;
|
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
using static FFXIVClientStructs.FFXIV.Client.UI.UIModule;
|
|
||||||
|
|
||||||
namespace Glamourer.Interop;
|
namespace Glamourer.Interop;
|
||||||
|
|
||||||
|
|
@ -75,14 +73,14 @@ public unsafe class WeaponService : IDisposable
|
||||||
switch (slot)
|
switch (slot)
|
||||||
{
|
{
|
||||||
case EquipSlot.MainHand:
|
case EquipSlot.MainHand:
|
||||||
_loadWeaponHook.Original(&character.AsCharacter->DrawData, 0, weapon.Value, 0, 0, 1, 0);
|
_loadWeaponHook.Original(&character.AsCharacter->DrawData, 0, weapon.Value, 1, 0, 1, 0);
|
||||||
return;
|
return;
|
||||||
case EquipSlot.OffHand:
|
case EquipSlot.OffHand:
|
||||||
_loadWeaponHook.Original(&character.AsCharacter->DrawData, 1, weapon.Value, 0, 0, 1, 0);
|
_loadWeaponHook.Original(&character.AsCharacter->DrawData, 1, weapon.Value, 1, 0, 1, 0);
|
||||||
return;
|
return;
|
||||||
case EquipSlot.BothHand:
|
case EquipSlot.BothHand:
|
||||||
_loadWeaponHook.Original(&character.AsCharacter->DrawData, 0, weapon.Value, 0, 0, 1, 0);
|
_loadWeaponHook.Original(&character.AsCharacter->DrawData, 0, weapon.Value, 1, 0, 1, 0);
|
||||||
_loadWeaponHook.Original(&character.AsCharacter->DrawData, 1, CharacterWeapon.Empty.Value, 0, 0, 1, 0);
|
_loadWeaponHook.Original(&character.AsCharacter->DrawData, 1, CharacterWeapon.Empty.Value, 1, 0, 1, 0);
|
||||||
return;
|
return;
|
||||||
// function can also be called with '2', but does not seem to ever be.
|
// function can also be called with '2', but does not seem to ever be.
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ public class ItemManager : IDisposable
|
||||||
if (itemId == SmallclothesId(slot))
|
if (itemId == SmallclothesId(slot))
|
||||||
return SmallClothesItem(slot);
|
return SmallClothesItem(slot);
|
||||||
|
|
||||||
if (!ItemService.AwaitedService.TryGetValue(itemId, slot is not EquipSlot.OffHand, out var item))
|
if (!ItemService.AwaitedService.TryGetValue(itemId, slot, out var item))
|
||||||
return new EquipItem(string.Intern($"Unknown #{itemId}"), itemId, 0, 0, 0, 0, 0);
|
return new EquipItem(string.Intern($"Unknown #{itemId}"), itemId, 0, 0, 0, 0, 0);
|
||||||
|
|
||||||
if (item.Type.ToSlot() != slot)
|
if (item.Type.ToSlot() != slot)
|
||||||
|
|
@ -88,7 +88,7 @@ public class ItemManager : IDisposable
|
||||||
if (itemId == NothingId(type))
|
if (itemId == NothingId(type))
|
||||||
return NothingItem(type);
|
return NothingItem(type);
|
||||||
|
|
||||||
if (!ItemService.AwaitedService.TryGetValue(itemId, type is FullEquipType.Shield, out var item))
|
if (!ItemService.AwaitedService.TryGetValue(itemId, type is FullEquipType.Shield ? EquipSlot.MainHand : EquipSlot.OffHand, out var item))
|
||||||
return new EquipItem(string.Intern($"Unknown #{itemId}"), itemId, 0, 0, 0, 0, 0);
|
return new EquipItem(string.Intern($"Unknown #{itemId}"), itemId, 0, 0, 0, 0, 0);
|
||||||
|
|
||||||
if (item.Type != type)
|
if (item.Type != type)
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,6 @@ public static class ServiceManager
|
||||||
private static IServiceCollection AddEvents(this IServiceCollection services)
|
private static IServiceCollection AddEvents(this IServiceCollection services)
|
||||||
=> services.AddSingleton<VisorStateChanged>()
|
=> services.AddSingleton<VisorStateChanged>()
|
||||||
.AddSingleton<SlotUpdating>()
|
.AddSingleton<SlotUpdating>()
|
||||||
.AddSingleton<EquipmentLoading>()
|
|
||||||
.AddSingleton<DesignChanged>()
|
.AddSingleton<DesignChanged>()
|
||||||
.AddSingleton<AutomationChanged>()
|
.AddSingleton<AutomationChanged>()
|
||||||
.AddSingleton<StateChanged>()
|
.AddSingleton<StateChanged>()
|
||||||
|
|
@ -69,7 +68,8 @@ public static class ServiceManager
|
||||||
.AddSingleton<HeadGearVisibilityChanged>()
|
.AddSingleton<HeadGearVisibilityChanged>()
|
||||||
.AddSingleton<WeaponVisibilityChanged>()
|
.AddSingleton<WeaponVisibilityChanged>()
|
||||||
.AddSingleton<ObjectUnlocked>()
|
.AddSingleton<ObjectUnlocked>()
|
||||||
.AddSingleton<TabSelected>();
|
.AddSingleton<TabSelected>()
|
||||||
|
.AddSingleton<MovedEquipment>();
|
||||||
|
|
||||||
private static IServiceCollection AddData(this IServiceCollection services)
|
private static IServiceCollection AddData(this IServiceCollection services)
|
||||||
=> services.AddSingleton<IdentifierService>()
|
=> services.AddSingleton<IdentifierService>()
|
||||||
|
|
@ -91,7 +91,8 @@ public static class ServiceManager
|
||||||
.AddSingleton<JobService>()
|
.AddSingleton<JobService>()
|
||||||
.AddSingleton<CustomizeUnlockManager>()
|
.AddSingleton<CustomizeUnlockManager>()
|
||||||
.AddSingleton<ItemUnlockManager>()
|
.AddSingleton<ItemUnlockManager>()
|
||||||
.AddSingleton<DatFileService>();
|
.AddSingleton<DatFileService>()
|
||||||
|
.AddSingleton<InventoryService>();
|
||||||
|
|
||||||
private static IServiceCollection AddDesigns(this IServiceCollection services)
|
private static IServiceCollection AddDesigns(this IServiceCollection services)
|
||||||
=> services.AddSingleton<DesignManager>()
|
=> services.AddSingleton<DesignManager>()
|
||||||
|
|
|
||||||
|
|
@ -75,8 +75,8 @@ public abstract class AsyncServiceWrapper<T> : IDisposable
|
||||||
|
|
||||||
public sealed class IdentifierService : AsyncServiceWrapper<IObjectIdentifier>
|
public sealed class IdentifierService : AsyncServiceWrapper<IObjectIdentifier>
|
||||||
{
|
{
|
||||||
public IdentifierService(DalamudPluginInterface pi, DataManager data)
|
public IdentifierService(DalamudPluginInterface pi, DataManager data, ItemService itemService)
|
||||||
: base(nameof(IdentifierService), () => Penumbra.GameData.GameData.GetIdentifier(pi, data))
|
: base(nameof(IdentifierService), () => Penumbra.GameData.GameData.GetIdentifier(pi, data, itemService.AwaitedService))
|
||||||
{ }
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
using Glamourer.Automation;
|
using Glamourer.Automation;
|
||||||
using Glamourer.Customization;
|
using Glamourer.Customization;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
|
using Glamourer.Interop;
|
||||||
using Glamourer.Interop.Penumbra;
|
using Glamourer.Interop.Penumbra;
|
||||||
using Glamourer.Interop.Structs;
|
using Glamourer.Interop.Structs;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
|
|
@ -22,12 +23,12 @@ public class StateListener : IDisposable
|
||||||
{
|
{
|
||||||
private readonly Configuration _config;
|
private readonly Configuration _config;
|
||||||
private readonly ActorService _actors;
|
private readonly ActorService _actors;
|
||||||
|
private readonly ObjectManager _objects;
|
||||||
private readonly StateManager _manager;
|
private readonly StateManager _manager;
|
||||||
private readonly StateApplier _applier;
|
private readonly StateApplier _applier;
|
||||||
private readonly ItemManager _items;
|
private readonly ItemManager _items;
|
||||||
private readonly PenumbraService _penumbra;
|
private readonly PenumbraService _penumbra;
|
||||||
private readonly SlotUpdating _slotUpdating;
|
private readonly SlotUpdating _slotUpdating;
|
||||||
private readonly EquipmentLoading _equipmentLoading;
|
|
||||||
private readonly WeaponLoading _weaponLoading;
|
private readonly WeaponLoading _weaponLoading;
|
||||||
private readonly HeadGearVisibilityChanged _headGearVisibility;
|
private readonly HeadGearVisibilityChanged _headGearVisibility;
|
||||||
private readonly VisorStateChanged _visorState;
|
private readonly VisorStateChanged _visorState;
|
||||||
|
|
@ -35,9 +36,11 @@ public class StateListener : IDisposable
|
||||||
private readonly AutoDesignApplier _autoDesignApplier;
|
private readonly AutoDesignApplier _autoDesignApplier;
|
||||||
private readonly FunModule _funModule;
|
private readonly FunModule _funModule;
|
||||||
private readonly HumanModelList _humans;
|
private readonly HumanModelList _humans;
|
||||||
|
private readonly MovedEquipment _movedEquipment;
|
||||||
|
|
||||||
private ActorIdentifier _creatingIdentifier = ActorIdentifier.Invalid;
|
private ActorIdentifier _creatingIdentifier = ActorIdentifier.Invalid;
|
||||||
private ActorState? _creatingState = null;
|
private ActorState? _creatingState;
|
||||||
|
private CharacterWeapon _lastFistOffhand = CharacterWeapon.Empty;
|
||||||
|
|
||||||
public bool Enabled
|
public bool Enabled
|
||||||
{
|
{
|
||||||
|
|
@ -48,7 +51,7 @@ public class StateListener : IDisposable
|
||||||
public StateListener(StateManager manager, ItemManager items, PenumbraService penumbra, ActorService actors, Configuration config,
|
public StateListener(StateManager manager, ItemManager items, PenumbraService penumbra, ActorService actors, Configuration config,
|
||||||
SlotUpdating slotUpdating, WeaponLoading weaponLoading, VisorStateChanged visorState, WeaponVisibilityChanged weaponVisibility,
|
SlotUpdating slotUpdating, WeaponLoading weaponLoading, VisorStateChanged visorState, WeaponVisibilityChanged weaponVisibility,
|
||||||
HeadGearVisibilityChanged headGearVisibility, AutoDesignApplier autoDesignApplier, FunModule funModule, HumanModelList humans,
|
HeadGearVisibilityChanged headGearVisibility, AutoDesignApplier autoDesignApplier, FunModule funModule, HumanModelList humans,
|
||||||
EquipmentLoading equipmentLoading, StateApplier applier)
|
StateApplier applier, MovedEquipment movedEquipment, ObjectManager objects)
|
||||||
{
|
{
|
||||||
_manager = manager;
|
_manager = manager;
|
||||||
_items = items;
|
_items = items;
|
||||||
|
|
@ -63,8 +66,9 @@ public class StateListener : IDisposable
|
||||||
_autoDesignApplier = autoDesignApplier;
|
_autoDesignApplier = autoDesignApplier;
|
||||||
_funModule = funModule;
|
_funModule = funModule;
|
||||||
_humans = humans;
|
_humans = humans;
|
||||||
_equipmentLoading = equipmentLoading;
|
|
||||||
_applier = applier;
|
_applier = applier;
|
||||||
|
_movedEquipment = movedEquipment;
|
||||||
|
_objects = objects;
|
||||||
|
|
||||||
if (Enabled)
|
if (Enabled)
|
||||||
Subscribe();
|
Subscribe();
|
||||||
|
|
@ -168,40 +172,36 @@ public class StateListener : IDisposable
|
||||||
(_, armor.Value) = _items.RestrictedGear.ResolveRestricted(armor, slot, customize.Race, customize.Gender);
|
(_, armor.Value) = _items.RestrictedGear.ResolveRestricted(armor, slot, customize.Race, customize.Gender);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private void OnMovedEquipment((EquipSlot, uint, StainId)[] items)
|
||||||
/// The game object does not actually invoke changes when the model id is identical,
|
|
||||||
/// so we need to handle that case too.
|
|
||||||
/// </summary>
|
|
||||||
private void OnEquipmentLoading(Actor actor, EquipSlot slot, CharacterArmor armor)
|
|
||||||
{
|
{
|
||||||
if (!actor.Model.Valid || armor != actor.GetArmor(slot))
|
_objects.Update();
|
||||||
|
var (identifier, objects) = _objects.PlayerData;
|
||||||
|
if (!identifier.IsValid || !_manager.TryGetValue(identifier, out var state))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!actor.Identifier(_actors.AwaitedService, out var identifier)
|
foreach (var (slot, item, stain) in items)
|
||||||
|| !_manager.TryGetValue(identifier, out var state)
|
|
||||||
|| !state.BaseData.IsHuman)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (state.ModelData.Armor(slot) == armor)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var setItem = state[slot, false] is not StateChanged.Source.Fixed and not StateChanged.Source.Ipc;
|
|
||||||
var setStain = state[slot, true] is not StateChanged.Source.Fixed and not StateChanged.Source.Ipc;
|
|
||||||
switch (setItem, setStain)
|
|
||||||
{
|
{
|
||||||
case (true, true):
|
var currentItem = state.BaseData.Item(slot);
|
||||||
_manager.ChangeEquip(state, slot, state.BaseData.Item(slot), state.BaseData.Stain(slot), StateChanged.Source.Manual);
|
var model = state.ModelData.Weapon(slot);
|
||||||
state[slot, false] = StateChanged.Source.Game;
|
var current = currentItem.Weapon(state.BaseData.Stain(slot));
|
||||||
state[slot, true] = StateChanged.Source.Game;
|
if (model.Value == current.Value || !_items.ItemService.AwaitedService.TryGetValue(item, EquipSlot.MainHand, out var changedItem))
|
||||||
break;
|
continue;
|
||||||
case (true, false):
|
|
||||||
_manager.ChangeItem(state, slot, state.BaseData.Item(slot), StateChanged.Source.Manual);
|
var changed = changedItem.Weapon(stain);
|
||||||
state[slot, false] = StateChanged.Source.Game;
|
if (current.Value == changed.Value && state[slot, false] is not StateChanged.Source.Fixed and not StateChanged.Source.Ipc)
|
||||||
break;
|
{
|
||||||
case (false, true):
|
_manager.ChangeItem(state, slot, currentItem, StateChanged.Source.Game);
|
||||||
_manager.ChangeStain(state, slot, state.BaseData.Stain(slot), StateChanged.Source.Manual);
|
switch (slot)
|
||||||
state[slot, true] = StateChanged.Source.Game;
|
{
|
||||||
break;
|
case EquipSlot.MainHand:
|
||||||
|
case EquipSlot.OffHand:
|
||||||
|
_applier.ChangeWeapon(objects, slot, currentItem, stain);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_applier.ChangeArmor(objects, slot, current.ToArmor(), state.ModelData.IsHatVisible());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -212,6 +212,13 @@ public class StateListener : IDisposable
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnWeaponLoading(Actor actor, EquipSlot slot, Ref<CharacterWeapon> weapon)
|
private void OnWeaponLoading(Actor actor, EquipSlot slot, Ref<CharacterWeapon> weapon)
|
||||||
{
|
{
|
||||||
|
// Fist weapon gauntlet hack.
|
||||||
|
if (slot is EquipSlot.OffHand && weapon.Value.Variant == 0 && weapon.Value.Set.Value != 0 && _lastFistOffhand.Set.Value != 0)
|
||||||
|
{
|
||||||
|
weapon.Value = _lastFistOffhand;
|
||||||
|
_lastFistOffhand = CharacterWeapon.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
if (!actor.Identifier(_actors.AwaitedService, out var identifier)
|
if (!actor.Identifier(_actors.AwaitedService, out var identifier)
|
||||||
|| !_manager.TryGetValue(identifier, out var state))
|
|| !_manager.TryGetValue(identifier, out var state))
|
||||||
return;
|
return;
|
||||||
|
|
@ -229,7 +236,7 @@ public class StateListener : IDisposable
|
||||||
else
|
else
|
||||||
apply = true;
|
apply = true;
|
||||||
|
|
||||||
if (state[slot, false] is not StateChanged.Source.Fixed and not StateChanged.Source.Ipc)
|
if (state[slot, true] is not StateChanged.Source.Fixed and not StateChanged.Source.Ipc)
|
||||||
_manager.ChangeStain(state, slot, state.BaseData.Stain(slot), StateChanged.Source.Game);
|
_manager.ChangeStain(state, slot, state.BaseData.Stain(slot), StateChanged.Source.Game);
|
||||||
else
|
else
|
||||||
apply = true;
|
apply = true;
|
||||||
|
|
@ -249,6 +256,11 @@ public class StateListener : IDisposable
|
||||||
else if (actorWeapon.Set.Value != 0)
|
else if (actorWeapon.Set.Value != 0)
|
||||||
actorWeapon = actorWeapon.With(newWeapon.Stain);
|
actorWeapon = actorWeapon.With(newWeapon.Stain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fist Weapon Offhand hack.
|
||||||
|
if (slot is EquipSlot.MainHand && weapon.Value.Set.Value is > 1600 and < 1651)
|
||||||
|
_lastFistOffhand = new CharacterWeapon((SetId)(weapon.Value.Set.Value + 50), weapon.Value.Type, weapon.Value.Variant,
|
||||||
|
weapon.Value.Stain);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Update base data for a single changed equipment slot. </summary>
|
/// <summary> Update base data for a single changed equipment slot. </summary>
|
||||||
|
|
@ -257,7 +269,7 @@ public class StateListener : IDisposable
|
||||||
var actorArmor = actor.GetArmor(slot);
|
var actorArmor = actor.GetArmor(slot);
|
||||||
// The actor armor does not correspond to the model armor, thus the actor is transformed.
|
// The actor armor does not correspond to the model armor, thus the actor is transformed.
|
||||||
// This also prevents it from changing values due to hat state.
|
// This also prevents it from changing values due to hat state.
|
||||||
if (actorArmor.Value != armor.Value)
|
if (actorArmor.Value != armor.Value && armor.Set.Value != actor.GetOffhand().Set.Value)
|
||||||
return UpdateState.Transformed;
|
return UpdateState.Transformed;
|
||||||
|
|
||||||
var baseData = state.BaseData.Armor(slot);
|
var baseData = state.BaseData.Armor(slot);
|
||||||
|
|
@ -491,7 +503,7 @@ public class StateListener : IDisposable
|
||||||
_penumbra.CreatingCharacterBase += OnCreatingCharacterBase;
|
_penumbra.CreatingCharacterBase += OnCreatingCharacterBase;
|
||||||
_penumbra.CreatedCharacterBase += OnCreatedCharacterBase;
|
_penumbra.CreatedCharacterBase += OnCreatedCharacterBase;
|
||||||
_slotUpdating.Subscribe(OnSlotUpdating, SlotUpdating.Priority.StateListener);
|
_slotUpdating.Subscribe(OnSlotUpdating, SlotUpdating.Priority.StateListener);
|
||||||
_equipmentLoading.Subscribe(OnEquipmentLoading, EquipmentLoading.Priority.StateListener);
|
_movedEquipment.Subscribe(OnMovedEquipment, MovedEquipment.Priority.StateListener);
|
||||||
_weaponLoading.Subscribe(OnWeaponLoading, WeaponLoading.Priority.StateListener);
|
_weaponLoading.Subscribe(OnWeaponLoading, WeaponLoading.Priority.StateListener);
|
||||||
_visorState.Subscribe(OnVisorChange, VisorStateChanged.Priority.StateListener);
|
_visorState.Subscribe(OnVisorChange, VisorStateChanged.Priority.StateListener);
|
||||||
_headGearVisibility.Subscribe(OnHeadGearVisibilityChange, HeadGearVisibilityChanged.Priority.StateListener);
|
_headGearVisibility.Subscribe(OnHeadGearVisibilityChange, HeadGearVisibilityChanged.Priority.StateListener);
|
||||||
|
|
@ -503,7 +515,7 @@ public class StateListener : IDisposable
|
||||||
_penumbra.CreatingCharacterBase -= OnCreatingCharacterBase;
|
_penumbra.CreatingCharacterBase -= OnCreatingCharacterBase;
|
||||||
_penumbra.CreatedCharacterBase -= OnCreatedCharacterBase;
|
_penumbra.CreatedCharacterBase -= OnCreatedCharacterBase;
|
||||||
_slotUpdating.Unsubscribe(OnSlotUpdating);
|
_slotUpdating.Unsubscribe(OnSlotUpdating);
|
||||||
_equipmentLoading.Unsubscribe(OnEquipmentLoading);
|
_movedEquipment.Unsubscribe(OnMovedEquipment);
|
||||||
_weaponLoading.Unsubscribe(OnWeaponLoading);
|
_weaponLoading.Unsubscribe(OnWeaponLoading);
|
||||||
_visorState.Unsubscribe(OnVisorChange);
|
_visorState.Unsubscribe(OnVisorChange);
|
||||||
_headGearVisibility.Unsubscribe(OnHeadGearVisibilityChange);
|
_headGearVisibility.Unsubscribe(OnHeadGearVisibilityChange);
|
||||||
|
|
@ -515,7 +527,7 @@ public class StateListener : IDisposable
|
||||||
if (_creatingState == null)
|
if (_creatingState == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_applier.ChangeHatState(new ActorData(gameObject, _creatingIdentifier.ToName()), _creatingState.ModelData.IsHatVisible());
|
_applier.ChangeHatState(new ActorData(gameObject, _creatingIdentifier.ToName()), _creatingState.ModelData.IsHatVisible());
|
||||||
_applier.ChangeWeaponState(new ActorData(gameObject, _creatingIdentifier.ToName()), _creatingState.ModelData.IsWeaponVisible());
|
_applier.ChangeWeaponState(new ActorData(gameObject, _creatingIdentifier.ToName()), _creatingState.ModelData.IsWeaponVisible());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -169,6 +169,7 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
||||||
|
|
||||||
main = actor.GetMainhand();
|
main = actor.GetMainhand();
|
||||||
off = actor.GetOffhand();
|
off = actor.GetOffhand();
|
||||||
|
FistWeaponHack(ref ret, ref main, ref off);
|
||||||
ret.SetVisor(actor.AsCharacter->DrawData.IsVisorToggled);
|
ret.SetVisor(actor.AsCharacter->DrawData.IsVisorToggled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -190,6 +191,19 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> This is hardcoded in the game. </summary>
|
||||||
|
private void FistWeaponHack(ref DesignData ret, ref CharacterWeapon mainhand, ref CharacterWeapon offhand)
|
||||||
|
{
|
||||||
|
if (mainhand.Set.Value is < 1601 or >= 1651)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var gauntlets = _items.Identify(EquipSlot.Hands, offhand.Set, 0, (byte)offhand.Variant);
|
||||||
|
offhand.Set = (SetId)(mainhand.Set.Value + 50);
|
||||||
|
offhand.Variant = mainhand.Variant;
|
||||||
|
offhand.Type = mainhand.Type;
|
||||||
|
ret.SetItem(EquipSlot.Hands, gauntlets);
|
||||||
|
}
|
||||||
|
|
||||||
#region Change Values
|
#region Change Values
|
||||||
|
|
||||||
/// <summary> Turn an actor human. </summary>
|
/// <summary> Turn an actor human. </summary>
|
||||||
|
|
@ -433,7 +447,8 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
||||||
if (!GetOrCreate(actor, out var state))
|
if (!GetOrCreate(actor, out var state))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ApplyAll(state, !actor.Model.IsHuman || Customize.Compare(actor.Model.GetCustomize(), state.ModelData.Customize).RequiresRedraw(), false);
|
ApplyAll(state, !actor.Model.IsHuman || Customize.Compare(actor.Model.GetCustomize(), state.ModelData.Customize).RequiresRedraw(),
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteState(ActorIdentifier identifier)
|
public void DeleteState(ActorIdentifier identifier)
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ public class ItemUnlockManager : ISavable, IDisposable
|
||||||
private bool AddItem(uint itemId, long time)
|
private bool AddItem(uint itemId, long time)
|
||||||
{
|
{
|
||||||
itemId = HandleHq(itemId);
|
itemId = HandleHq(itemId);
|
||||||
if (!_items.ItemService.AwaitedService.TryGetValue(itemId, out var equip) || !_unlocked.TryAdd(equip.ItemId, time))
|
if (!_items.ItemService.AwaitedService.TryGetValue(itemId, EquipSlot.MainHand, out var equip) || !_unlocked.TryAdd(equip.ItemId, time))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_event.Invoke(ObjectUnlocked.Type.Item, equip.ItemId, DateTimeOffset.FromUnixTimeMilliseconds(time));
|
_event.Invoke(ObjectUnlocked.Type.Item, equip.ItemId, DateTimeOffset.FromUnixTimeMilliseconds(time));
|
||||||
|
|
@ -278,7 +278,7 @@ public class ItemUnlockManager : ISavable, IDisposable
|
||||||
private void Load()
|
private void Load()
|
||||||
{
|
{
|
||||||
var version = UnlockDictionaryHelpers.Load(ToFilename(_saveService.FileNames), _unlocked,
|
var version = UnlockDictionaryHelpers.Load(ToFilename(_saveService.FileNames), _unlocked,
|
||||||
id => _items.ItemService.AwaitedService.TryGetValue(id, out _), "item");
|
id => _items.ItemService.AwaitedService.TryGetValue(id, EquipSlot.MainHand, out _), "item");
|
||||||
UpdateModels(version);
|
UpdateModels(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -291,7 +291,7 @@ public class ItemUnlockManager : ISavable, IDisposable
|
||||||
var cabinet = gameData.GetExcelSheet<Cabinet>()!;
|
var cabinet = gameData.GetExcelSheet<Cabinet>()!;
|
||||||
foreach (var row in cabinet)
|
foreach (var row in cabinet)
|
||||||
{
|
{
|
||||||
if (items.ItemService.AwaitedService.TryGetValue(row.Item.Row, out var item))
|
if (items.ItemService.AwaitedService.TryGetValue(row.Item.Row, EquipSlot.MainHand, out var item))
|
||||||
ret.TryAdd(item.ItemId, new UnlockRequirements(row.RowId, 0, 0, 0, UnlockType.Cabinet));
|
ret.TryAdd(item.ItemId, new UnlockRequirements(row.RowId, 0, 0, 0, UnlockType.Cabinet));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -299,7 +299,7 @@ public class ItemUnlockManager : ISavable, IDisposable
|
||||||
var gilShop = gameData.GetExcelSheet<GilShop>()!;
|
var gilShop = gameData.GetExcelSheet<GilShop>()!;
|
||||||
foreach (var row in gilShopItem)
|
foreach (var row in gilShopItem)
|
||||||
{
|
{
|
||||||
if (!items.ItemService.AwaitedService.TryGetValue(row.Item.Row, out var item))
|
if (!items.ItemService.AwaitedService.TryGetValue(row.Item.Row, EquipSlot.MainHand, out var item))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var quest1 = row.QuestRequired[0].Row;
|
var quest1 = row.QuestRequired[0].Row;
|
||||||
|
|
@ -332,7 +332,7 @@ public class ItemUnlockManager : ISavable, IDisposable
|
||||||
|
|
||||||
foreach (var (item, time) in _unlocked.ToArray())
|
foreach (var (item, time) in _unlocked.ToArray())
|
||||||
{
|
{
|
||||||
if (!_items.ItemService.AwaitedService.TryGetValue(item, out var equip))
|
if (!_items.ItemService.AwaitedService.TryGetValue(item, EquipSlot.MainHand, out var equip))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var ident = _identifier.AwaitedService.Identify(equip.ModelId, equip.WeaponType, equip.Variant, equip.Type.ToSlot());
|
var ident = _identifier.AwaitedService.Identify(equip.ModelId, equip.WeaponType, equip.Variant, equip.Type.ToSlot());
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue