mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 18:27:24 +01:00
Use more specific ID types in most places, fix issues with actor identifiers.
This commit is contained in:
parent
c7f9d3a3c0
commit
a0456e7ae7
26 changed files with 184 additions and 170 deletions
|
|
@ -513,10 +513,11 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
|
|||
{
|
||||
ObjectKind.BattleNpc => manager.Data.BNpcs,
|
||||
ObjectKind.EventNpc => manager.Data.ENpcs,
|
||||
_ => throw new NotImplementedException(),
|
||||
_ => new Dictionary<uint, string>(),
|
||||
};
|
||||
return table.Where(kvp => kvp.Value == name)
|
||||
.Select(kvp => manager.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, identifier.HomeWorld, identifier.Kind,
|
||||
.Select(kvp => manager.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, identifier.HomeWorld.Id,
|
||||
identifier.Kind,
|
||||
kvp.Key)).ToArray();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -168,11 +168,11 @@ public class DesignBase
|
|||
|
||||
protected JObject SerializeEquipment()
|
||||
{
|
||||
static JObject Serialize(ulong id, StainId stain, bool apply, bool applyStain)
|
||||
static JObject Serialize(CustomItemId id, StainId stain, bool apply, bool applyStain)
|
||||
=> new()
|
||||
{
|
||||
["ItemId"] = id,
|
||||
["Stain"] = stain.Value,
|
||||
["ItemId"] = id.Id,
|
||||
["Stain"] = stain.Id,
|
||||
["Apply"] = apply,
|
||||
["ApplyStain"] = applyStain,
|
||||
};
|
||||
|
|
@ -267,9 +267,9 @@ public class DesignBase
|
|||
return;
|
||||
}
|
||||
|
||||
static (ulong, StainId, bool, bool) ParseItem(EquipSlot slot, JToken? item)
|
||||
static (CustomItemId, StainId, bool, bool) ParseItem(EquipSlot slot, JToken? item)
|
||||
{
|
||||
var id = item?["ItemId"]?.ToObject<ulong>() ?? ItemManager.NothingId(slot);
|
||||
var id = item?["ItemId"]?.ToObject<ulong>() ?? ItemManager.NothingId(slot).Id;
|
||||
var stain = (StainId)(item?["Stain"]?.ToObject<byte>() ?? 0);
|
||||
var apply = item?["Apply"]?.ToObject<bool>() ?? false;
|
||||
var applyStain = item?["ApplyStain"]?.ToObject<bool>() ?? false;
|
||||
|
|
@ -302,7 +302,7 @@ public class DesignBase
|
|||
if (id == ItemManager.NothingId(EquipSlot.OffHand))
|
||||
id = ItemManager.NothingId(FullEquipType.Shield);
|
||||
|
||||
PrintWarning(items.ValidateWeapons((uint)id, (uint)idOff, out var main, out var off));
|
||||
PrintWarning(items.ValidateWeapons(id.Item, idOff.Item, out var main, out var off));
|
||||
PrintWarning(items.ValidateStain(stain, out stain, allowUnknown));
|
||||
PrintWarning(items.ValidateStain(stainOff, out stainOff, allowUnknown));
|
||||
design.DesignData.SetItem(EquipSlot.MainHand, main);
|
||||
|
|
|
|||
|
|
@ -113,42 +113,42 @@ public class DesignBase64Migration
|
|||
var mdl = eq[idx];
|
||||
var item = items.Identify(slot, mdl.Set, mdl.Variant);
|
||||
if (!item.Valid)
|
||||
throw new Exception($"Base64 string invalid, item could not be identified.");
|
||||
throw new Exception("Base64 string invalid, item could not be identified.");
|
||||
|
||||
data.SetItem(slot, item);
|
||||
data.SetStain(slot, mdl.Stain);
|
||||
}
|
||||
|
||||
var main = cur[0].Set.Value == 0
|
||||
var main = cur[0].Set.Id == 0
|
||||
? items.DefaultSword
|
||||
: items.Identify(EquipSlot.MainHand, cur[0].Set, cur[0].Type, (byte)cur[0].Variant);
|
||||
: items.Identify(EquipSlot.MainHand, cur[0].Set, cur[0].Type, cur[0].Variant);
|
||||
if (!main.Valid)
|
||||
throw new Exception($"Base64 string invalid, weapon could not be identified.");
|
||||
throw new Exception("Base64 string invalid, weapon could not be identified.");
|
||||
|
||||
data.SetItem(EquipSlot.MainHand, main);
|
||||
data.SetStain(EquipSlot.MainHand, cur[0].Stain);
|
||||
|
||||
EquipItem off;
|
||||
// Fist weapon hack
|
||||
if (main.ModelId.Value is > 1600 and < 1651 && cur[1].Variant == 0)
|
||||
if (main.ModelId.Id is > 1600 and < 1651 && cur[1].Variant == 0)
|
||||
{
|
||||
off = items.Identify(EquipSlot.OffHand, (SetId)(main.ModelId.Value + 50), main.WeaponType, main.Variant, main.Type);
|
||||
var gauntlet = items.Identify(EquipSlot.Hands, cur[1].Set, (byte)cur[1].Type);
|
||||
off = items.Identify(EquipSlot.OffHand, (SetId)(main.ModelId.Id + 50), main.WeaponType, main.Variant, main.Type);
|
||||
var gauntlet = items.Identify(EquipSlot.Hands, cur[1].Set, (Variant)cur[1].Type.Id);
|
||||
if (!gauntlet.Valid)
|
||||
throw new Exception($"Base64 string invalid, item could not be identified.");
|
||||
throw new Exception("Base64 string invalid, item could not be identified.");
|
||||
|
||||
data.SetItem(EquipSlot.Hands, gauntlet);
|
||||
data.SetStain(EquipSlot.Hands, cur[0].Stain);
|
||||
}
|
||||
else
|
||||
{
|
||||
off = cur[0].Set.Value == 0
|
||||
off = cur[0].Set.Id == 0
|
||||
? ItemManager.NothingItem(FullEquipType.Shield)
|
||||
: items.Identify(EquipSlot.OffHand, cur[1].Set, cur[1].Type, (byte)cur[1].Variant, main.Type);
|
||||
: items.Identify(EquipSlot.OffHand, cur[1].Set, cur[1].Type, cur[1].Variant, main.Type);
|
||||
}
|
||||
|
||||
if (main.Type.ValidOffhand() != FullEquipType.Unknown && !off.Valid)
|
||||
throw new Exception($"Base64 string invalid, weapon could not be identified.");
|
||||
throw new Exception("Base64 string invalid, weapon could not be identified.");
|
||||
|
||||
data.SetItem(EquipSlot.OffHand, off);
|
||||
data.SetStain(EquipSlot.OffHand, cur[1].Stain);
|
||||
|
|
|
|||
|
|
@ -95,11 +95,11 @@ public unsafe struct DesignData
|
|||
if (index > 11)
|
||||
return false;
|
||||
|
||||
_itemIds[index] = item.ItemId;
|
||||
_iconIds[index] = item.IconId;
|
||||
_equipmentBytes[4 * index + 0] = (byte)item.ModelId;
|
||||
_equipmentBytes[4 * index + 1] = (byte)(item.ModelId.Value >> 8);
|
||||
_equipmentBytes[4 * index + 2] = item.Variant;
|
||||
_itemIds[index] = item.ItemId.Id;
|
||||
_iconIds[index] = item.IconId.Id;
|
||||
_equipmentBytes[4 * index + 0] = (byte)item.ModelId.Id;
|
||||
_equipmentBytes[4 * index + 1] = (byte)(item.ModelId.Id >> 8);
|
||||
_equipmentBytes[4 * index + 2] = item.Variant.Id;
|
||||
switch (index)
|
||||
{
|
||||
// @formatter:off
|
||||
|
|
@ -132,18 +132,18 @@ public unsafe struct DesignData
|
|||
public bool SetStain(EquipSlot slot, StainId stain)
|
||||
=> slot.ToIndex() switch
|
||||
{
|
||||
0 => SetIfDifferent(ref _equipmentBytes[3], stain.Value),
|
||||
1 => SetIfDifferent(ref _equipmentBytes[7], stain.Value),
|
||||
2 => SetIfDifferent(ref _equipmentBytes[11], stain.Value),
|
||||
3 => SetIfDifferent(ref _equipmentBytes[15], stain.Value),
|
||||
4 => SetIfDifferent(ref _equipmentBytes[19], stain.Value),
|
||||
5 => SetIfDifferent(ref _equipmentBytes[23], stain.Value),
|
||||
6 => SetIfDifferent(ref _equipmentBytes[27], stain.Value),
|
||||
7 => SetIfDifferent(ref _equipmentBytes[31], stain.Value),
|
||||
8 => SetIfDifferent(ref _equipmentBytes[35], stain.Value),
|
||||
9 => SetIfDifferent(ref _equipmentBytes[39], stain.Value),
|
||||
10 => SetIfDifferent(ref _equipmentBytes[43], stain.Value),
|
||||
11 => SetIfDifferent(ref _equipmentBytes[47], stain.Value),
|
||||
0 => SetIfDifferent(ref _equipmentBytes[3], stain.Id),
|
||||
1 => SetIfDifferent(ref _equipmentBytes[7], stain.Id),
|
||||
2 => SetIfDifferent(ref _equipmentBytes[11], stain.Id),
|
||||
3 => SetIfDifferent(ref _equipmentBytes[15], stain.Id),
|
||||
4 => SetIfDifferent(ref _equipmentBytes[19], stain.Id),
|
||||
5 => SetIfDifferent(ref _equipmentBytes[23], stain.Id),
|
||||
6 => SetIfDifferent(ref _equipmentBytes[27], stain.Id),
|
||||
7 => SetIfDifferent(ref _equipmentBytes[31], stain.Id),
|
||||
8 => SetIfDifferent(ref _equipmentBytes[35], stain.Id),
|
||||
9 => SetIfDifferent(ref _equipmentBytes[39], stain.Id),
|
||||
10 => SetIfDifferent(ref _equipmentBytes[43], stain.Id),
|
||||
11 => SetIfDifferent(ref _equipmentBytes[47], stain.Id),
|
||||
_ => false,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -398,7 +398,7 @@ public class DesignManager
|
|||
|
||||
design.LastEdit = DateTimeOffset.UtcNow;
|
||||
_saveService.QueueSave(design);
|
||||
Glamourer.Log.Debug($"Set stain of {slot} equipment piece to {stain.Value}.");
|
||||
Glamourer.Log.Debug($"Set stain of {slot} equipment piece to {stain.Id}.");
|
||||
_event.Invoke(DesignChanged.Type.Stain, design, (oldStain, stain, slot));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ public class EquipmentDrawer
|
|||
_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, textures)).ToArray();
|
||||
_itemCombo = EquipSlotExtensions.EqdpSlots.Select(e => new ItemCombo(gameData, items, e)).ToArray();
|
||||
_weaponCombo = new Dictionary<FullEquipType, WeaponCombo>(FullEquipTypeExtensions.WeaponTypes.Count * 2);
|
||||
foreach (var type in Enum.GetValues<FullEquipType>())
|
||||
{
|
||||
|
|
@ -118,7 +118,7 @@ public class EquipmentDrawer
|
|||
bool allWeapons,
|
||||
out bool rApplyMainhand, out bool rApplyMainhandStain, out bool rApplyOffhand, out bool rApplyOffhandStain, bool locked)
|
||||
{
|
||||
if (cMainhand.ModelId.Value == 0)
|
||||
if (cMainhand.ModelId.Id == 0)
|
||||
{
|
||||
rOffhand = cOffhand;
|
||||
rMainhand = cMainhand;
|
||||
|
|
@ -239,7 +239,7 @@ public class EquipmentDrawer
|
|||
if (change)
|
||||
armor = combo.CurrentSelection;
|
||||
|
||||
if (!locked && armor.ModelId.Value != 0)
|
||||
if (!locked && armor.ModelId.Id != 0)
|
||||
{
|
||||
ImGuiUtil.HoverTooltip("Right-click to clear.");
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
|
|
@ -282,15 +282,15 @@ public class EquipmentDrawer
|
|||
/// <summary> Draw an input for armor that can set arbitrary values instead of choosing items. </summary>
|
||||
private bool DrawArmorArtisan(EquipSlot slot, EquipItem current, out EquipItem armor)
|
||||
{
|
||||
int setId = current.ModelId.Value;
|
||||
int variant = current.Variant;
|
||||
int setId = current.ModelId.Id;
|
||||
int variant = current.Variant.Id;
|
||||
var ret = false;
|
||||
armor = current;
|
||||
ImGui.SetNextItemWidth(80 * ImGuiHelpers.GlobalScale);
|
||||
if (ImGui.InputInt("##setId", ref setId, 0, 0))
|
||||
{
|
||||
var newSetId = (SetId)Math.Clamp(setId, 0, ushort.MaxValue);
|
||||
if (newSetId.Value != current.ModelId.Value)
|
||||
if (newSetId.Id != current.ModelId.Id)
|
||||
{
|
||||
armor = _items.Identify(slot, newSetId, current.Variant);
|
||||
ret = true;
|
||||
|
|
@ -315,7 +315,7 @@ public class EquipmentDrawer
|
|||
/// <summary> Draw an input for stain that can set arbitrary values instead of choosing valid stains. </summary>
|
||||
private bool DrawStainArtisan(EquipSlot slot, StainId current, out StainId stain)
|
||||
{
|
||||
int stainId = current.Value;
|
||||
int stainId = current.Id;
|
||||
ImGui.SetNextItemWidth(40 * ImGuiHelpers.GlobalScale);
|
||||
if (ImGui.InputInt("##stain", ref stainId, 0, 0))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,16 +15,13 @@ namespace Glamourer.Gui.Equipment;
|
|||
|
||||
public sealed class ItemCombo : FilterComboCache<EquipItem>
|
||||
{
|
||||
private readonly TextureService _textures;
|
||||
|
||||
public readonly string Label;
|
||||
private uint _currentItem;
|
||||
private ItemId _currentItem;
|
||||
private float _innerWidth;
|
||||
|
||||
public ItemCombo(DataManager gameData, ItemManager items, EquipSlot slot, TextureService textures)
|
||||
public ItemCombo(DataManager gameData, ItemManager items, EquipSlot slot)
|
||||
: base(() => GetItems(items, slot))
|
||||
{
|
||||
_textures = textures;
|
||||
Label = GetLabel(gameData, slot);
|
||||
_currentItem = ItemManager.NothingId(slot);
|
||||
SearchByParts = true;
|
||||
|
|
@ -47,7 +44,7 @@ public sealed class ItemCombo : FilterComboCache<EquipItem>
|
|||
return base.UpdateCurrentSelected(CurrentSelectionIdx);
|
||||
}
|
||||
|
||||
public bool Draw(string previewName, uint previewIdx, float width, float innerWidth)
|
||||
public bool Draw(string previewName, ItemId previewIdx, float width, float innerWidth)
|
||||
{
|
||||
_innerWidth = innerWidth;
|
||||
_currentItem = previewIdx;
|
||||
|
|
@ -64,12 +61,12 @@ public sealed class ItemCombo : FilterComboCache<EquipItem>
|
|||
var ret = ImGui.Selectable(name, selected);
|
||||
ImGui.SameLine();
|
||||
using var color = ImRaii.PushColor(ImGuiCol.Text, 0xFF808080);
|
||||
ImGuiUtil.RightAlign($"({obj.ModelId.Value}-{obj.Variant})");
|
||||
ImGuiUtil.RightAlign($"({obj.ModelString})");
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected override bool IsVisible(int globalIndex, LowerString filter)
|
||||
=> base.IsVisible(globalIndex, filter) || filter.IsContained(Items[globalIndex].ModelId.Value.ToString());
|
||||
=> base.IsVisible(globalIndex, filter) || filter.IsContained(Items[globalIndex].ModelId.Id.ToString());
|
||||
|
||||
protected override string ToString(EquipItem obj)
|
||||
=> obj.Name;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ namespace Glamourer.Gui.Equipment;
|
|||
public sealed class WeaponCombo : FilterComboCache<EquipItem>
|
||||
{
|
||||
public readonly string Label;
|
||||
private uint _currentItemId;
|
||||
private ItemId _currentItemId;
|
||||
private float _innerWidth;
|
||||
|
||||
public WeaponCombo(ItemManager items, FullEquipType type)
|
||||
|
|
@ -45,7 +45,7 @@ public sealed class WeaponCombo : FilterComboCache<EquipItem>
|
|||
protected override float GetFilterWidth()
|
||||
=> _innerWidth - 2 * ImGui.GetStyle().FramePadding.X;
|
||||
|
||||
public bool Draw(string previewName, uint previewId, float width, float innerWidth)
|
||||
public bool Draw(string previewName, ItemId previewId, float width, float innerWidth)
|
||||
{
|
||||
_currentItemId = previewId;
|
||||
_innerWidth = innerWidth;
|
||||
|
|
@ -59,12 +59,12 @@ public sealed class WeaponCombo : FilterComboCache<EquipItem>
|
|||
var ret = ImGui.Selectable(name, selected);
|
||||
ImGui.SameLine();
|
||||
using var color = ImRaii.PushColor(ImGuiCol.Text, 0xFF808080);
|
||||
ImGuiUtil.RightAlign($"({obj.ModelId.Value}-{obj.WeaponType.Value}-{obj.Variant})");
|
||||
ImGuiUtil.RightAlign($"({obj.ModelId.Id}-{obj.WeaponType.Id}-{obj.Variant})");
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected override bool IsVisible(int globalIndex, LowerString filter)
|
||||
=> base.IsVisible(globalIndex, filter) || filter.IsContained(Items[globalIndex].ModelId.Value.ToString());
|
||||
=> base.IsVisible(globalIndex, filter) || filter.IsContained(Items[globalIndex].ModelId.Id.ToString());
|
||||
|
||||
protected override string ToString(EquipItem obj)
|
||||
=> obj.Name;
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ public class PenumbraChangedItemTooltip : IDisposable
|
|||
private bool CanApplyWeapon(EquipSlot slot, EquipItem item)
|
||||
{
|
||||
var main = _objects.Player.GetMainhand();
|
||||
var mainItem = _items.Identify(slot, main.Set, main.Type, (byte)main.Variant);
|
||||
var mainItem = _items.Identify(slot, main.Set, main.Type, main.Variant);
|
||||
if (slot == EquipSlot.MainHand)
|
||||
return item.Type == mainItem.Type;
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ public sealed class HumanNpcCombo : FilterComboCache<(string Name, ObjectKind Ki
|
|||
{
|
||||
case ObjectKind.BattleNpc:
|
||||
var nameIds = service.AwaitedService.GetBnpcNames(id);
|
||||
ret.AddRange(nameIds.Select(nameId => (name, kind, nameId)));
|
||||
ret.AddRange(nameIds.Select(nameId => (service.AwaitedService.Name(ObjectKind.BattleNpc, nameId), kind, nameId.Id)));
|
||||
break;
|
||||
case ObjectKind.EventNpc:
|
||||
ret.Add((name, kind, id));
|
||||
|
|
@ -87,8 +87,10 @@ public sealed class HumanNpcCombo : FilterComboCache<(string Name, ObjectKind Ki
|
|||
}
|
||||
}
|
||||
|
||||
return ret.GroupBy(t => (t.Name, t.Kind)).OrderBy(g => g.Key, Comparer)
|
||||
.Select(g => (g.Key.Name, g.Key.Kind, g.Select(g => g.Id).ToArray())).ToList();
|
||||
return ret.GroupBy(t => (t.Name, t.Kind))
|
||||
.OrderBy(g => g.Key, Comparer)
|
||||
.Select(g => (g.Key.Name, g.Key.Kind, g.Select(g => g.Id).Distinct().ToArray()))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private static readonly NameComparer Comparer = new();
|
||||
|
|
|
|||
|
|
@ -640,16 +640,17 @@ public unsafe class DebugTab : ITab
|
|||
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||
{
|
||||
var identified = _items.Identify(slot, (SetId)_setId, (byte)_variant);
|
||||
var identified = _items.Identify(slot, (SetId)_setId, (Variant)_variant);
|
||||
Text(identified.Name);
|
||||
ImGuiUtil.HoverTooltip(string.Join("\n",
|
||||
_items.IdentifierService.AwaitedService.Identify((SetId)_setId, (ushort)_variant, slot).Select(i => $"{i.Name} {i.Id} {i.ItemId} {i.IconId}")));
|
||||
_items.IdentifierService.AwaitedService.Identify((SetId)_setId, (Variant)_variant, slot)
|
||||
.Select(i => $"{i.Name} {i.Id} {i.ItemId} {i.IconId}")));
|
||||
}
|
||||
|
||||
var weapon = _items.Identify(EquipSlot.MainHand, (SetId)_setId, (WeaponType)_secondaryId, (byte)_variant);
|
||||
var weapon = _items.Identify(EquipSlot.MainHand, (SetId)_setId, (WeaponType)_secondaryId, (Variant)_variant);
|
||||
Text(weapon.Name);
|
||||
ImGuiUtil.HoverTooltip(string.Join("\n",
|
||||
_items.IdentifierService.AwaitedService.Identify((SetId)_setId, (WeaponType)_secondaryId, (ushort)_variant, EquipSlot.MainHand)));
|
||||
_items.IdentifierService.AwaitedService.Identify((SetId)_setId, (WeaponType)_secondaryId, (Variant)_variant, EquipSlot.MainHand)));
|
||||
}
|
||||
|
||||
private void DrawRestrictedGear()
|
||||
|
|
@ -672,7 +673,7 @@ public unsafe class DebugTab : ITab
|
|||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||
{
|
||||
var (replaced, model) =
|
||||
_items.RestrictedGear.ResolveRestricted(new CharacterArmor((SetId)_setId, (byte)_variant, 0), slot, race, gender);
|
||||
_items.RestrictedGear.ResolveRestricted(new CharacterArmor((SetId)_setId, (Variant)_variant, 0), slot, race, gender);
|
||||
if (replaced)
|
||||
ImGui.TextUnformatted($"{race.ToName()} - {gender} - {slot.ToName()} resolves to {model}.");
|
||||
}
|
||||
|
|
@ -765,18 +766,18 @@ public unsafe class DebugTab : ITab
|
|||
ImRaii.TreeNode($"Default Sword: {_items.DefaultSword.Name} ({_items.DefaultSword.ItemId}) ({_items.DefaultSword.Weapon()})",
|
||||
ImGuiTreeNodeFlags.Leaf).Dispose();
|
||||
DrawNameTable("All Items (Main)", ref _itemFilter,
|
||||
_items.ItemService.AwaitedService.AllItems(true).Select(p => (p.Item1,
|
||||
_items.ItemService.AwaitedService.AllItems(true).Select(p => (p.Item1.Id,
|
||||
$"{p.Item2.Name} ({(p.Item2.WeaponType == 0 ? p.Item2.Armor().ToString() : p.Item2.Weapon().ToString())})"))
|
||||
.OrderBy(p => p.Item1));
|
||||
DrawNameTable("All Items (Off)", ref _itemFilter,
|
||||
_items.ItemService.AwaitedService.AllItems(false).Select(p => (p.Item1,
|
||||
_items.ItemService.AwaitedService.AllItems(false).Select(p => (p.Item1.Id,
|
||||
$"{p.Item2.Name} ({(p.Item2.WeaponType == 0 ? p.Item2.Armor().ToString() : p.Item2.Weapon().ToString())})"))
|
||||
.OrderBy(p => p.Item1));
|
||||
foreach (var type in Enum.GetValues<FullEquipType>().Skip(1))
|
||||
{
|
||||
DrawNameTable(type.ToName(), ref _itemFilter,
|
||||
_items.ItemService.AwaitedService[type]
|
||||
.Select(p => (Id: p.ItemId, $"{p.Name} ({(p.WeaponType == 0 ? p.Armor().ToString() : p.Weapon().ToString())})")));
|
||||
.Select(p => (Id: p.ItemId.Id, $"{p.Name} ({(p.WeaponType == 0 ? p.Armor().ToString() : p.Weapon().ToString())})")));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -803,10 +804,10 @@ public unsafe class DebugTab : ITab
|
|||
var skips = ImGuiClip.GetNecessarySkips(height);
|
||||
ImGui.TableNextRow();
|
||||
var remainder = ImGuiClip.FilteredClippedDraw(_items.Stains, skips,
|
||||
p => p.Key.Value.ToString().Contains(_stainFilter) || p.Value.Name.Contains(_stainFilter, StringComparison.OrdinalIgnoreCase),
|
||||
p => p.Key.Id.ToString().Contains(_stainFilter) || p.Value.Name.Contains(_stainFilter, StringComparison.OrdinalIgnoreCase),
|
||||
p =>
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(p.Key.Value.ToString("D3"));
|
||||
ImGuiUtil.DrawTableColumn(p.Key.Id.ToString("D3"));
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.GetWindowDrawList().AddRectFilled(ImGui.GetCursorScreenPos(),
|
||||
ImGui.GetCursorScreenPos() + new Vector2(ImGui.GetTextLineHeight()),
|
||||
|
|
@ -1116,7 +1117,7 @@ public unsafe class DebugTab : ITab
|
|||
static string ItemString(in DesignData data, EquipSlot slot)
|
||||
{
|
||||
var item = data.Item(slot);
|
||||
return $"{item.Name} ({item.ModelId.Value}{(item.WeaponType != 0 ? $"-{item.WeaponType.Value}" : string.Empty)}-{item.Variant})";
|
||||
return $"{item.Name} ({item.ModelId.Id}{(item.WeaponType != 0 ? $"-{item.WeaponType.Id}" : string.Empty)}-{item.Variant})";
|
||||
}
|
||||
|
||||
PrintRow("Model ID", state.BaseData.ModelId, state.ModelData.ModelId, state[ActorState.MetaIndex.ModelId]);
|
||||
|
|
@ -1137,8 +1138,8 @@ public unsafe class DebugTab : ITab
|
|||
foreach (var slot in EquipSlotExtensions.EqdpSlots.Prepend(EquipSlot.OffHand).Prepend(EquipSlot.MainHand))
|
||||
{
|
||||
PrintRow(slot.ToName(), ItemString(state.BaseData, slot), ItemString(state.ModelData, slot), state[slot, false]);
|
||||
ImGuiUtil.DrawTableColumn(state.BaseData.Stain(slot).Value.ToString());
|
||||
ImGuiUtil.DrawTableColumn(state.ModelData.Stain(slot).Value.ToString());
|
||||
ImGuiUtil.DrawTableColumn(state.BaseData.Stain(slot).Id.ToString());
|
||||
ImGuiUtil.DrawTableColumn(state.ModelData.Stain(slot).Id.ToString());
|
||||
ImGuiUtil.DrawTableColumn(state[slot, true].ToString());
|
||||
}
|
||||
|
||||
|
|
@ -1453,7 +1454,7 @@ public unsafe class DebugTab : ITab
|
|||
ImGui.TableNextColumn();
|
||||
var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeightWithSpacing());
|
||||
ImGui.TableNextRow();
|
||||
var remainder = ImGuiClip.ClippedDraw(_itemUnlocks.Unlocked, skips, t =>
|
||||
var remainder = ImGuiClip.ClippedDraw(_itemUnlocks, skips, t =>
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(t.Key.ToString());
|
||||
if (_items.ItemService.AwaitedService.TryGetValue(t.Key, EquipSlot.MainHand, out var equip))
|
||||
|
|
@ -1474,7 +1475,7 @@ public unsafe class DebugTab : ITab
|
|||
? "Always"
|
||||
: time.LocalDateTime.ToString("g")
|
||||
: "Never");
|
||||
}, _itemUnlocks.Unlocked.Count);
|
||||
}, _itemUnlocks.Count);
|
||||
ImGuiClip.DrawEndDummy(remainder, ImGui.GetTextLineHeight());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ public class UnlockOverview
|
|||
void DrawItem(EquipItem item)
|
||||
{
|
||||
var unlocked = _itemUnlocks.IsUnlocked(item.Id, out var time);
|
||||
var iconHandle = _textures.LoadIcon(item.IconId);
|
||||
var iconHandle = _textures.LoadIcon(item.IconId.Id);
|
||||
if (!iconHandle.HasValue)
|
||||
return;
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ public class UnlockTable : Table<EquipItem>, IDisposable
|
|||
|
||||
public override void DrawColumn(EquipItem item, int _)
|
||||
{
|
||||
var iconHandle = _textures.LoadIcon(item.IconId);
|
||||
var iconHandle = _textures.LoadIcon(item.IconId.Id);
|
||||
if (iconHandle.HasValue)
|
||||
ImGuiUtil.HoverIcon(iconHandle.Value, new Vector2(ImGui.GetFrameHeight()));
|
||||
else
|
||||
|
|
@ -214,7 +214,7 @@ public class UnlockTable : Table<EquipItem>, IDisposable
|
|||
=> 70 * ImGuiHelpers.GlobalScale;
|
||||
|
||||
public override int Compare(EquipItem lhs, EquipItem rhs)
|
||||
=> lhs.ItemId.CompareTo(rhs.ItemId);
|
||||
=> lhs.ItemId.Id.CompareTo(rhs.ItemId.Id);
|
||||
|
||||
public override string ToName(EquipItem item)
|
||||
=> item.ItemId.ToString();
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ public static class UiHelpers
|
|||
{
|
||||
public static void DrawIcon(this EquipItem item, TextureService textures, Vector2 size)
|
||||
{
|
||||
var isEmpty = item.ModelId.Value == 0;
|
||||
var isEmpty = item.ModelId.Id == 0;
|
||||
var (ptr, textureSize, empty) = textures.GetIcon(item);
|
||||
if (empty)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ public class ContextMenuService : IDisposable
|
|||
_state.ChangeEquip(state, slot, item, 0, StateChanged.Source.Manual);
|
||||
if (item.Type.ValidOffhand().IsOffhandType())
|
||||
{
|
||||
if (item.ModelId.Value is > 1600 and < 1651
|
||||
if (item.ModelId.Id is > 1600 and < 1651
|
||||
&& _items.ItemService.AwaitedService.TryGetValue(item.ItemId, EquipSlot.Hands, out var gauntlets))
|
||||
_state.ChangeEquip(state, EquipSlot.Hands, gauntlets, 0, StateChanged.Source.Manual);
|
||||
if (_items.ItemService.AwaitedService.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand))
|
||||
|
|
@ -143,7 +143,7 @@ public class ContextMenuService : IDisposable
|
|||
_state.ChangeEquip(state, slot, item, 0, StateChanged.Source.Manual);
|
||||
if (item.Type.ValidOffhand().IsOffhandType())
|
||||
{
|
||||
if (item.ModelId.Value is > 1600 and < 1651
|
||||
if (item.ModelId.Id is > 1600 and < 1651
|
||||
&& _items.ItemService.AwaitedService.TryGetValue(item.ItemId, EquipSlot.Hands, out var gauntlets))
|
||||
_state.ChangeEquip(state, EquipSlot.Hands, gauntlets, 0, StateChanged.Source.Manual);
|
||||
if (_items.ItemService.AwaitedService.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand))
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ public readonly unsafe struct Model : IEquatable<Model>
|
|||
Model weapon = AsDrawObject->Object.ChildObject;
|
||||
return !weapon.IsWeapon
|
||||
? (Null, CharacterWeapon.Empty)
|
||||
: (weapon, new CharacterWeapon(weapon.AsWeapon->ModelSetId, weapon.AsWeapon->SecondaryId, weapon.AsWeapon->Variant,
|
||||
: (weapon, new CharacterWeapon(weapon.AsWeapon->ModelSetId, weapon.AsWeapon->SecondaryId, (Variant)weapon.AsWeapon->Variant,
|
||||
(StainId)weapon.AsWeapon->ModelUnknown));
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +112,7 @@ public readonly unsafe struct Model : IEquatable<Model>
|
|||
if (offhand == mainhand || !offhand.IsWeapon)
|
||||
return (Null, CharacterWeapon.Empty);
|
||||
|
||||
return (offhand, new CharacterWeapon(offhand.AsWeapon->ModelSetId, offhand.AsWeapon->SecondaryId, offhand.AsWeapon->Variant,
|
||||
return (offhand, new CharacterWeapon(offhand.AsWeapon->ModelSetId, offhand.AsWeapon->SecondaryId, (Variant)offhand.AsWeapon->Variant,
|
||||
(StainId)offhand.AsWeapon->ModelUnknown));
|
||||
}
|
||||
|
||||
|
|
@ -124,13 +124,14 @@ public readonly unsafe struct Model : IEquatable<Model>
|
|||
{
|
||||
case 0: return (Null, Null, CharacterWeapon.Empty, CharacterWeapon.Empty);
|
||||
case 1:
|
||||
return (first, Null, new CharacterWeapon(first.AsWeapon->ModelSetId, first.AsWeapon->SecondaryId, first.AsWeapon->Variant,
|
||||
return (first, Null, new CharacterWeapon(first.AsWeapon->ModelSetId, first.AsWeapon->SecondaryId,
|
||||
(Variant)first.AsWeapon->Variant,
|
||||
(StainId)first.AsWeapon->ModelUnknown), CharacterWeapon.Empty);
|
||||
default:
|
||||
var (main, off) = DetermineMainhand(first, second);
|
||||
var mainData = new CharacterWeapon(main.AsWeapon->ModelSetId, main.AsWeapon->SecondaryId, main.AsWeapon->Variant,
|
||||
var mainData = new CharacterWeapon(main.AsWeapon->ModelSetId, main.AsWeapon->SecondaryId, (Variant)main.AsWeapon->Variant,
|
||||
(StainId)main.AsWeapon->ModelUnknown);
|
||||
var offData = new CharacterWeapon(off.AsWeapon->ModelSetId, off.AsWeapon->SecondaryId, off.AsWeapon->Variant,
|
||||
var offData = new CharacterWeapon(off.AsWeapon->ModelSetId, off.AsWeapon->SecondaryId, (Variant)off.AsWeapon->Variant,
|
||||
(StainId)off.AsWeapon->ModelUnknown);
|
||||
return (main, off, mainData, offData);
|
||||
}
|
||||
|
|
@ -145,14 +146,14 @@ public readonly unsafe struct Model : IEquatable<Model>
|
|||
Model main = *((nint*)&actor.AsCharacter->DrawData.MainHand + 1);
|
||||
var mainData = CharacterWeapon.Empty;
|
||||
if (main.IsWeapon)
|
||||
mainData = new CharacterWeapon(main.AsWeapon->ModelSetId, main.AsWeapon->SecondaryId, main.AsWeapon->Variant,
|
||||
mainData = new CharacterWeapon(main.AsWeapon->ModelSetId, main.AsWeapon->SecondaryId, (Variant)main.AsWeapon->Variant,
|
||||
(StainId)main.AsWeapon->ModelUnknown);
|
||||
else
|
||||
main = Null;
|
||||
Model off = *((nint*)&actor.AsCharacter->DrawData.OffHand + 1);
|
||||
var offData = CharacterWeapon.Empty;
|
||||
if (off.IsWeapon)
|
||||
offData = new CharacterWeapon(off.AsWeapon->ModelSetId, off.AsWeapon->SecondaryId, off.AsWeapon->Variant,
|
||||
offData = new CharacterWeapon(off.AsWeapon->ModelSetId, off.AsWeapon->SecondaryId, (Variant)off.AsWeapon->Variant,
|
||||
(StainId)off.AsWeapon->ModelUnknown);
|
||||
else
|
||||
off = Null;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ public class VisorService : IDisposable
|
|||
if (oldState == on)
|
||||
return false;
|
||||
|
||||
SetupVisorHook(human, human.GetArmor(EquipSlot.Head).Set.Value, on);
|
||||
SetupVisorHook(human, human.GetArmor(EquipSlot.Head).Set.Id, on);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public unsafe class WeaponService : IDisposable
|
|||
_loadWeaponHook.Original(drawData, slot, weapon.Value, redrawOnEquality, unk2, skipGameObject, unk4);
|
||||
if (tmpWeapon.Value != weapon.Value)
|
||||
{
|
||||
if (tmpWeapon.Set.Value == 0)
|
||||
if (tmpWeapon.Set.Id == 0)
|
||||
tmpWeapon.Stain = 0;
|
||||
_loadWeaponHook.Original(drawData, slot, tmpWeapon.Value, 1, unk2, 1, unk4);
|
||||
}
|
||||
|
|
@ -91,7 +91,7 @@ public unsafe class WeaponService : IDisposable
|
|||
var mdl = character.Model;
|
||||
var (_, _, mh, oh) = mdl.GetWeapons(character);
|
||||
var value = slot == EquipSlot.OffHand ? oh : mh;
|
||||
var weapon = value.With(value.Set.Value == 0 ? 0 : stain);
|
||||
var weapon = value.With(value.Set.Id == 0 ? 0 : stain);
|
||||
LoadWeapon(character, slot, weapon);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,13 +48,13 @@ public class ItemManager : IDisposable
|
|||
public (bool, CharacterArmor) ResolveRestrictedGear(CharacterArmor armor, EquipSlot slot, Race race, Gender gender)
|
||||
=> _config.UseRestrictedGearProtection ? RestrictedGear.ResolveRestricted(armor, slot, race, gender) : (false, armor);
|
||||
|
||||
public static uint NothingId(EquipSlot slot)
|
||||
public static ItemId NothingId(EquipSlot slot)
|
||||
=> uint.MaxValue - 128 - (uint)slot.ToSlot();
|
||||
|
||||
public static uint SmallclothesId(EquipSlot slot)
|
||||
public static ItemId SmallclothesId(EquipSlot slot)
|
||||
=> uint.MaxValue - 256 - (uint)slot.ToSlot();
|
||||
|
||||
public static uint NothingId(FullEquipType type)
|
||||
public static ItemId NothingId(FullEquipType type)
|
||||
=> uint.MaxValue - 384 - (uint)type;
|
||||
|
||||
public static EquipItem NothingItem(EquipSlot slot)
|
||||
|
|
@ -66,7 +66,7 @@ public class ItemManager : IDisposable
|
|||
public static EquipItem SmallClothesItem(EquipSlot slot)
|
||||
=> new(SmallClothesNpc, SmallclothesId(slot), 0, SmallClothesNpcModel, 0, 1, slot.ToEquipType());
|
||||
|
||||
public EquipItem Resolve(EquipSlot slot, uint itemId)
|
||||
public EquipItem Resolve(EquipSlot slot, ItemId itemId)
|
||||
{
|
||||
slot = slot.ToSlot();
|
||||
if (itemId == NothingId(slot))
|
||||
|
|
@ -83,7 +83,7 @@ public class ItemManager : IDisposable
|
|||
return item;
|
||||
}
|
||||
|
||||
public EquipItem Resolve(FullEquipType type, uint itemId)
|
||||
public EquipItem Resolve(FullEquipType type, ItemId itemId)
|
||||
{
|
||||
if (itemId == NothingId(type))
|
||||
return NothingItem(type);
|
||||
|
|
@ -97,13 +97,13 @@ public class ItemManager : IDisposable
|
|||
return item;
|
||||
}
|
||||
|
||||
public EquipItem Identify(EquipSlot slot, SetId id, byte variant)
|
||||
public EquipItem Identify(EquipSlot slot, SetId id, Variant variant)
|
||||
{
|
||||
slot = slot.ToSlot();
|
||||
if (slot.ToIndex() == uint.MaxValue)
|
||||
return new EquipItem($"Invalid ({id.Value}-{variant})", 0, 0, id, 0, variant, 0);
|
||||
return new EquipItem($"Invalid ({id.Id}-{variant})", 0, 0, id, 0, variant, 0);
|
||||
|
||||
switch (id.Value)
|
||||
switch (id.Id)
|
||||
{
|
||||
case 0: return NothingItem(slot);
|
||||
case SmallClothesNpcModel: return SmallClothesItem(slot);
|
||||
|
|
@ -125,17 +125,17 @@ public class ItemManager : IDisposable
|
|||
return NothingItem(offhandType);
|
||||
}
|
||||
|
||||
public EquipItem Identify(EquipSlot slot, SetId id, WeaponType type, byte variant, FullEquipType mainhandType = FullEquipType.Unknown)
|
||||
public EquipItem Identify(EquipSlot slot, SetId id, WeaponType type, Variant variant, FullEquipType mainhandType = FullEquipType.Unknown)
|
||||
{
|
||||
if (slot is EquipSlot.OffHand)
|
||||
{
|
||||
var weaponType = mainhandType.ValidOffhand();
|
||||
if (id.Value == 0)
|
||||
if (id.Id == 0)
|
||||
return NothingItem(weaponType);
|
||||
}
|
||||
|
||||
if (slot is not EquipSlot.MainHand and not EquipSlot.OffHand)
|
||||
return new EquipItem($"Invalid ({id.Value}-{type.Value}-{variant})", 0, 0, id, type, variant, 0);
|
||||
return new EquipItem($"Invalid ({id.Id}-{type.Id}-{variant})", 0, 0, id, type, variant, 0);
|
||||
|
||||
var item = IdentifierService.AwaitedService.Identify(id, type, variant, slot).FirstOrDefault();
|
||||
return item.Valid
|
||||
|
|
@ -145,7 +145,7 @@ public class ItemManager : IDisposable
|
|||
|
||||
/// <summary> Returns whether an item id represents a valid item for a slot and gives the item. </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public bool IsItemValid(EquipSlot slot, uint itemId, out EquipItem item)
|
||||
public bool IsItemValid(EquipSlot slot, ItemId itemId, out EquipItem item)
|
||||
{
|
||||
item = Resolve(slot, itemId);
|
||||
return item.Valid;
|
||||
|
|
@ -156,20 +156,19 @@ public class ItemManager : IDisposable
|
|||
/// The returned item is either the resolved correct item, or the Nothing item for that slot.
|
||||
/// The return value is an empty string if there was no problem and a warning otherwise.
|
||||
/// </summary>
|
||||
public string ValidateItem(EquipSlot slot, ulong itemId, out EquipItem item, bool allowUnknown)
|
||||
public string ValidateItem(EquipSlot slot, CustomItemId itemId, out EquipItem item, bool allowUnknown)
|
||||
{
|
||||
if (slot is EquipSlot.MainHand or EquipSlot.OffHand)
|
||||
throw new Exception("Internal Error: Used armor functionality for weapons.");
|
||||
|
||||
if (itemId > uint.MaxValue)
|
||||
if (!itemId.IsItem)
|
||||
{
|
||||
var id = (SetId)(itemId & ushort.MaxValue);
|
||||
var variant = (byte)(itemId >> 32);
|
||||
var (id, _, variant, _) = itemId.Split;
|
||||
item = Identify(slot, id, variant);
|
||||
return allowUnknown ? string.Empty : $"The item {itemId} yields an unknown item.";
|
||||
}
|
||||
|
||||
if (IsItemValid(slot, (uint)itemId, out item))
|
||||
if (IsItemValid(slot, itemId.Item, out item))
|
||||
return string.Empty;
|
||||
|
||||
item = NothingItem(slot);
|
||||
|
|
@ -179,7 +178,7 @@ public class ItemManager : IDisposable
|
|||
/// <summary> Returns whether a stain id is a valid stain. </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public bool IsStainValid(StainId stain)
|
||||
=> stain.Value == 0 || Stains.ContainsKey(stain);
|
||||
=> stain.Id == 0 || Stains.ContainsKey(stain);
|
||||
|
||||
/// <summary>
|
||||
/// Check whether a stain id is an existing stain.
|
||||
|
|
@ -200,7 +199,7 @@ public class ItemManager : IDisposable
|
|||
|
||||
/// <summary> Returns whether an offhand is valid given the required offhand type. </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public bool IsOffhandValid(FullEquipType offType, uint offId, out EquipItem off)
|
||||
public bool IsOffhandValid(FullEquipType offType, ItemId offId, out EquipItem off)
|
||||
{
|
||||
off = Resolve(offType, offId);
|
||||
return offType == FullEquipType.Unknown || off.Valid;
|
||||
|
|
@ -208,7 +207,7 @@ public class ItemManager : IDisposable
|
|||
|
||||
/// <summary> Returns whether an offhand is valid given mainhand. </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public bool IsOffhandValid(in EquipItem main, uint offId, out EquipItem off)
|
||||
public bool IsOffhandValid(in EquipItem main, ItemId offId, out EquipItem off)
|
||||
=> IsOffhandValid(main.Type.ValidOffhand(), offId, out off);
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -218,7 +217,7 @@ public class ItemManager : IDisposable
|
|||
/// or the default sword and a nothing offhand.
|
||||
/// The return value is an empty string if there was no problem and a warning otherwise.
|
||||
/// </summary>
|
||||
public string ValidateWeapons(uint mainId, uint offId, out EquipItem main, out EquipItem off)
|
||||
public string ValidateWeapons(ItemId mainId, ItemId offId, out EquipItem main, out EquipItem off)
|
||||
{
|
||||
var ret = string.Empty;
|
||||
if (!IsItemValid(EquipSlot.MainHand, mainId, out main))
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ public sealed class TextureService : TextureCache, IDisposable
|
|||
|
||||
public (nint, Vector2, bool) GetIcon(EquipItem item)
|
||||
{
|
||||
if (item.IconId != 0 && TryLoadIcon(item.IconId, out var ret))
|
||||
if (item.IconId.Id != 0 && TryLoadIcon(item.IconId.Id, out var ret))
|
||||
return (ret.Value.Texture, ret.Value.Dimensions, false);
|
||||
|
||||
var idx = item.Type.ToSlot().ToIndex();
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ public class StateApplier
|
|||
/// <summary> Apply a weapon to the offhand. </summary>
|
||||
public void ChangeOffhand(ActorData data, EquipItem weapon, StainId stain)
|
||||
{
|
||||
stain = weapon.ModelId.Value == 0 ? 0 : stain;
|
||||
stain = weapon.ModelId.Id == 0 ? 0 : stain;
|
||||
foreach (var actor in data.Objects.Where(a => a.Model.IsHuman))
|
||||
_weapon.LoadWeapon(actor, EquipSlot.OffHand, weapon.Weapon().With(stain));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ public class StateListener : IDisposable
|
|||
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)
|
||||
if (slot is EquipSlot.OffHand && weapon.Value.Variant == 0 && weapon.Value.Set.Id != 0 && _lastFistOffhand.Set.Id != 0)
|
||||
weapon.Value = _lastFistOffhand;
|
||||
|
||||
if (!actor.Identifier(_actors.AwaitedService, out var identifier)
|
||||
|
|
@ -297,13 +297,13 @@ public class StateListener : IDisposable
|
|||
var newWeapon = state.ModelData.Weapon(slot);
|
||||
if (baseType is FullEquipType.Unknown || baseType == state.ModelData.Item(slot).Type || _gPose.InGPose && actor.IsGPoseOrCutscene)
|
||||
actorWeapon = newWeapon;
|
||||
else if (actorWeapon.Set.Value != 0)
|
||||
else if (actorWeapon.Set.Id != 0)
|
||||
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,
|
||||
if (slot is EquipSlot.MainHand && weapon.Value.Set.Id is > 1600 and < 1651)
|
||||
_lastFistOffhand = new CharacterWeapon((SetId)(weapon.Value.Set.Id + 50), weapon.Value.Type, weapon.Value.Variant,
|
||||
weapon.Value.Stain);
|
||||
}
|
||||
|
||||
|
|
@ -316,7 +316,7 @@ public class StateListener : IDisposable
|
|||
return false;
|
||||
|
||||
var offhand = actor.GetOffhand();
|
||||
return offhand.Variant == 0 && offhand.Set.Value != 0 && armor.Set.Value == offhand.Set.Value;
|
||||
return offhand.Variant == 0 && offhand.Set.Id != 0 && armor.Set.Id == offhand.Set.Id;
|
||||
}
|
||||
|
||||
var actorArmor = actor.GetArmor(slot);
|
||||
|
|
@ -333,7 +333,7 @@ public class StateListener : IDisposable
|
|||
change = UpdateState.Change;
|
||||
}
|
||||
|
||||
if (baseData.Set.Value != armor.Set.Value || baseData.Variant != armor.Variant)
|
||||
if (baseData.Set.Id != armor.Set.Id || baseData.Variant != armor.Variant)
|
||||
{
|
||||
var item = _items.Identify(slot, armor.Set, armor.Variant);
|
||||
state.BaseData.SetItem(slot, item);
|
||||
|
|
@ -387,9 +387,9 @@ public class StateListener : IDisposable
|
|||
change = UpdateState.Change;
|
||||
}
|
||||
|
||||
if (baseData.Set.Value != weapon.Set.Value || baseData.Type.Value != weapon.Type.Value || baseData.Variant != weapon.Variant)
|
||||
if (baseData.Set.Id != weapon.Set.Id || baseData.Type.Id != weapon.Type.Id || baseData.Variant != weapon.Variant)
|
||||
{
|
||||
var item = _items.Identify(slot, weapon.Set, weapon.Type, (byte)weapon.Variant,
|
||||
var item = _items.Identify(slot, weapon.Set, weapon.Type, weapon.Variant,
|
||||
slot is EquipSlot.OffHand ? state.BaseData.Item(EquipSlot.MainHand).Type : FullEquipType.Unknown);
|
||||
state.BaseData.SetItem(slot, item);
|
||||
change = UpdateState.Change;
|
||||
|
|
|
|||
|
|
@ -174,8 +174,8 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
|||
}
|
||||
|
||||
// Set the weapons regardless of source.
|
||||
var mainItem = _items.Identify(EquipSlot.MainHand, main.Set, main.Type, (byte)main.Variant);
|
||||
var offItem = _items.Identify(EquipSlot.OffHand, off.Set, off.Type, (byte)off.Variant, mainItem.Type);
|
||||
var mainItem = _items.Identify(EquipSlot.MainHand, main.Set, main.Type, main.Variant);
|
||||
var offItem = _items.Identify(EquipSlot.OffHand, off.Set, off.Type, off.Variant, mainItem.Type);
|
||||
ret.SetItem(EquipSlot.MainHand, mainItem);
|
||||
ret.SetStain(EquipSlot.MainHand, main.Stain);
|
||||
ret.SetItem(EquipSlot.OffHand, offItem);
|
||||
|
|
@ -194,11 +194,11 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
|||
/// <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)
|
||||
if (mainhand.Set.Id is < 1601 or >= 1651)
|
||||
return;
|
||||
|
||||
var gauntlets = _items.Identify(EquipSlot.Hands, offhand.Set, 0, (byte)offhand.Variant);
|
||||
offhand.Set = (SetId)(mainhand.Set.Value + 50);
|
||||
var gauntlets = _items.Identify(EquipSlot.Hands, offhand.Set, 0, offhand.Variant);
|
||||
offhand.Set = (SetId)(mainhand.Set.Id + 50);
|
||||
offhand.Variant = mainhand.Variant;
|
||||
offhand.Type = mainhand.Type;
|
||||
ret.SetItem(EquipSlot.Hands, gauntlets);
|
||||
|
|
@ -275,7 +275,7 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
|||
? _applier.ChangeArmor(state, slot, source is StateChanged.Source.Manual or StateChanged.Source.Ipc)
|
||||
: _applier.ChangeWeapon(state, slot, source is StateChanged.Source.Manual or StateChanged.Source.Ipc, item.Type != (slot is EquipSlot.MainHand ? state.BaseData.MainhandType : state.BaseData.OffhandType));
|
||||
Glamourer.Log.Verbose(
|
||||
$"Set {slot.ToName()} in state {state.Identifier.Incognito(null)} from {old.Name} ({old.ItemId}) to {item.Name} ({item.ItemId}) and its stain from {oldStain.Value} to {stain.Value}. [Affecting {actors.ToLazyString("nothing")}.]");
|
||||
$"Set {slot.ToName()} in state {state.Identifier.Incognito(null)} from {old.Name} ({old.ItemId}) to {item.Name} ({item.ItemId}) and its stain from {oldStain.Id} to {stain.Id}. [Affecting {actors.ToLazyString("nothing")}.]");
|
||||
_event.Invoke(type, source, state, actors, (old, item, slot));
|
||||
_event.Invoke(StateChanged.Type.Stain, source, state, actors, (oldStain, stain, slot));
|
||||
}
|
||||
|
|
@ -289,7 +289,7 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
|||
|
||||
var actors = _applier.ChangeStain(state, slot, source is StateChanged.Source.Manual or StateChanged.Source.Ipc);
|
||||
Glamourer.Log.Verbose(
|
||||
$"Set {slot.ToName()} stain in state {state.Identifier.Incognito(null)} from {old.Value} to {stain.Value}. [Affecting {actors.ToLazyString("nothing")}.]");
|
||||
$"Set {slot.ToName()} stain in state {state.Identifier.Incognito(null)} from {old.Id} to {stain.Id}. [Affecting {actors.ToLazyString("nothing")}.]");
|
||||
_event.Invoke(StateChanged.Type.Stain, source, state, actors, (old, stain, slot));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
|
@ -12,14 +13,12 @@ using Glamourer.Events;
|
|||
using Glamourer.Services;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Penumbra.GameData.Enums;
|
||||
using static OtterGui.Raii.ImRaii;
|
||||
using static Penumbra.GameData.Files.ShpkFile;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Cabinet = Lumina.Excel.GeneratedSheets.Cabinet;
|
||||
using Item = Lumina.Excel.GeneratedSheets.Item;
|
||||
|
||||
namespace Glamourer.Unlocks;
|
||||
|
||||
public class ItemUnlockManager : ISavable, IDisposable
|
||||
public class ItemUnlockManager : ISavable, IDisposable, IReadOnlyDictionary<ItemId, long>
|
||||
{
|
||||
private readonly SaveService _saveService;
|
||||
private readonly ItemManager _items;
|
||||
|
|
@ -46,10 +45,7 @@ public class ItemUnlockManager : ISavable, IDisposable
|
|||
Cabinet = 0x08,
|
||||
}
|
||||
|
||||
public readonly IReadOnlyDictionary<uint, UnlockRequirements> Unlockable;
|
||||
|
||||
public IReadOnlyDictionary<uint, long> Unlocked
|
||||
=> _unlocked;
|
||||
public readonly IReadOnlyDictionary<ItemId, UnlockRequirements> Unlockable;
|
||||
|
||||
public ItemUnlockManager(SaveService saveService, ItemManager items, ClientState clientState, DataManager gameData, Framework framework,
|
||||
ObjectUnlocked @event, IdentifierService identifier)
|
||||
|
|
@ -104,18 +100,19 @@ public class ItemUnlockManager : ISavable, IDisposable
|
|||
InventoryType.RetainerMarket,
|
||||
};
|
||||
|
||||
private bool AddItem(uint itemId, long time)
|
||||
private bool AddItem(ItemId itemId, long time)
|
||||
{
|
||||
itemId = HandleHq(itemId);
|
||||
if (!_items.ItemService.AwaitedService.TryGetValue(itemId, EquipSlot.MainHand, out var equip) || !_unlocked.TryAdd(equip.ItemId, time))
|
||||
itemId = itemId.StripModifiers;
|
||||
if (!_items.ItemService.AwaitedService.TryGetValue(itemId, EquipSlot.MainHand, out var equip)
|
||||
|| !_unlocked.TryAdd(equip.ItemId.Id, time))
|
||||
return false;
|
||||
|
||||
_event.Invoke(ObjectUnlocked.Type.Item, equip.ItemId, DateTimeOffset.FromUnixTimeMilliseconds(time));
|
||||
_event.Invoke(ObjectUnlocked.Type.Item, equip.ItemId.Id, DateTimeOffset.FromUnixTimeMilliseconds(time));
|
||||
var ident = _identifier.AwaitedService.Identify(equip.ModelId, equip.WeaponType, equip.Variant, equip.Type.ToSlot());
|
||||
foreach (var item in ident)
|
||||
{
|
||||
if (_unlocked.TryAdd(item.ItemId, time))
|
||||
_event.Invoke(ObjectUnlocked.Type.Item, item.ItemId, DateTimeOffset.FromUnixTimeMilliseconds(time));
|
||||
if (_unlocked.TryAdd(item.ItemId.Id, time))
|
||||
_event.Invoke(ObjectUnlocked.Type.Item, item.ItemId.Id, DateTimeOffset.FromUnixTimeMilliseconds(time));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -201,27 +198,28 @@ public class ItemUnlockManager : ISavable, IDisposable
|
|||
Save();
|
||||
}
|
||||
|
||||
public bool IsUnlocked(ulong itemId, out DateTimeOffset time)
|
||||
public bool IsUnlocked(CustomItemId itemId, out DateTimeOffset time)
|
||||
{
|
||||
// Pseudo items are always unlocked.
|
||||
if (itemId >= _items.ItemSheet.RowCount)
|
||||
if (itemId.Id >= _items.ItemSheet.RowCount)
|
||||
{
|
||||
time = DateTimeOffset.MinValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_unlocked.TryGetValue((uint) itemId, out var t))
|
||||
var id = itemId.Item.Id;
|
||||
if (_unlocked.TryGetValue(id, out var t))
|
||||
{
|
||||
time = DateTimeOffset.FromUnixTimeMilliseconds(t);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsGameUnlocked((uint) itemId))
|
||||
if (IsGameUnlocked(id))
|
||||
{
|
||||
time = DateTimeOffset.UtcNow;
|
||||
if (_unlocked.TryAdd((uint) itemId, time.ToUnixTimeMilliseconds()))
|
||||
if (_unlocked.TryAdd(id, time.ToUnixTimeMilliseconds()))
|
||||
{
|
||||
_event.Invoke(ObjectUnlocked.Type.Item, (uint) itemId, time);
|
||||
_event.Invoke(ObjectUnlocked.Type.Item, id, time);
|
||||
Save();
|
||||
}
|
||||
|
||||
|
|
@ -232,7 +230,7 @@ public class ItemUnlockManager : ISavable, IDisposable
|
|||
return false;
|
||||
}
|
||||
|
||||
public unsafe bool IsGameUnlocked(uint itemId)
|
||||
public unsafe bool IsGameUnlocked(ItemId itemId)
|
||||
{
|
||||
if (Unlockable.TryGetValue(itemId, out var req))
|
||||
return req.IsUnlocked(this);
|
||||
|
|
@ -253,15 +251,14 @@ public class ItemUnlockManager : ISavable, IDisposable
|
|||
var changes = false;
|
||||
foreach (var (itemId, unlock) in Unlockable)
|
||||
{
|
||||
if (unlock.IsUnlocked(this) && _unlocked.TryAdd(itemId, time))
|
||||
if (unlock.IsUnlocked(this) && _unlocked.TryAdd(itemId.Id, time))
|
||||
{
|
||||
_event.Invoke(ObjectUnlocked.Type.Item, itemId, DateTimeOffset.FromUnixTimeMilliseconds(time));
|
||||
_event.Invoke(ObjectUnlocked.Type.Item, itemId.Id, DateTimeOffset.FromUnixTimeMilliseconds(time));
|
||||
changes = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO inventories
|
||||
|
||||
if (changes)
|
||||
Save();
|
||||
}
|
||||
|
|
@ -273,7 +270,7 @@ public class ItemUnlockManager : ISavable, IDisposable
|
|||
=> _saveService.DelaySave(this, TimeSpan.FromSeconds(10));
|
||||
|
||||
public void Save(StreamWriter writer)
|
||||
=> UnlockDictionaryHelpers.Save(writer, Unlocked);
|
||||
=> UnlockDictionaryHelpers.Save(writer, _unlocked);
|
||||
|
||||
private void Load()
|
||||
{
|
||||
|
|
@ -285,9 +282,9 @@ public class ItemUnlockManager : ISavable, IDisposable
|
|||
private void OnLogin(object? _, EventArgs _2)
|
||||
=> Scan();
|
||||
|
||||
private static Dictionary<uint, UnlockRequirements> CreateUnlockData(DataManager gameData, ItemManager items)
|
||||
private static Dictionary<ItemId, UnlockRequirements> CreateUnlockData(DataManager gameData, ItemManager items)
|
||||
{
|
||||
var ret = new Dictionary<uint, UnlockRequirements>();
|
||||
var ret = new Dictionary<ItemId, UnlockRequirements>();
|
||||
var cabinet = gameData.GetExcelSheet<Cabinet>()!;
|
||||
foreach (var row in cabinet)
|
||||
{
|
||||
|
|
@ -338,17 +335,33 @@ public class ItemUnlockManager : ISavable, IDisposable
|
|||
var ident = _identifier.AwaitedService.Identify(equip.ModelId, equip.WeaponType, equip.Variant, equip.Type.ToSlot());
|
||||
foreach (var item2 in ident)
|
||||
{
|
||||
if (_unlocked.TryAdd(item2.ItemId, time))
|
||||
_event.Invoke(ObjectUnlocked.Type.Item, item2.ItemId, DateTimeOffset.FromUnixTimeMilliseconds(time));
|
||||
if (_unlocked.TryAdd(item2.ItemId.Id, time))
|
||||
_event.Invoke(ObjectUnlocked.Type.Item, item2.ItemId.Id, DateTimeOffset.FromUnixTimeMilliseconds(time));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private uint HandleHq(uint itemId)
|
||||
=> itemId switch
|
||||
{
|
||||
> 1000000 => itemId - 1000000,
|
||||
> 500000 => itemId - 500000,
|
||||
_ => itemId,
|
||||
};
|
||||
public IEnumerator<KeyValuePair<ItemId, long>> GetEnumerator()
|
||||
=> _unlocked.Select(kvp => new KeyValuePair<ItemId, long>(kvp.Key, kvp.Value)).GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
=> GetEnumerator();
|
||||
|
||||
public int Count
|
||||
=> _unlocked.Count;
|
||||
|
||||
public bool ContainsKey(ItemId key)
|
||||
=> _unlocked.ContainsKey(key.Id);
|
||||
|
||||
public bool TryGetValue(ItemId key, out long value)
|
||||
=> _unlocked.TryGetValue(key.Id, out value);
|
||||
|
||||
public long this[ItemId key]
|
||||
=> _unlocked[key.Id];
|
||||
|
||||
public IEnumerable<ItemId> Keys
|
||||
=> _unlocked.Keys.Select(i => (ItemId)i);
|
||||
|
||||
public IEnumerable<long> Values
|
||||
=> _unlocked.Values;
|
||||
}
|
||||
|
|
|
|||
2
OtterGui
2
OtterGui
|
|
@ -1 +1 @@
|
|||
Subproject commit e3d26f16234a4295bf3c7802d87ce43293c6ffe0
|
||||
Subproject commit 03b6b17fee66488fff7f598e444fa99454098767
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 5dd2b440e69b1725fa214b005b7179f2414a4053
|
||||
Subproject commit dee0ab36fac204b9da12d45b66b52e8cfb1fdc08
|
||||
Loading…
Add table
Add a link
Reference in a new issue