mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 10:17:23 +01:00
Update gamedata and services.
This commit is contained in:
parent
36d95c37bc
commit
a982c0a1c1
74 changed files with 907 additions and 960 deletions
|
|
@ -12,9 +12,9 @@ public class CustomizationManager : ICustomizationManager
|
|||
private CustomizationManager()
|
||||
{ }
|
||||
|
||||
public static ICustomizationManager Create(ITextureProvider textures, IDataManager gameData, IPluginLog log)
|
||||
public static ICustomizationManager Create(ITextureProvider textures, IDataManager gameData, IPluginLog log, NpcCustomizeSet npcCustomizeSet)
|
||||
{
|
||||
_options ??= new CustomizationOptions(textures, gameData, log);
|
||||
_options ??= new CustomizationOptions(textures, gameData, log, npcCustomizeSet);
|
||||
return new CustomizationManager();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,240 +1,13 @@
|
|||
using System;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Lumina.Excel;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using OtterGui;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.GameData.Enums;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using Dalamud.Utility;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using Penumbra.GameData;
|
||||
|
||||
namespace Glamourer.Customization;
|
||||
|
||||
public static class CustomizationNpcOptions
|
||||
{
|
||||
public unsafe struct NpcData
|
||||
public static Dictionary<(SubRace, Gender), IReadOnlyList<(CustomizeIndex, CustomizeValue)>> CreateNpcData(CustomizationSet[] sets, NpcCustomizeSet npcCustomizeSet)
|
||||
{
|
||||
public string Name;
|
||||
public Customize Customize;
|
||||
private fixed byte _equip[40];
|
||||
public CharacterWeapon Mainhand;
|
||||
public CharacterWeapon Offhand;
|
||||
public uint Id;
|
||||
public bool VisorToggled;
|
||||
public ObjectKind Kind;
|
||||
|
||||
public ReadOnlySpan<CharacterArmor> Equip
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _equip)
|
||||
{
|
||||
return new ReadOnlySpan<CharacterArmor>((CharacterArmor*)ptr, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string WriteGear()
|
||||
{
|
||||
var sb = new StringBuilder(128);
|
||||
var span = Equip;
|
||||
for (var i = 0; i < 10; ++i)
|
||||
{
|
||||
sb.Append(span[i].Set.Id.ToString("D4"));
|
||||
sb.Append('-');
|
||||
sb.Append(span[i].Variant.Id.ToString("D3"));
|
||||
sb.Append('-');
|
||||
sb.Append(span[i].Stain.Id.ToString("D3"));
|
||||
sb.Append(", ");
|
||||
}
|
||||
|
||||
sb.Append(Mainhand.Set.Id.ToString("D4"));
|
||||
sb.Append('-');
|
||||
sb.Append(Mainhand.Type.Id.ToString("D4"));
|
||||
sb.Append('-');
|
||||
sb.Append(Mainhand.Variant.Id.ToString("D3"));
|
||||
sb.Append('-');
|
||||
sb.Append(Mainhand.Stain.Id.ToString("D4"));
|
||||
sb.Append(", ");
|
||||
sb.Append(Offhand.Set.Id.ToString("D4"));
|
||||
sb.Append('-');
|
||||
sb.Append(Offhand.Type.Id.ToString("D4"));
|
||||
sb.Append('-');
|
||||
sb.Append(Offhand.Variant.Id.ToString("D3"));
|
||||
sb.Append('-');
|
||||
sb.Append(Offhand.Stain.Id.ToString("D3"));
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
internal void Set(int idx, uint value)
|
||||
{
|
||||
fixed (byte* ptr = _equip)
|
||||
{
|
||||
((uint*)ptr)[idx] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool DataEquals(in NpcData other)
|
||||
{
|
||||
if (VisorToggled != other.VisorToggled)
|
||||
return false;
|
||||
|
||||
if (!Customize.Equals(other.Customize))
|
||||
return false;
|
||||
|
||||
if (!Mainhand.Equals(other.Mainhand))
|
||||
return false;
|
||||
|
||||
if (!Offhand.Equals(other.Offhand))
|
||||
return false;
|
||||
|
||||
fixed (byte* ptr1 = _equip, ptr2 = other._equip)
|
||||
{
|
||||
return new ReadOnlySpan<byte>(ptr1, 40).SequenceEqual(new ReadOnlySpan<byte>(ptr2, 40));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ApplyNpcEquip(ref NpcData data, NpcEquip row)
|
||||
{
|
||||
data.Set(0, row.ModelHead | (row.DyeHead.Row << 24));
|
||||
data.Set(1, row.ModelBody | (row.DyeBody.Row << 24));
|
||||
data.Set(2, row.ModelHands | (row.DyeHands.Row << 24));
|
||||
data.Set(3, row.ModelLegs | (row.DyeLegs.Row << 24));
|
||||
data.Set(4, row.ModelFeet | (row.DyeFeet.Row << 24));
|
||||
data.Set(5, row.ModelEars | (row.DyeEars.Row << 24));
|
||||
data.Set(6, row.ModelNeck | (row.DyeNeck.Row << 24));
|
||||
data.Set(7, row.ModelWrists | (row.DyeWrists.Row << 24));
|
||||
data.Set(8, row.ModelRightRing | (row.DyeRightRing.Row << 24));
|
||||
data.Set(9, row.ModelLeftRing | (row.DyeLeftRing.Row << 24));
|
||||
data.Mainhand = new CharacterWeapon(row.ModelMainHand | ((ulong)row.DyeMainHand.Row << 48));
|
||||
data.Offhand = new CharacterWeapon(row.ModelOffHand | ((ulong)row.DyeOffHand.Row << 48));
|
||||
data.VisorToggled = row.Visor;
|
||||
}
|
||||
|
||||
public static unsafe IReadOnlyList<NpcData> CreateNpcData(IReadOnlyDictionary<uint, string> eNpcs,
|
||||
IReadOnlyDictionary<uint, string> bnpcNames, IObjectIdentifier identifier, IDataManager data)
|
||||
{
|
||||
var enpcSheet = data.GetExcelSheet<ENpcBase>()!;
|
||||
var bnpcSheet = data.GetExcelSheet<BNpcBase>()!;
|
||||
var list = new List<NpcData>(eNpcs.Count + (int)bnpcSheet.RowCount);
|
||||
foreach (var (id, name) in eNpcs)
|
||||
{
|
||||
var row = enpcSheet.GetRow(id);
|
||||
if (row == null || name.IsNullOrWhitespace())
|
||||
continue;
|
||||
|
||||
var (valid, customize) = FromEnpcBase(row);
|
||||
if (!valid)
|
||||
continue;
|
||||
|
||||
var ret = new NpcData
|
||||
{
|
||||
Name = name,
|
||||
Customize = customize,
|
||||
Id = id,
|
||||
Kind = ObjectKind.EventNpc,
|
||||
};
|
||||
|
||||
if (row.NpcEquip.Row != 0 && row.NpcEquip.Value is { } equip)
|
||||
{
|
||||
ApplyNpcEquip(ref ret, equip);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.Set(0, row.ModelHead | (row.DyeHead.Row << 24));
|
||||
ret.Set(1, row.ModelBody | (row.DyeBody.Row << 24));
|
||||
ret.Set(2, row.ModelHands | (row.DyeHands.Row << 24));
|
||||
ret.Set(3, row.ModelLegs | (row.DyeLegs.Row << 24));
|
||||
ret.Set(4, row.ModelFeet | (row.DyeFeet.Row << 24));
|
||||
ret.Set(5, row.ModelEars | (row.DyeEars.Row << 24));
|
||||
ret.Set(6, row.ModelNeck | (row.DyeNeck.Row << 24));
|
||||
ret.Set(7, row.ModelWrists | (row.DyeWrists.Row << 24));
|
||||
ret.Set(8, row.ModelRightRing | (row.DyeRightRing.Row << 24));
|
||||
ret.Set(9, row.ModelLeftRing | (row.DyeLeftRing.Row << 24));
|
||||
ret.Mainhand = new CharacterWeapon(row.ModelMainHand | ((ulong)row.DyeMainHand.Row << 48));
|
||||
ret.Offhand = new CharacterWeapon(row.ModelOffHand | ((ulong)row.DyeOffHand.Row << 48));
|
||||
ret.VisorToggled = row.Visor;
|
||||
}
|
||||
|
||||
list.Add(ret);
|
||||
}
|
||||
|
||||
foreach (var baseRow in bnpcSheet)
|
||||
{
|
||||
if (baseRow.ModelChara.Value!.Type != 1)
|
||||
continue;
|
||||
|
||||
var bnpcNameIds = identifier.GetBnpcNames(baseRow.RowId);
|
||||
if (bnpcNameIds.Count == 0)
|
||||
continue;
|
||||
|
||||
var (valid, customize) = FromBnpcCustomize(baseRow.BNpcCustomize.Value!);
|
||||
if (!valid)
|
||||
continue;
|
||||
|
||||
var equip = baseRow.NpcEquip.Value!;
|
||||
var ret = new NpcData
|
||||
{
|
||||
Customize = customize,
|
||||
Id = baseRow.RowId,
|
||||
Kind = ObjectKind.BattleNpc,
|
||||
};
|
||||
ApplyNpcEquip(ref ret, equip);
|
||||
foreach (var bnpcNameId in bnpcNameIds)
|
||||
{
|
||||
if (bnpcNames.TryGetValue(bnpcNameId.Id, out var name) && !name.IsNullOrWhitespace())
|
||||
list.Add(ret with { Name = name });
|
||||
}
|
||||
}
|
||||
|
||||
var groups = list.GroupBy(d => d.Name).ToDictionary(g => g.Key, g => g.ToList());
|
||||
list.Clear();
|
||||
foreach (var (name, duplicates) in groups.OrderBy(kvp => kvp.Key))
|
||||
{
|
||||
for (var i = 0; i < duplicates.Count; ++i)
|
||||
{
|
||||
var current = duplicates[i];
|
||||
var add = true;
|
||||
for (var j = 0; j < i; ++j)
|
||||
{
|
||||
if (current.DataEquals(duplicates[j]))
|
||||
{
|
||||
duplicates.RemoveAt(i--);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (duplicates.Count == 1)
|
||||
list.Add(duplicates[0]);
|
||||
else
|
||||
list.AddRange(duplicates
|
||||
.Select(duplicate => duplicate with { Name = $"{name} ({(duplicate.Kind is ObjectKind.BattleNpc ? 'B' : 'E')}{duplicate.Id})" }));
|
||||
}
|
||||
|
||||
var lastWeird = list.FindIndex(d => char.IsAsciiLetterOrDigit(d.Name[0]));
|
||||
if (lastWeird != -1)
|
||||
{
|
||||
list.AddRange(list.Take(lastWeird));
|
||||
list.RemoveRange(0, lastWeird);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
public static Dictionary<(SubRace, Gender), IReadOnlyList<(CustomizeIndex, CustomizeValue)>> CreateNpcData(CustomizationSet[] sets,
|
||||
ExcelSheet<BNpcCustomize> bNpc, ExcelSheet<ENpcBase> eNpc)
|
||||
{
|
||||
var customizes = bNpc.SelectWhere(FromBnpcCustomize)
|
||||
.Concat(eNpc.SelectWhere(FromEnpcBase)).ToList();
|
||||
|
||||
var dict = new Dictionary<(SubRace, Gender), HashSet<(CustomizeIndex, CustomizeValue)>>();
|
||||
var customizeIndices = new[]
|
||||
{
|
||||
|
|
@ -251,7 +24,7 @@ public static class CustomizationNpcOptions
|
|||
CustomizeIndex.EyeColorRight,
|
||||
};
|
||||
|
||||
foreach (var customize in customizes)
|
||||
foreach (var customize in npcCustomizeSet.Select(s => s.Customize))
|
||||
{
|
||||
var set = sets[CustomizationOptions.ToIndex(customize.Clan, customize.Gender)];
|
||||
foreach (var customizeIndex in customizeIndices)
|
||||
|
|
@ -265,7 +38,7 @@ public static class CustomizationNpcOptions
|
|||
|
||||
if (!dict.TryGetValue((set.Clan, set.Gender), out var npcSet))
|
||||
{
|
||||
npcSet = new HashSet<(CustomizeIndex, CustomizeValue)> { (customizeIndex, value) };
|
||||
npcSet = [(customizeIndex, value)];
|
||||
dict.Add((set.Clan, set.Gender), npcSet);
|
||||
}
|
||||
else
|
||||
|
|
@ -278,85 +51,4 @@ public static class CustomizationNpcOptions
|
|||
return dict.ToDictionary(kvp => kvp.Key,
|
||||
kvp => (IReadOnlyList<(CustomizeIndex, CustomizeValue)>)kvp.Value.OrderBy(p => p.Item1).ThenBy(p => p.Item2.Value).ToArray());
|
||||
}
|
||||
|
||||
private static (bool, Customize) FromBnpcCustomize(BNpcCustomize bnpcCustomize)
|
||||
{
|
||||
var customize = new Customize();
|
||||
customize.Data.Set(0, (byte)bnpcCustomize.Race.Row);
|
||||
customize.Data.Set(1, bnpcCustomize.Gender);
|
||||
customize.Data.Set(2, bnpcCustomize.BodyType);
|
||||
customize.Data.Set(3, bnpcCustomize.Height);
|
||||
customize.Data.Set(4, (byte)bnpcCustomize.Tribe.Row);
|
||||
customize.Data.Set(5, bnpcCustomize.Face);
|
||||
customize.Data.Set(6, bnpcCustomize.HairStyle);
|
||||
customize.Data.Set(7, bnpcCustomize.HairHighlight);
|
||||
customize.Data.Set(8, bnpcCustomize.SkinColor);
|
||||
customize.Data.Set(9, bnpcCustomize.EyeHeterochromia);
|
||||
customize.Data.Set(10, bnpcCustomize.HairColor);
|
||||
customize.Data.Set(11, bnpcCustomize.HairHighlightColor);
|
||||
customize.Data.Set(12, bnpcCustomize.FacialFeature);
|
||||
customize.Data.Set(13, bnpcCustomize.FacialFeatureColor);
|
||||
customize.Data.Set(14, bnpcCustomize.Eyebrows);
|
||||
customize.Data.Set(15, bnpcCustomize.EyeColor);
|
||||
customize.Data.Set(16, bnpcCustomize.EyeShape);
|
||||
customize.Data.Set(17, bnpcCustomize.Nose);
|
||||
customize.Data.Set(18, bnpcCustomize.Jaw);
|
||||
customize.Data.Set(19, bnpcCustomize.Mouth);
|
||||
customize.Data.Set(20, bnpcCustomize.LipColor);
|
||||
customize.Data.Set(21, bnpcCustomize.BustOrTone1);
|
||||
customize.Data.Set(22, bnpcCustomize.ExtraFeature1);
|
||||
customize.Data.Set(23, bnpcCustomize.ExtraFeature2OrBust);
|
||||
customize.Data.Set(24, bnpcCustomize.FacePaint);
|
||||
customize.Data.Set(25, bnpcCustomize.FacePaintColor);
|
||||
|
||||
if (customize.BodyType.Value != 1
|
||||
|| !CustomizationOptions.Races.Contains(customize.Race)
|
||||
|| !CustomizationOptions.Clans.Contains(customize.Clan)
|
||||
|| !CustomizationOptions.Genders.Contains(customize.Gender))
|
||||
return (false, Customize.Default);
|
||||
|
||||
return (true, customize);
|
||||
}
|
||||
|
||||
private static (bool, Customize) FromEnpcBase(ENpcBase enpcBase)
|
||||
{
|
||||
if (enpcBase.ModelChara.Value?.Type != 1)
|
||||
return (false, Customize.Default);
|
||||
|
||||
var customize = new Customize();
|
||||
customize.Data.Set(0, (byte)enpcBase.Race.Row);
|
||||
customize.Data.Set(1, enpcBase.Gender);
|
||||
customize.Data.Set(2, enpcBase.BodyType);
|
||||
customize.Data.Set(3, enpcBase.Height);
|
||||
customize.Data.Set(4, (byte)enpcBase.Tribe.Row);
|
||||
customize.Data.Set(5, enpcBase.Face);
|
||||
customize.Data.Set(6, enpcBase.HairStyle);
|
||||
customize.Data.Set(7, enpcBase.HairHighlight);
|
||||
customize.Data.Set(8, enpcBase.SkinColor);
|
||||
customize.Data.Set(9, enpcBase.EyeHeterochromia);
|
||||
customize.Data.Set(10, enpcBase.HairColor);
|
||||
customize.Data.Set(11, enpcBase.HairHighlightColor);
|
||||
customize.Data.Set(12, enpcBase.FacialFeature);
|
||||
customize.Data.Set(13, enpcBase.FacialFeatureColor);
|
||||
customize.Data.Set(14, enpcBase.Eyebrows);
|
||||
customize.Data.Set(15, enpcBase.EyeColor);
|
||||
customize.Data.Set(16, enpcBase.EyeShape);
|
||||
customize.Data.Set(17, enpcBase.Nose);
|
||||
customize.Data.Set(18, enpcBase.Jaw);
|
||||
customize.Data.Set(19, enpcBase.Mouth);
|
||||
customize.Data.Set(20, enpcBase.LipColor);
|
||||
customize.Data.Set(21, enpcBase.BustOrTone1);
|
||||
customize.Data.Set(22, enpcBase.ExtraFeature1);
|
||||
customize.Data.Set(23, enpcBase.ExtraFeature2OrBust);
|
||||
customize.Data.Set(24, enpcBase.FacePaint);
|
||||
customize.Data.Set(25, enpcBase.FacePaintColor);
|
||||
|
||||
if (customize.BodyType.Value != 1
|
||||
|| !CustomizationOptions.Races.Contains(customize.Race)
|
||||
|| !CustomizationOptions.Clans.Contains(customize.Clan)
|
||||
|| !CustomizationOptions.Genders.Contains(customize.Gender))
|
||||
return (false, Customize.Default);
|
||||
|
||||
return (true, customize);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ public partial class CustomizationOptions
|
|||
public string GetName(CustomName name)
|
||||
=> _names[(int)name];
|
||||
|
||||
internal CustomizationOptions(ITextureProvider textures, IDataManager gameData, IPluginLog log)
|
||||
internal CustomizationOptions(ITextureProvider textures, IDataManager gameData, IPluginLog log, NpcCustomizeSet npcCustomizeSet)
|
||||
{
|
||||
var tmp = new TemporaryData(gameData, this, log);
|
||||
_icons = new IconStorage(textures, gameData);
|
||||
|
|
@ -73,7 +73,7 @@ public partial class CustomizationOptions
|
|||
_customizationSets[ToIndex(race, gender)] = tmp.GetSet(race, gender);
|
||||
}
|
||||
|
||||
tmp.SetNpcData(_customizationSets);
|
||||
tmp.SetNpcData(_customizationSets, npcCustomizeSet);
|
||||
}
|
||||
|
||||
// Obtain localized names of customization options and race names from the game data.
|
||||
|
|
@ -163,9 +163,9 @@ public partial class CustomizationOptions
|
|||
return set;
|
||||
}
|
||||
|
||||
public void SetNpcData(CustomizationSet[] sets)
|
||||
public void SetNpcData(CustomizationSet[] sets, NpcCustomizeSet npcCustomizeSet)
|
||||
{
|
||||
var data = CustomizationNpcOptions.CreateNpcData(sets, _bnpcCustomize, _enpcBase);
|
||||
var data = CustomizationNpcOptions.CreateNpcData(sets, npcCustomizeSet);
|
||||
foreach (var set in sets)
|
||||
{
|
||||
if (data.TryGetValue((set.Clan, set.Gender), out var npcData))
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
using System;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Customization;
|
||||
|
||||
public unsafe struct Customize
|
||||
{
|
||||
public Penumbra.GameData.Structs.CustomizeData Data;
|
||||
public CustomizeArray Data;
|
||||
|
||||
public Customize(in Penumbra.GameData.Structs.CustomizeData data)
|
||||
public Customize(in CustomizeArray data)
|
||||
{
|
||||
Data = data.Clone();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,14 +144,14 @@ public static class CustomizationExtensions
|
|||
};
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static unsafe CustomizeValue Get(this in Penumbra.GameData.Structs.CustomizeData data, CustomizeIndex index)
|
||||
public static unsafe CustomizeValue Get(this in Penumbra.GameData.Structs.CustomizeArray data, CustomizeIndex index)
|
||||
{
|
||||
var (offset, mask) = index.ToByteAndMask();
|
||||
return (CustomizeValue)(data.Data[offset] & mask);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static unsafe bool Set(this ref Penumbra.GameData.Structs.CustomizeData data, CustomizeIndex index, CustomizeValue value)
|
||||
public static unsafe bool Set(this ref Penumbra.GameData.Structs.CustomizeArray data, CustomizeIndex index, CustomizeValue value)
|
||||
{
|
||||
var (offset, mask) = index.ToByteAndMask();
|
||||
return mask != 0xFF
|
||||
|
|
|
|||
|
|
@ -3,13 +3,14 @@ using System.IO;
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Dalamud.Memory;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Customization;
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = Size)]
|
||||
public unsafe struct DatCharacterFile
|
||||
{
|
||||
public const int Size = 4 + 4 + 4 + 4 + Penumbra.GameData.Structs.CustomizeData.Size + 2 + 4 + 41 * 4; // 212
|
||||
public const int Size = 4 + 4 + 4 + 4 + CustomizeArray.Size + 2 + 4 + 41 * 4; // 212
|
||||
|
||||
[FieldOffset(0)]
|
||||
private fixed byte _data[Size];
|
||||
|
|
@ -27,12 +28,12 @@ public unsafe struct DatCharacterFile
|
|||
private readonly uint _padding = 0;
|
||||
|
||||
[FieldOffset(16)]
|
||||
private Penumbra.GameData.Structs.CustomizeData _customize;
|
||||
private CustomizeArray _customize;
|
||||
|
||||
[FieldOffset(16 + Penumbra.GameData.Structs.CustomizeData.Size)]
|
||||
[FieldOffset(16 + CustomizeArray.Size)]
|
||||
private ushort _voice;
|
||||
|
||||
[FieldOffset(16 + Penumbra.GameData.Structs.CustomizeData.Size + 2)]
|
||||
[FieldOffset(16 + CustomizeArray.Size + 2)]
|
||||
private uint _timeStamp;
|
||||
|
||||
[FieldOffset(Size - 41 * 4)]
|
||||
|
|
|
|||
282
Glamourer.GameData/Customization/NpcCustomizeSet.cs
Normal file
282
Glamourer.GameData/Customization/NpcCustomizeSet.cs
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Customization;
|
||||
|
||||
public class NpcCustomizeSet : IAsyncDataContainer, IReadOnlyList<NpcData>
|
||||
{
|
||||
public string Name
|
||||
=> nameof(NpcCustomizeSet);
|
||||
|
||||
private readonly List<NpcData> _data = [];
|
||||
|
||||
public long Time { get; private set; }
|
||||
public long Memory { get; private set; }
|
||||
public int TotalCount
|
||||
=> _data.Count;
|
||||
|
||||
public Task Awaiter { get; }
|
||||
|
||||
public NpcCustomizeSet(IDataManager data, DictENpc eNpcs, DictBNpc bNpcs, DictBNpcNames bNpcNames)
|
||||
{
|
||||
var waitTask = Task.WhenAll(eNpcs.Awaiter, bNpcs.Awaiter, bNpcNames.Awaiter);
|
||||
Awaiter = waitTask.ContinueWith(_ =>
|
||||
{
|
||||
var watch = Stopwatch.StartNew();
|
||||
var eNpcTask = Task.Run(() => CreateEnpcData(data, eNpcs));
|
||||
var bNpcTask = Task.Run(() => CreateBnpcData(data, bNpcs, bNpcNames));
|
||||
FilterAndOrderNpcData(eNpcTask.Result, bNpcTask.Result);
|
||||
Time = watch.ElapsedMilliseconds;
|
||||
});
|
||||
}
|
||||
|
||||
private static List<NpcData> CreateEnpcData(IDataManager data, DictENpc eNpcs)
|
||||
{
|
||||
var enpcSheet = data.GetExcelSheet<ENpcBase>()!;
|
||||
var list = new List<NpcData>(eNpcs.Count);
|
||||
|
||||
foreach (var (id, name) in eNpcs)
|
||||
{
|
||||
var row = enpcSheet.GetRow(id.Id);
|
||||
if (row == null || name.IsNullOrWhitespace())
|
||||
continue;
|
||||
|
||||
var (valid, customize) = FromEnpcBase(row);
|
||||
if (!valid)
|
||||
continue;
|
||||
|
||||
var ret = new NpcData
|
||||
{
|
||||
Name = name,
|
||||
Customize = customize,
|
||||
Id = id,
|
||||
Kind = ObjectKind.EventNpc,
|
||||
};
|
||||
|
||||
if (row.NpcEquip.Row != 0 && row.NpcEquip.Value is { } equip)
|
||||
{
|
||||
ApplyNpcEquip(ref ret, equip);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.Set(0, row.ModelHead | (row.DyeHead.Row << 24));
|
||||
ret.Set(1, row.ModelBody | (row.DyeBody.Row << 24));
|
||||
ret.Set(2, row.ModelHands | (row.DyeHands.Row << 24));
|
||||
ret.Set(3, row.ModelLegs | (row.DyeLegs.Row << 24));
|
||||
ret.Set(4, row.ModelFeet | (row.DyeFeet.Row << 24));
|
||||
ret.Set(5, row.ModelEars | (row.DyeEars.Row << 24));
|
||||
ret.Set(6, row.ModelNeck | (row.DyeNeck.Row << 24));
|
||||
ret.Set(7, row.ModelWrists | (row.DyeWrists.Row << 24));
|
||||
ret.Set(8, row.ModelRightRing | (row.DyeRightRing.Row << 24));
|
||||
ret.Set(9, row.ModelLeftRing | (row.DyeLeftRing.Row << 24));
|
||||
ret.Mainhand = new CharacterWeapon(row.ModelMainHand | ((ulong)row.DyeMainHand.Row << 48));
|
||||
ret.Offhand = new CharacterWeapon(row.ModelOffHand | ((ulong)row.DyeOffHand.Row << 48));
|
||||
ret.VisorToggled = row.Visor;
|
||||
}
|
||||
|
||||
list.Add(ret);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private static List<NpcData> CreateBnpcData(IDataManager data, DictBNpc bNpcs, DictBNpcNames bNpcNames)
|
||||
{
|
||||
var bnpcSheet = data.GetExcelSheet<BNpcBase>()!;
|
||||
var list = new List<NpcData>((int)bnpcSheet.RowCount);
|
||||
foreach (var baseRow in bnpcSheet)
|
||||
{
|
||||
if (baseRow.ModelChara.Value!.Type != 1)
|
||||
continue;
|
||||
|
||||
var bnpcNameIds = bNpcNames[baseRow.RowId];
|
||||
if (bnpcNameIds.Count == 0)
|
||||
continue;
|
||||
|
||||
var (valid, customize) = FromBnpcCustomize(baseRow.BNpcCustomize.Value!);
|
||||
if (!valid)
|
||||
continue;
|
||||
|
||||
var equip = baseRow.NpcEquip.Value!;
|
||||
var ret = new NpcData
|
||||
{
|
||||
Customize = customize,
|
||||
Id = baseRow.RowId,
|
||||
Kind = ObjectKind.BattleNpc,
|
||||
};
|
||||
ApplyNpcEquip(ref ret, equip);
|
||||
foreach (var bnpcNameId in bnpcNameIds)
|
||||
{
|
||||
if (bNpcs.TryGetValue(bnpcNameId.Id, out var name) && !name.IsNullOrWhitespace())
|
||||
list.Add(ret with { Name = name });
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private void FilterAndOrderNpcData(List<NpcData> eNpcEquip, List<NpcData> bNpcEquip)
|
||||
{
|
||||
_data.Clear();
|
||||
_data.EnsureCapacity(eNpcEquip.Count + bNpcEquip.Count);
|
||||
var groups = eNpcEquip.Concat(bNpcEquip).GroupBy(d => d.Name).ToDictionary(g => g.Key, g => g.ToList());
|
||||
foreach (var (name, duplicates) in groups.OrderBy(kvp => kvp.Key))
|
||||
{
|
||||
for (var i = 0; i < duplicates.Count; ++i)
|
||||
{
|
||||
var current = duplicates[i];
|
||||
for (var j = 0; j < i; ++j)
|
||||
{
|
||||
if (current.DataEquals(duplicates[j]))
|
||||
{
|
||||
duplicates.RemoveAt(i--);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (duplicates.Count == 1)
|
||||
{
|
||||
_data.Add(duplicates[0]);
|
||||
Memory += 96;
|
||||
}
|
||||
else
|
||||
{
|
||||
_data.AddRange(duplicates
|
||||
.Select(duplicate => duplicate with
|
||||
{
|
||||
Name = $"{name} ({(duplicate.Kind is ObjectKind.BattleNpc ? 'B' : 'E')}{duplicate.Id})"
|
||||
}));
|
||||
Memory += 96 * duplicates.Count + duplicates.Sum(d => d.Name.Length * 2);
|
||||
}
|
||||
}
|
||||
|
||||
var lastWeird = _data.FindIndex(d => char.IsAsciiLetterOrDigit(d.Name[0]));
|
||||
if (lastWeird != -1)
|
||||
{
|
||||
_data.AddRange(_data.Take(lastWeird));
|
||||
_data.RemoveRange(0, lastWeird);
|
||||
}
|
||||
_data.TrimExcess();
|
||||
}
|
||||
|
||||
private static void ApplyNpcEquip(ref NpcData data, NpcEquip row)
|
||||
{
|
||||
data.Set(0, row.ModelHead | (row.DyeHead.Row << 24));
|
||||
data.Set(1, row.ModelBody | (row.DyeBody.Row << 24));
|
||||
data.Set(2, row.ModelHands | (row.DyeHands.Row << 24));
|
||||
data.Set(3, row.ModelLegs | (row.DyeLegs.Row << 24));
|
||||
data.Set(4, row.ModelFeet | (row.DyeFeet.Row << 24));
|
||||
data.Set(5, row.ModelEars | (row.DyeEars.Row << 24));
|
||||
data.Set(6, row.ModelNeck | (row.DyeNeck.Row << 24));
|
||||
data.Set(7, row.ModelWrists | (row.DyeWrists.Row << 24));
|
||||
data.Set(8, row.ModelRightRing | (row.DyeRightRing.Row << 24));
|
||||
data.Set(9, row.ModelLeftRing | (row.DyeLeftRing.Row << 24));
|
||||
data.Mainhand = new CharacterWeapon(row.ModelMainHand | ((ulong)row.DyeMainHand.Row << 48));
|
||||
data.Offhand = new CharacterWeapon(row.ModelOffHand | ((ulong)row.DyeOffHand.Row << 48));
|
||||
data.VisorToggled = row.Visor;
|
||||
}
|
||||
|
||||
private static (bool, Customize) FromBnpcCustomize(BNpcCustomize bnpcCustomize)
|
||||
{
|
||||
var customize = new Customize();
|
||||
customize.Data.Set(0, (byte)bnpcCustomize.Race.Row);
|
||||
customize.Data.Set(1, bnpcCustomize.Gender);
|
||||
customize.Data.Set(2, bnpcCustomize.BodyType);
|
||||
customize.Data.Set(3, bnpcCustomize.Height);
|
||||
customize.Data.Set(4, (byte)bnpcCustomize.Tribe.Row);
|
||||
customize.Data.Set(5, bnpcCustomize.Face);
|
||||
customize.Data.Set(6, bnpcCustomize.HairStyle);
|
||||
customize.Data.Set(7, bnpcCustomize.HairHighlight);
|
||||
customize.Data.Set(8, bnpcCustomize.SkinColor);
|
||||
customize.Data.Set(9, bnpcCustomize.EyeHeterochromia);
|
||||
customize.Data.Set(10, bnpcCustomize.HairColor);
|
||||
customize.Data.Set(11, bnpcCustomize.HairHighlightColor);
|
||||
customize.Data.Set(12, bnpcCustomize.FacialFeature);
|
||||
customize.Data.Set(13, bnpcCustomize.FacialFeatureColor);
|
||||
customize.Data.Set(14, bnpcCustomize.Eyebrows);
|
||||
customize.Data.Set(15, bnpcCustomize.EyeColor);
|
||||
customize.Data.Set(16, bnpcCustomize.EyeShape);
|
||||
customize.Data.Set(17, bnpcCustomize.Nose);
|
||||
customize.Data.Set(18, bnpcCustomize.Jaw);
|
||||
customize.Data.Set(19, bnpcCustomize.Mouth);
|
||||
customize.Data.Set(20, bnpcCustomize.LipColor);
|
||||
customize.Data.Set(21, bnpcCustomize.BustOrTone1);
|
||||
customize.Data.Set(22, bnpcCustomize.ExtraFeature1);
|
||||
customize.Data.Set(23, bnpcCustomize.ExtraFeature2OrBust);
|
||||
customize.Data.Set(24, bnpcCustomize.FacePaint);
|
||||
customize.Data.Set(25, bnpcCustomize.FacePaintColor);
|
||||
|
||||
if (customize.BodyType.Value != 1
|
||||
|| !CustomizationOptions.Races.Contains(customize.Race)
|
||||
|| !CustomizationOptions.Clans.Contains(customize.Clan)
|
||||
|| !CustomizationOptions.Genders.Contains(customize.Gender))
|
||||
return (false, Customize.Default);
|
||||
|
||||
return (true, customize);
|
||||
}
|
||||
|
||||
private static (bool, Customize) FromEnpcBase(ENpcBase enpcBase)
|
||||
{
|
||||
if (enpcBase.ModelChara.Value?.Type != 1)
|
||||
return (false, Customize.Default);
|
||||
|
||||
var customize = new Customize();
|
||||
customize.Data.Set(0, (byte)enpcBase.Race.Row);
|
||||
customize.Data.Set(1, enpcBase.Gender);
|
||||
customize.Data.Set(2, enpcBase.BodyType);
|
||||
customize.Data.Set(3, enpcBase.Height);
|
||||
customize.Data.Set(4, (byte)enpcBase.Tribe.Row);
|
||||
customize.Data.Set(5, enpcBase.Face);
|
||||
customize.Data.Set(6, enpcBase.HairStyle);
|
||||
customize.Data.Set(7, enpcBase.HairHighlight);
|
||||
customize.Data.Set(8, enpcBase.SkinColor);
|
||||
customize.Data.Set(9, enpcBase.EyeHeterochromia);
|
||||
customize.Data.Set(10, enpcBase.HairColor);
|
||||
customize.Data.Set(11, enpcBase.HairHighlightColor);
|
||||
customize.Data.Set(12, enpcBase.FacialFeature);
|
||||
customize.Data.Set(13, enpcBase.FacialFeatureColor);
|
||||
customize.Data.Set(14, enpcBase.Eyebrows);
|
||||
customize.Data.Set(15, enpcBase.EyeColor);
|
||||
customize.Data.Set(16, enpcBase.EyeShape);
|
||||
customize.Data.Set(17, enpcBase.Nose);
|
||||
customize.Data.Set(18, enpcBase.Jaw);
|
||||
customize.Data.Set(19, enpcBase.Mouth);
|
||||
customize.Data.Set(20, enpcBase.LipColor);
|
||||
customize.Data.Set(21, enpcBase.BustOrTone1);
|
||||
customize.Data.Set(22, enpcBase.ExtraFeature1);
|
||||
customize.Data.Set(23, enpcBase.ExtraFeature2OrBust);
|
||||
customize.Data.Set(24, enpcBase.FacePaint);
|
||||
customize.Data.Set(25, enpcBase.FacePaintColor);
|
||||
|
||||
if (customize.BodyType.Value != 1
|
||||
|| !CustomizationOptions.Races.Contains(customize.Race)
|
||||
|| !CustomizationOptions.Clans.Contains(customize.Clan)
|
||||
|| !CustomizationOptions.Genders.Contains(customize.Gender))
|
||||
return (false, Customize.Default);
|
||||
|
||||
return (true, customize);
|
||||
}
|
||||
|
||||
public IEnumerator<NpcData> GetEnumerator()
|
||||
=> _data.GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
=> GetEnumerator();
|
||||
|
||||
public int Count
|
||||
=> _data.Count;
|
||||
|
||||
public NpcData this[int index]
|
||||
=> _data[index];
|
||||
}
|
||||
89
Glamourer.GameData/Customization/NpcData.cs
Normal file
89
Glamourer.GameData/Customization/NpcData.cs
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Customization;
|
||||
|
||||
public unsafe struct NpcData
|
||||
{
|
||||
public string Name;
|
||||
public Customize Customize;
|
||||
private fixed byte _equip[40];
|
||||
public CharacterWeapon Mainhand;
|
||||
public CharacterWeapon Offhand;
|
||||
public NpcId Id;
|
||||
public bool VisorToggled;
|
||||
public ObjectKind Kind;
|
||||
|
||||
public ReadOnlySpan<CharacterArmor> Equip
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _equip)
|
||||
{
|
||||
return new ReadOnlySpan<CharacterArmor>((CharacterArmor*)ptr, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string WriteGear()
|
||||
{
|
||||
var sb = new StringBuilder(128);
|
||||
var span = Equip;
|
||||
for (var i = 0; i < 10; ++i)
|
||||
{
|
||||
sb.Append(span[i].Set.Id.ToString("D4"));
|
||||
sb.Append('-');
|
||||
sb.Append(span[i].Variant.Id.ToString("D3"));
|
||||
sb.Append('-');
|
||||
sb.Append(span[i].Stain.Id.ToString("D3"));
|
||||
sb.Append(", ");
|
||||
}
|
||||
|
||||
sb.Append(Mainhand.Skeleton.Id.ToString("D4"));
|
||||
sb.Append('-');
|
||||
sb.Append(Mainhand.Weapon.Id.ToString("D4"));
|
||||
sb.Append('-');
|
||||
sb.Append(Mainhand.Variant.Id.ToString("D3"));
|
||||
sb.Append('-');
|
||||
sb.Append(Mainhand.Stain.Id.ToString("D4"));
|
||||
sb.Append(", ");
|
||||
sb.Append(Offhand.Skeleton.Id.ToString("D4"));
|
||||
sb.Append('-');
|
||||
sb.Append(Offhand.Weapon.Id.ToString("D4"));
|
||||
sb.Append('-');
|
||||
sb.Append(Offhand.Variant.Id.ToString("D3"));
|
||||
sb.Append('-');
|
||||
sb.Append(Offhand.Stain.Id.ToString("D3"));
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
internal void Set(int idx, uint value)
|
||||
{
|
||||
fixed (byte* ptr = _equip)
|
||||
{
|
||||
((uint*)ptr)[idx] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool DataEquals(in NpcData other)
|
||||
{
|
||||
if (VisorToggled != other.VisorToggled)
|
||||
return false;
|
||||
|
||||
if (!Customize.Equals(other.Customize))
|
||||
return false;
|
||||
|
||||
if (!Mainhand.Equals(other.Mainhand))
|
||||
return false;
|
||||
|
||||
if (!Offhand.Equals(other.Offhand))
|
||||
return false;
|
||||
|
||||
fixed (byte* ptr1 = _equip, ptr2 = other._equip)
|
||||
{
|
||||
return new ReadOnlySpan<byte>(ptr1, 40).SequenceEqual(new ReadOnlySpan<byte>(ptr2, 40));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,10 +7,10 @@ using Glamourer.Automation;
|
|||
using Glamourer.Designs;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.State;
|
||||
using Penumbra.Api.Helpers;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.String;
|
||||
|
||||
namespace Glamourer.Api;
|
||||
|
|
@ -22,11 +22,11 @@ public partial class GlamourerIpc : IDisposable
|
|||
|
||||
private readonly StateManager _stateManager;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly ActorService _actors;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly DesignConverter _designConverter;
|
||||
private readonly AutoDesignApplier _autoDesignApplier;
|
||||
|
||||
public GlamourerIpc(DalamudPluginInterface pi, StateManager stateManager, ObjectManager objects, ActorService actors,
|
||||
public GlamourerIpc(DalamudPluginInterface pi, StateManager stateManager, ObjectManager objects, ActorManager actors,
|
||||
DesignConverter designConverter, StateChanged stateChangedEvent, GPoseService gPose, AutoDesignApplier autoDesignApplier)
|
||||
{
|
||||
_stateManager = stateManager;
|
||||
|
|
@ -142,7 +142,7 @@ public partial class GlamourerIpc : IDisposable
|
|||
|
||||
private IEnumerable<ActorIdentifier> FindActors(Character? character)
|
||||
{
|
||||
var id = _actors.AwaitedService.FromObject(character, true, true, false);
|
||||
var id = _actors.FromObject(character, true, true, false);
|
||||
if (!id.IsValid)
|
||||
yield break;
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ using Glamourer.Structs;
|
|||
using Glamourer.Unlocks;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ public class AutoDesignApplier : IDisposable
|
|||
private readonly StateManager _state;
|
||||
private readonly JobService _jobs;
|
||||
private readonly EquippedGearset _equippedGearset;
|
||||
private readonly ActorService _actors;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly CustomizationService _customizations;
|
||||
private readonly CustomizeUnlockManager _customizeUnlocks;
|
||||
private readonly ItemUnlockManager _itemUnlocks;
|
||||
|
|
@ -50,7 +50,7 @@ public class AutoDesignApplier : IDisposable
|
|||
}
|
||||
|
||||
public AutoDesignApplier(Configuration config, AutoDesignManager manager, StateManager state, JobService jobs,
|
||||
CustomizationService customizations, ActorService actors, ItemUnlockManager itemUnlocks, CustomizeUnlockManager customizeUnlocks,
|
||||
CustomizationService customizations, ActorManager actors, ItemUnlockManager itemUnlocks, CustomizeUnlockManager customizeUnlocks,
|
||||
AutomationChanged @event, ObjectManager objects, WeaponLoading weapons, HumanModelList humans, IClientState clientState,
|
||||
EquippedGearset equippedGearset)
|
||||
{
|
||||
|
|
@ -87,7 +87,7 @@ public class AutoDesignApplier : IDisposable
|
|||
if (_jobChangeState == null || !_config.EnableAutoDesigns)
|
||||
return;
|
||||
|
||||
var id = actor.GetIdentifier(_actors.AwaitedService);
|
||||
var id = actor.GetIdentifier(_actors);
|
||||
if (id == _jobChangeState.Identifier)
|
||||
{
|
||||
var current = _jobChangeState.BaseData.Item(slot);
|
||||
|
|
@ -161,7 +161,7 @@ public class AutoDesignApplier : IDisposable
|
|||
{
|
||||
foreach (var actor in data.Objects)
|
||||
{
|
||||
var specificId = actor.GetIdentifier(_actors.AwaitedService);
|
||||
var specificId = actor.GetIdentifier(_actors);
|
||||
if (_state.GetOrCreate(specificId, actor, out var state))
|
||||
{
|
||||
Reduce(actor, state, newSet, false, false);
|
||||
|
|
@ -203,7 +203,7 @@ public class AutoDesignApplier : IDisposable
|
|||
|
||||
private void OnJobChange(Actor actor, Job oldJob, Job newJob)
|
||||
{
|
||||
if (!_config.EnableAutoDesigns || !actor.Identifier(_actors.AwaitedService, out var id))
|
||||
if (!_config.EnableAutoDesigns || !actor.Identifier(_actors, out var id))
|
||||
return;
|
||||
|
||||
if (!GetPlayerSet(id, out var set))
|
||||
|
|
@ -312,13 +312,13 @@ public class AutoDesignApplier : IDisposable
|
|||
if (_manager.EnabledSets.TryGetValue(identifier, out set))
|
||||
return true;
|
||||
|
||||
identifier = _actors.AwaitedService.CreatePlayer(identifier.PlayerName, ushort.MaxValue);
|
||||
identifier = _actors.CreatePlayer(identifier.PlayerName, ushort.MaxValue);
|
||||
return _manager.EnabledSets.TryGetValue(identifier, out set);
|
||||
case IdentifierType.Retainer:
|
||||
case IdentifierType.Npc:
|
||||
return _manager.EnabledSets.TryGetValue(identifier, out set);
|
||||
case IdentifierType.Owned:
|
||||
identifier = _actors.AwaitedService.CreateNpc(identifier.Kind, identifier.DataId);
|
||||
identifier = _actors.CreateNpc(identifier.Kind, identifier.DataId);
|
||||
return _manager.EnabledSets.TryGetValue(identifier, out set);
|
||||
default:
|
||||
set = null;
|
||||
|
|
@ -470,7 +470,7 @@ public class AutoDesignApplier : IDisposable
|
|||
totalCustomizeFlags |= CustomizeFlag.Face;
|
||||
}
|
||||
|
||||
var set = _customizations.AwaitedService.GetList(state.ModelData.Customize.Clan, state.ModelData.Customize.Gender);
|
||||
var set = _customizations.Service.GetList(state.ModelData.Customize.Clan, state.ModelData.Customize.Gender);
|
||||
var face = state.ModelData.Customize.Face;
|
||||
foreach (var index in Enum.GetValues<CustomizeIndex>())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ using OtterGui;
|
|||
using OtterGui.Classes;
|
||||
using OtterGui.Filesystem;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Automation;
|
||||
|
||||
|
|
@ -28,17 +30,17 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
|
|||
|
||||
private readonly JobService _jobs;
|
||||
private readonly DesignManager _designs;
|
||||
private readonly ActorService _actors;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly AutomationChanged _event;
|
||||
private readonly DesignChanged _designEvent;
|
||||
|
||||
private readonly List<AutoDesignSet> _data = new();
|
||||
private readonly Dictionary<ActorIdentifier, AutoDesignSet> _enabled = new();
|
||||
private readonly List<AutoDesignSet> _data = [];
|
||||
private readonly Dictionary<ActorIdentifier, AutoDesignSet> _enabled = [];
|
||||
|
||||
public IReadOnlyDictionary<ActorIdentifier, AutoDesignSet> EnabledSets
|
||||
=> _enabled;
|
||||
|
||||
public AutoDesignManager(JobService jobs, ActorService actors, SaveService saveService, DesignManager designs, AutomationChanged @event,
|
||||
public AutoDesignManager(JobService jobs, ActorManager actors, SaveService saveService, DesignManager designs, AutomationChanged @event,
|
||||
FixedDesignMigrator migrator, DesignFileSystem fileSystem, DesignChanged designEvent)
|
||||
{
|
||||
_jobs = jobs;
|
||||
|
|
@ -419,7 +421,7 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
|
|||
continue;
|
||||
}
|
||||
|
||||
var id = _actors.AwaitedService.FromJson(obj["Identifier"] as JObject);
|
||||
var id = _actors.FromJson(obj["Identifier"] as JObject);
|
||||
if (!IdentifierValid(id, out var group))
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage("Skipped loading Automation Set: Invalid Identifier.", NotificationType.Warning);
|
||||
|
|
@ -562,9 +564,9 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
|
|||
var name = manager.Data.ToName(identifier.Kind, identifier.DataId);
|
||||
var table = identifier.Kind switch
|
||||
{
|
||||
ObjectKind.BattleNpc => manager.Data.BNpcs,
|
||||
ObjectKind.BattleNpc => (IReadOnlyDictionary<NpcId, string>)manager.Data.BNpcs,
|
||||
ObjectKind.EventNpc => manager.Data.ENpcs,
|
||||
_ => new Dictionary<uint, string>(),
|
||||
_ => new Dictionary<NpcId, string>(),
|
||||
};
|
||||
return table.Where(kvp => kvp.Value == name)
|
||||
.Select(kvp => manager.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, identifier.HomeWorld.Id,
|
||||
|
|
@ -580,12 +582,12 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
|
|||
},
|
||||
IdentifierType.Retainer => new[]
|
||||
{
|
||||
_actors.AwaitedService.CreateRetainer(identifier.PlayerName,
|
||||
_actors.CreateRetainer(identifier.PlayerName,
|
||||
identifier.Retainer == ActorIdentifier.RetainerType.Mannequin
|
||||
? ActorIdentifier.RetainerType.Mannequin
|
||||
: ActorIdentifier.RetainerType.Bell).CreatePermanent(),
|
||||
},
|
||||
IdentifierType.Npc => CreateNpcs(_actors.AwaitedService, identifier),
|
||||
IdentifierType.Npc => CreateNpcs(_actors, identifier),
|
||||
_ => Array.Empty<ActorIdentifier>(),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public class FixedDesignMigrator
|
|||
public FixedDesignMigrator(JobService jobs)
|
||||
=> _jobs = jobs;
|
||||
|
||||
public void ConsumeMigratedData(ActorService actors, DesignFileSystem designFileSystem, AutoDesignManager autoManager)
|
||||
public void ConsumeMigratedData(ActorManager actors, DesignFileSystem designFileSystem, AutoDesignManager autoManager)
|
||||
{
|
||||
if (_migratedData == null)
|
||||
return;
|
||||
|
|
@ -35,15 +35,15 @@ public class FixedDesignMigrator
|
|||
var id = ActorIdentifier.Invalid;
|
||||
if (ByteString.FromString(data.Name, out var byteString, false))
|
||||
{
|
||||
id = actors.AwaitedService.CreatePlayer(byteString, ushort.MaxValue);
|
||||
id = actors.CreatePlayer(byteString, ushort.MaxValue);
|
||||
if (!id.IsValid)
|
||||
id = actors.AwaitedService.CreateRetainer(byteString, ActorIdentifier.RetainerType.Both);
|
||||
id = actors.CreateRetainer(byteString, ActorIdentifier.RetainerType.Both);
|
||||
}
|
||||
|
||||
if (!id.IsValid)
|
||||
{
|
||||
byteString = ByteString.FromSpanUnsafe("Mig Ration"u8, true, false, true);
|
||||
id = actors.AwaitedService.CreatePlayer(byteString, actors.AwaitedService.Data.Worlds.First().Key);
|
||||
id = actors.CreatePlayer(byteString, actors.Data.Worlds.First().Key);
|
||||
if (!id.IsValid)
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage($"Could not migrate fixed design {data.Name}.", NotificationType.Error);
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ using Glamourer.Services;
|
|||
using Glamourer.Structs;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
|
||||
namespace Glamourer.Designs;
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ public class DesignBase
|
|||
return false;
|
||||
|
||||
_designData.Customize.Load(customize);
|
||||
CustomizationSet = customizationService.AwaitedService.GetList(customize.Clan, customize.Gender);
|
||||
CustomizationSet = customizationService.Service.GetList(customize.Clan, customize.Gender);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -243,8 +243,8 @@ public class DesignBase
|
|||
|
||||
private CustomizationSet SetCustomizationSet(CustomizationService customize)
|
||||
=> !_designData.IsHuman
|
||||
? customize.AwaitedService.GetList(SubRace.Midlander, Gender.Male)
|
||||
: customize.AwaitedService.GetList(_designData.Customize.Clan, _designData.Customize.Gender);
|
||||
? customize.Service.GetList(SubRace.Midlander, Gender.Male)
|
||||
: customize.Service.GetList(_designData.Customize.Clan, _designData.Customize.Gender);
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ using Glamourer.Customization;
|
|||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using OtterGui;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
|
|
@ -121,9 +121,9 @@ public class DesignBase64Migration
|
|||
data.SetStain(slot, mdl.Stain);
|
||||
}
|
||||
|
||||
var main = cur[0].Set.Id == 0
|
||||
var main = cur[0].X.Id == 0
|
||||
? items.DefaultSword
|
||||
: items.Identify(EquipSlot.MainHand, cur[0].Set, cur[0].Type, cur[0].Variant);
|
||||
: items.Identify(EquipSlot.MainHand, cur[0].X, cur[0].Y, cur[0].Variant);
|
||||
if (!main.Valid)
|
||||
{
|
||||
Glamourer.Log.Warning("Base64 string invalid, weapon could not be identified.");
|
||||
|
|
@ -135,10 +135,10 @@ public class DesignBase64Migration
|
|||
|
||||
EquipItem off;
|
||||
// Fist weapon hack
|
||||
if (main.ModelId.Id is > 1600 and < 1651 && cur[1].Variant == 0)
|
||||
if (main.PrimaryId.Id is > 1600 and < 1651 && cur[1].Variant == 0)
|
||||
{
|
||||
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);
|
||||
off = items.Identify(EquipSlot.OffHand, (PrimaryId)(main.PrimaryId.Id + 50), main.SecondaryId, main.Variant, main.Type);
|
||||
var gauntlet = items.Identify(EquipSlot.Hands, cur[1].X, (Variant)cur[1].Y.Id);
|
||||
if (gauntlet.Valid)
|
||||
{
|
||||
data.SetItem(EquipSlot.Hands, gauntlet);
|
||||
|
|
@ -147,9 +147,9 @@ public class DesignBase64Migration
|
|||
}
|
||||
else
|
||||
{
|
||||
off = cur[0].Set.Id == 0
|
||||
off = cur[0].X.Id == 0
|
||||
? ItemManager.NothingItem(FullEquipType.Shield)
|
||||
: items.Identify(EquipSlot.OffHand, cur[1].Set, cur[1].Type, cur[1].Variant, main.Type);
|
||||
: items.Identify(EquipSlot.OffHand, cur[1].X, cur[1].Y, cur[1].Variant, main.Type);
|
||||
}
|
||||
|
||||
if (main.Type.ValidOffhand() != FullEquipType.Unknown && !off.Valid)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ using Glamourer.Structs;
|
|||
using Glamourer.Utility;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
|
|
@ -165,7 +165,7 @@ public class DesignConverter(ItemManager _items, DesignManager _designs, Customi
|
|||
yield return (slot, item, armor.Stain);
|
||||
}
|
||||
|
||||
var mh = _items.Identify(EquipSlot.MainHand, mainhand.Set, mainhand.Type, mainhand.Variant, FullEquipType.Unknown);
|
||||
var mh = _items.Identify(EquipSlot.MainHand, mainhand.X, mainhand.Y, mainhand.Variant, FullEquipType.Unknown);
|
||||
if (!mh.Valid)
|
||||
{
|
||||
Glamourer.Log.Warning($"Appearance data {mainhand} for mainhand weapon invalid, item could not be identified.");
|
||||
|
|
@ -174,7 +174,7 @@ public class DesignConverter(ItemManager _items, DesignManager _designs, Customi
|
|||
|
||||
yield return (EquipSlot.MainHand, mh, mainhand.Stain);
|
||||
|
||||
var oh = _items.Identify(EquipSlot.OffHand, offhand.Set, offhand.Type, offhand.Variant, mh.Type);
|
||||
var oh = _items.Identify(EquipSlot.OffHand, offhand.X, offhand.Y, offhand.Variant, mh.Type);
|
||||
if (!oh.Valid)
|
||||
{
|
||||
Glamourer.Log.Warning($"Appearance data {offhand} for offhand weapon invalid, item could not be identified.");
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ using OtterGui.Classes;
|
|||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.String.Functions;
|
||||
using CustomizeData = Penumbra.GameData.Structs.CustomizeData;
|
||||
|
||||
namespace Glamourer.Designs;
|
||||
|
||||
|
|
@ -31,8 +30,8 @@ public unsafe struct DesignData
|
|||
public Customize Customize = Customize.Default;
|
||||
public uint ModelId;
|
||||
public CrestFlag CrestVisibility;
|
||||
private WeaponType _secondaryMainhand;
|
||||
private WeaponType _secondaryOffhand;
|
||||
private SecondaryId _secondaryMainhand;
|
||||
private SecondaryId _secondaryOffhand;
|
||||
private FullEquipType _typeMainhand;
|
||||
private FullEquipType _typeOffhand;
|
||||
private byte _states;
|
||||
|
|
@ -75,18 +74,18 @@ public unsafe struct DesignData
|
|||
=> slot.ToIndex() switch
|
||||
{
|
||||
// @formatter:off
|
||||
0 => EquipItem.FromIds(_itemIds[ 0], _iconIds[ 0], (SetId)(_equipmentBytes[ 0] | (_equipmentBytes[ 1] << 8)), (WeaponType)0, _equipmentBytes[ 2], FullEquipType.Head, name: _nameHead ),
|
||||
1 => EquipItem.FromIds(_itemIds[ 1], _iconIds[ 1], (SetId)(_equipmentBytes[ 4] | (_equipmentBytes[ 5] << 8)), (WeaponType)0, _equipmentBytes[ 6], FullEquipType.Body, name: _nameBody ),
|
||||
2 => EquipItem.FromIds(_itemIds[ 2], _iconIds[ 2], (SetId)(_equipmentBytes[ 8] | (_equipmentBytes[ 9] << 8)), (WeaponType)0, _equipmentBytes[10], FullEquipType.Hands, name: _nameHands ),
|
||||
3 => EquipItem.FromIds(_itemIds[ 3], _iconIds[ 3], (SetId)(_equipmentBytes[12] | (_equipmentBytes[13] << 8)), (WeaponType)0, _equipmentBytes[14], FullEquipType.Legs, name: _nameLegs ),
|
||||
4 => EquipItem.FromIds(_itemIds[ 4], _iconIds[ 4], (SetId)(_equipmentBytes[16] | (_equipmentBytes[17] << 8)), (WeaponType)0, _equipmentBytes[18], FullEquipType.Feet, name: _nameFeet ),
|
||||
5 => EquipItem.FromIds(_itemIds[ 5], _iconIds[ 5], (SetId)(_equipmentBytes[20] | (_equipmentBytes[21] << 8)), (WeaponType)0, _equipmentBytes[22], FullEquipType.Ears, name: _nameEars ),
|
||||
6 => EquipItem.FromIds(_itemIds[ 6], _iconIds[ 6], (SetId)(_equipmentBytes[24] | (_equipmentBytes[25] << 8)), (WeaponType)0, _equipmentBytes[26], FullEquipType.Neck, name: _nameNeck ),
|
||||
7 => EquipItem.FromIds(_itemIds[ 7], _iconIds[ 7], (SetId)(_equipmentBytes[28] | (_equipmentBytes[29] << 8)), (WeaponType)0, _equipmentBytes[30], FullEquipType.Wrists, name: _nameWrists ),
|
||||
8 => EquipItem.FromIds(_itemIds[ 8], _iconIds[ 8], (SetId)(_equipmentBytes[32] | (_equipmentBytes[33] << 8)), (WeaponType)0, _equipmentBytes[34], FullEquipType.Finger, name: _nameRFinger ),
|
||||
9 => EquipItem.FromIds(_itemIds[ 9], _iconIds[ 9], (SetId)(_equipmentBytes[36] | (_equipmentBytes[37] << 8)), (WeaponType)0, _equipmentBytes[38], FullEquipType.Finger, name: _nameLFinger ),
|
||||
10 => EquipItem.FromIds(_itemIds[10], _iconIds[10], (SetId)(_equipmentBytes[40] | (_equipmentBytes[41] << 8)), _secondaryMainhand, _equipmentBytes[42], _typeMainhand, name: _nameMainhand),
|
||||
11 => EquipItem.FromIds(_itemIds[11], _iconIds[11], (SetId)(_equipmentBytes[44] | (_equipmentBytes[45] << 8)), _secondaryOffhand, _equipmentBytes[46], _typeOffhand, name: _nameOffhand ),
|
||||
0 => EquipItem.FromIds((ItemId)_itemIds[ 0], (IconId)_iconIds[ 0], (PrimaryId)(_equipmentBytes[ 0] | (_equipmentBytes[ 1] << 8)), (SecondaryId)0, (Variant)_equipmentBytes[ 2], FullEquipType.Head, name: _nameHead ),
|
||||
1 => EquipItem.FromIds((ItemId)_itemIds[ 1], (IconId)_iconIds[ 1], (PrimaryId)(_equipmentBytes[ 4] | (_equipmentBytes[ 5] << 8)), (SecondaryId)0, (Variant)_equipmentBytes[ 6], FullEquipType.Body, name: _nameBody ),
|
||||
2 => EquipItem.FromIds((ItemId)_itemIds[ 2], (IconId)_iconIds[ 2], (PrimaryId)(_equipmentBytes[ 8] | (_equipmentBytes[ 9] << 8)), (SecondaryId)0, (Variant)_equipmentBytes[10], FullEquipType.Hands, name: _nameHands ),
|
||||
3 => EquipItem.FromIds((ItemId)_itemIds[ 3], (IconId)_iconIds[ 3], (PrimaryId)(_equipmentBytes[12] | (_equipmentBytes[13] << 8)), (SecondaryId)0, (Variant)_equipmentBytes[14], FullEquipType.Legs, name: _nameLegs ),
|
||||
4 => EquipItem.FromIds((ItemId)_itemIds[ 4], (IconId)_iconIds[ 4], (PrimaryId)(_equipmentBytes[16] | (_equipmentBytes[17] << 8)), (SecondaryId)0, (Variant)_equipmentBytes[18], FullEquipType.Feet, name: _nameFeet ),
|
||||
5 => EquipItem.FromIds((ItemId)_itemIds[ 5], (IconId)_iconIds[ 5], (PrimaryId)(_equipmentBytes[20] | (_equipmentBytes[21] << 8)), (SecondaryId)0, (Variant)_equipmentBytes[22], FullEquipType.Ears, name: _nameEars ),
|
||||
6 => EquipItem.FromIds((ItemId)_itemIds[ 6], (IconId)_iconIds[ 6], (PrimaryId)(_equipmentBytes[24] | (_equipmentBytes[25] << 8)), (SecondaryId)0, (Variant)_equipmentBytes[26], FullEquipType.Neck, name: _nameNeck ),
|
||||
7 => EquipItem.FromIds((ItemId)_itemIds[ 7], (IconId)_iconIds[ 7], (PrimaryId)(_equipmentBytes[28] | (_equipmentBytes[29] << 8)), (SecondaryId)0, (Variant)_equipmentBytes[30], FullEquipType.Wrists, name: _nameWrists ),
|
||||
8 => EquipItem.FromIds((ItemId)_itemIds[ 8], (IconId)_iconIds[ 8], (PrimaryId)(_equipmentBytes[32] | (_equipmentBytes[33] << 8)), (SecondaryId)0, (Variant)_equipmentBytes[34], FullEquipType.Finger, name: _nameRFinger ),
|
||||
9 => EquipItem.FromIds((ItemId)_itemIds[ 9], (IconId)_iconIds[ 9], (PrimaryId)(_equipmentBytes[36] | (_equipmentBytes[37] << 8)), (SecondaryId)0, (Variant)_equipmentBytes[38], FullEquipType.Finger, name: _nameLFinger ),
|
||||
10 => EquipItem.FromIds((ItemId)_itemIds[10], (IconId)_iconIds[10], (PrimaryId)(_equipmentBytes[40] | (_equipmentBytes[41] << 8)), _secondaryMainhand, (Variant)_equipmentBytes[42], _typeMainhand, name: _nameMainhand),
|
||||
11 => EquipItem.FromIds((ItemId)_itemIds[11], (IconId)_iconIds[11], (PrimaryId)(_equipmentBytes[44] | (_equipmentBytes[45] << 8)), _secondaryOffhand, (Variant)_equipmentBytes[46], _typeOffhand, name: _nameOffhand ),
|
||||
_ => new EquipItem(),
|
||||
// @formatter:on
|
||||
};
|
||||
|
|
@ -129,8 +128,8 @@ public unsafe struct DesignData
|
|||
|
||||
_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 + 0] = (byte)item.PrimaryId.Id;
|
||||
_equipmentBytes[4 * index + 1] = (byte)(item.PrimaryId.Id >> 8);
|
||||
_equipmentBytes[4 * index + 2] = item.Variant.Id;
|
||||
switch (index)
|
||||
{
|
||||
|
|
@ -148,12 +147,12 @@ public unsafe struct DesignData
|
|||
// @formatter:on
|
||||
case 10:
|
||||
_nameMainhand = item.Name;
|
||||
_secondaryMainhand = item.WeaponType;
|
||||
_secondaryMainhand = item.SecondaryId;
|
||||
_typeMainhand = item.Type;
|
||||
return true;
|
||||
case 11:
|
||||
_nameOffhand = item.Name;
|
||||
_secondaryOffhand = item.WeaponType;
|
||||
_secondaryOffhand = item.SecondaryId;
|
||||
_typeOffhand = item.Type;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -294,7 +293,7 @@ public unsafe struct DesignData
|
|||
|
||||
public readonly byte[] GetCustomizeBytes()
|
||||
{
|
||||
var ret = new byte[CustomizeData.Size];
|
||||
var ret = new byte[CustomizeArray.Size];
|
||||
fixed (byte* retPtr = ret, inPtr = Customize.Data.Data)
|
||||
{
|
||||
MemoryUtility.MemCpyUnchecked(retPtr, inPtr, ret.Length);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ using Glamourer.Structs;
|
|||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using Glamourer.State;
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Services;
|
||||
|
||||
namespace Glamourer;
|
||||
|
||||
|
|
@ -25,21 +26,21 @@ public class Glamourer : IDalamudPlugin
|
|||
public static readonly Logger Log = new();
|
||||
public static MessageService Messager { get; private set; } = null!;
|
||||
|
||||
private readonly ServiceProvider _services;
|
||||
private readonly ServiceManager _services;
|
||||
|
||||
public Glamourer(DalamudPluginInterface pluginInterface)
|
||||
{
|
||||
try
|
||||
{
|
||||
_services = ServiceManager.CreateProvider(pluginInterface, Log);
|
||||
Messager = _services.GetRequiredService<MessageService>();
|
||||
_services.GetRequiredService<VisorService>();
|
||||
_services.GetRequiredService<WeaponService>();
|
||||
_services.GetRequiredService<ScalingService>();
|
||||
_services.GetRequiredService<StateListener>(); // Initialize State Listener.
|
||||
_services.GetRequiredService<GlamourerWindowSystem>(); // initialize ui.
|
||||
_services.GetRequiredService<CommandService>(); // initialize commands.
|
||||
_services.GetRequiredService<GlamourerIpc>(); // initialize IPC.
|
||||
_services = ServiceManagerA.CreateProvider(pluginInterface, Log);
|
||||
Messager = _services.GetService<MessageService>();
|
||||
_services.GetService<VisorService>();
|
||||
_services.GetService<WeaponService>();
|
||||
_services.GetService<ScalingService>();
|
||||
_services.GetService<StateListener>(); // Initialize State Listener.
|
||||
_services.GetService<GlamourerWindowSystem>(); // initialize ui.
|
||||
_services.GetService<CommandService>(); // initialize commands.
|
||||
_services.GetService<GlamourerIpc>(); // initialize IPC.
|
||||
Log.Information($"Glamourer v{Version} loaded successfully.");
|
||||
}
|
||||
catch
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Glamourer.Customization;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
|
|
@ -28,7 +27,7 @@ public partial class CustomizationDrawer
|
|||
npc = true;
|
||||
}
|
||||
|
||||
var icon = _service.AwaitedService.GetIcon(custom!.Value.IconId);
|
||||
var icon = _service.Service.GetIcon(custom!.Value.IconId);
|
||||
using (var disabled = ImRaii.Disabled(_locked || _currentIndex is CustomizeIndex.Face && _lockedRedraw))
|
||||
{
|
||||
if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize))
|
||||
|
|
@ -68,7 +67,7 @@ public partial class CustomizationDrawer
|
|||
for (var i = 0; i < _currentCount; ++i)
|
||||
{
|
||||
var custom = _set.Data(_currentIndex, i, _customize.Face);
|
||||
var icon = _service.AwaitedService.GetIcon(custom.IconId);
|
||||
var icon = _service.Service.GetIcon(custom.IconId);
|
||||
using (var _ = ImRaii.Group())
|
||||
{
|
||||
using var frameColor = ImRaii.PushColor(ImGuiCol.Button, Colors.SelectedRed, current == i);
|
||||
|
|
@ -179,8 +178,8 @@ public partial class CustomizationDrawer
|
|||
var enabled = _customize.Get(featureIdx) != CustomizeValue.Zero;
|
||||
var feature = _set.Data(featureIdx, 0, face);
|
||||
var icon = featureIdx == CustomizeIndex.LegacyTattoo
|
||||
? _legacyTattoo ?? _service.AwaitedService.GetIcon(feature.IconId)
|
||||
: _service.AwaitedService.GetIcon(feature.IconId);
|
||||
? _legacyTattoo ?? _service.Service.GetIcon(feature.IconId)
|
||||
: _service.Service.GetIcon(feature.IconId);
|
||||
if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize, Vector2.Zero, Vector2.One, (int)ImGui.GetStyle().FramePadding.X,
|
||||
Vector4.Zero, enabled ? Vector4.One : _redTint))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ using ImGuiNET;
|
|||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
using CustomizeData = Penumbra.GameData.Structs.CustomizeData;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Gui.Customization;
|
||||
|
||||
|
|
@ -120,7 +120,7 @@ public partial class CustomizationDrawer(DalamudPluginInterface pi, Customizatio
|
|||
return DrawArtisan();
|
||||
|
||||
DrawRaceGenderSelector();
|
||||
_set = _service.AwaitedService.GetList(_customize.Clan, _customize.Gender);
|
||||
_set = _service.Service.GetList(_customize.Clan, _customize.Gender);
|
||||
|
||||
foreach (var id in _set.Order[CharaMakeParams.MenuType.Percentage])
|
||||
PercentageSelector(id);
|
||||
|
|
@ -153,7 +153,7 @@ public partial class CustomizationDrawer(DalamudPluginInterface pi, Customizatio
|
|||
|
||||
private unsafe bool DrawArtisan()
|
||||
{
|
||||
for (var i = 0; i < CustomizeData.Size; ++i)
|
||||
for (var i = 0; i < CustomizeArray.Size; ++i)
|
||||
{
|
||||
using var id = ImRaii.PushId(i);
|
||||
int value = _customize.Data.Data[i];
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ using Glamourer.Unlocks;
|
|||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ public class EquipmentDrawer
|
|||
|
||||
private readonly ItemManager _items;
|
||||
private readonly GlamourerColorCombo _stainCombo;
|
||||
private readonly StainData _stainData;
|
||||
private readonly DictStains _stainData;
|
||||
private readonly ItemCombo[] _itemCombo;
|
||||
private readonly Dictionary<FullEquipType, WeaponCombo> _weaponCombo;
|
||||
private readonly CodeService _codes;
|
||||
|
|
@ -66,8 +66,8 @@ public class EquipmentDrawer
|
|||
_iconSize = new Vector2(2 * ImGui.GetFrameHeight() + ImGui.GetStyle().ItemSpacing.Y);
|
||||
_comboLength = DefaultWidth * ImGuiHelpers.GlobalScale;
|
||||
if (_requiredComboWidthUnscaled == 0)
|
||||
_requiredComboWidthUnscaled = _items.ItemService.AwaitedService.AllItems(true)
|
||||
.Concat(_items.ItemService.AwaitedService.AllItems(false))
|
||||
_requiredComboWidthUnscaled = _items.ItemData.AllItems(true)
|
||||
.Concat(_items.ItemData.AllItems(false))
|
||||
.Max(i => ImGui.CalcTextSize($"{i.Item2.Name} ({i.Item2.ModelString})").X)
|
||||
/ ImGuiHelpers.GlobalScale;
|
||||
|
||||
|
|
@ -102,7 +102,7 @@ public class EquipmentDrawer
|
|||
|
||||
public void DrawWeapons(EquipDrawData mainhand, EquipDrawData offhand, bool allWeapons)
|
||||
{
|
||||
if (mainhand.CurrentItem.ModelId.Id == 0)
|
||||
if (mainhand.CurrentItem.PrimaryId.Id == 0)
|
||||
return;
|
||||
|
||||
if (_config.HideApplyCheckmarks)
|
||||
|
|
@ -202,24 +202,24 @@ public class EquipmentDrawer
|
|||
|
||||
void DrawWeapon(in EquipDrawData current)
|
||||
{
|
||||
int setId = current.CurrentItem.ModelId.Id;
|
||||
int type = current.CurrentItem.WeaponType.Id;
|
||||
int setId = current.CurrentItem.PrimaryId.Id;
|
||||
int type = current.CurrentItem.SecondaryId.Id;
|
||||
int variant = current.CurrentItem.Variant.Id;
|
||||
ImGui.SetNextItemWidth(80 * ImGuiHelpers.GlobalScale);
|
||||
if (ImGui.InputInt("##setId", ref setId, 0, 0))
|
||||
{
|
||||
var newSetId = (SetId)Math.Clamp(setId, 0, ushort.MaxValue);
|
||||
if (newSetId.Id != current.CurrentItem.ModelId.Id)
|
||||
current.ItemSetter(_items.Identify(current.Slot, newSetId, current.CurrentItem.WeaponType, current.CurrentItem.Variant));
|
||||
var newSetId = (PrimaryId)Math.Clamp(setId, 0, ushort.MaxValue);
|
||||
if (newSetId.Id != current.CurrentItem.PrimaryId.Id)
|
||||
current.ItemSetter(_items.Identify(current.Slot, newSetId, current.CurrentItem.SecondaryId, current.CurrentItem.Variant));
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.SetNextItemWidth(80 * ImGuiHelpers.GlobalScale);
|
||||
if (ImGui.InputInt("##type", ref type, 0, 0))
|
||||
{
|
||||
var newType = (WeaponType)Math.Clamp(type, 0, ushort.MaxValue);
|
||||
if (newType.Id != current.CurrentItem.WeaponType.Id)
|
||||
current.ItemSetter(_items.Identify(current.Slot, current.CurrentItem.ModelId, newType, current.CurrentItem.Variant));
|
||||
var newType = (SecondaryId)Math.Clamp(type, 0, ushort.MaxValue);
|
||||
if (newType.Id != current.CurrentItem.SecondaryId.Id)
|
||||
current.ItemSetter(_items.Identify(current.Slot, current.CurrentItem.PrimaryId, newType, current.CurrentItem.Variant));
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
|
@ -228,7 +228,8 @@ public class EquipmentDrawer
|
|||
{
|
||||
var newVariant = (Variant)Math.Clamp(variant, 0, byte.MaxValue);
|
||||
if (newVariant.Id != current.CurrentItem.Variant.Id)
|
||||
current.ItemSetter(_items.Identify(current.Slot, current.CurrentItem.ModelId, current.CurrentItem.WeaponType, newVariant));
|
||||
current.ItemSetter(_items.Identify(current.Slot, current.CurrentItem.PrimaryId, current.CurrentItem.SecondaryId,
|
||||
newVariant));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -249,13 +250,13 @@ public class EquipmentDrawer
|
|||
/// <summary> Draw an input for armor that can set arbitrary values instead of choosing items. </summary>
|
||||
private void DrawArmorArtisan(EquipDrawData data)
|
||||
{
|
||||
int setId = data.CurrentItem.ModelId.Id;
|
||||
int setId = data.CurrentItem.PrimaryId.Id;
|
||||
int variant = data.CurrentItem.Variant.Id;
|
||||
ImGui.SetNextItemWidth(80 * ImGuiHelpers.GlobalScale);
|
||||
if (ImGui.InputInt("##setId", ref setId, 0, 0))
|
||||
{
|
||||
var newSetId = (SetId)Math.Clamp(setId, 0, ushort.MaxValue);
|
||||
if (newSetId.Id != data.CurrentItem.ModelId.Id)
|
||||
var newSetId = (PrimaryId)Math.Clamp(setId, 0, ushort.MaxValue);
|
||||
if (newSetId.Id != data.CurrentItem.PrimaryId.Id)
|
||||
data.ItemSetter(_items.Identify(data.Slot, newSetId, data.CurrentItem.Variant));
|
||||
}
|
||||
|
||||
|
|
@ -265,7 +266,7 @@ public class EquipmentDrawer
|
|||
{
|
||||
var newVariant = (byte)Math.Clamp(variant, 0, byte.MaxValue);
|
||||
if (newVariant != data.CurrentItem.Variant)
|
||||
data.ItemSetter(_items.Identify(data.Slot, data.CurrentItem.ModelId, newVariant));
|
||||
data.ItemSetter(_items.Identify(data.Slot, data.CurrentItem.PrimaryId, newVariant));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -454,7 +455,7 @@ public class EquipmentDrawer
|
|||
else if (combo.CustomVariant.Id > 0)
|
||||
data.ItemSetter(_items.Identify(data.Slot, combo.CustomSetId, combo.CustomVariant));
|
||||
|
||||
if (!data.Locked && data.CurrentItem.ModelId.Id != 0)
|
||||
if (!data.Locked && data.CurrentItem.PrimaryId.Id != 0)
|
||||
{
|
||||
if (clear || ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
data.ItemSetter(ItemManager.NothingItem(data.Slot));
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ using Dalamud.Interface.Utility.Raii;
|
|||
using Glamourer.Unlocks;
|
||||
using ImGuiNET;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Gui.Equipment;
|
||||
|
||||
public sealed class GlamourerColorCombo(float _comboWidth, StainData _stains, FavoriteManager _favorites)
|
||||
public sealed class GlamourerColorCombo(float _comboWidth, DictStains _stains, FavoriteManager _favorites)
|
||||
: FilterComboColors(_comboWidth, CreateFunc(_stains, _favorites), Glamourer.Log)
|
||||
{
|
||||
protected override bool DrawSelectable(int globalIdx, bool selected)
|
||||
|
|
@ -40,8 +40,9 @@ public sealed class GlamourerColorCombo(float _comboWidth, StainData _stains, Fa
|
|||
return base.DrawSelectable(globalIdx, selected);
|
||||
}
|
||||
|
||||
private static Func<IReadOnlyList<KeyValuePair<byte, (string Name, uint Color, bool Gloss)>>> CreateFunc(StainData stains,
|
||||
private static Func<IReadOnlyList<KeyValuePair<byte, (string Name, uint Color, bool Gloss)>>> CreateFunc(DictStains stains,
|
||||
FavoriteManager favorites)
|
||||
=> () => stains.Data.Select(kvp => (kvp, favorites.Contains((StainId)kvp.Key))).OrderBy(p => !p.Item2).Select(p => p.kvp)
|
||||
.Prepend(new KeyValuePair<byte, (string Name, uint Dye, bool Gloss)>(0, ("None", 0, false))).ToList();
|
||||
=> () => stains.Select(kvp => (kvp, favorites.Contains(kvp.Key))).OrderBy(p => !p.Item2).Select(p => p.kvp)
|
||||
.Prepend(new KeyValuePair<StainId, Stain>(Stain.None.RowIndex, Stain.None)).Select(kvp
|
||||
=> new KeyValuePair<byte, (string, uint, bool)>(kvp.Key.Id, (kvp.Value.Name, kvp.Value.RgbaColor, kvp.Value.Gloss))).ToList();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ public sealed class ItemCombo : FilterComboCache<EquipItem>
|
|||
private ItemId _currentItem;
|
||||
private float _innerWidth;
|
||||
|
||||
public SetId CustomSetId { get; private set; }
|
||||
public PrimaryId CustomSetId { get; private set; }
|
||||
public Variant CustomVariant { get; private set; }
|
||||
|
||||
public ItemCombo(IDataManager gameData, ItemManager items, EquipSlot slot, Logger log, FavoriteManager favorites)
|
||||
|
|
@ -83,7 +83,7 @@ public sealed class ItemCombo : FilterComboCache<EquipItem>
|
|||
}
|
||||
|
||||
protected override bool IsVisible(int globalIndex, LowerString filter)
|
||||
=> base.IsVisible(globalIndex, filter) || filter.IsContained(Items[globalIndex].ModelId.Id.ToString());
|
||||
=> base.IsVisible(globalIndex, filter) || filter.IsContained(Items[globalIndex].PrimaryId.Id.ToString());
|
||||
|
||||
protected override string ToString(EquipItem obj)
|
||||
=> obj.Name;
|
||||
|
|
@ -111,7 +111,7 @@ public sealed class ItemCombo : FilterComboCache<EquipItem>
|
|||
private static IReadOnlyList<EquipItem> GetItems(FavoriteManager favorites, ItemManager items, EquipSlot slot)
|
||||
{
|
||||
var nothing = ItemManager.NothingItem(slot);
|
||||
if (!items.ItemService.AwaitedService.TryGetValue(slot.ToEquipType(), out var list))
|
||||
if (!items.ItemData.ByType.TryGetValue(slot.ToEquipType(), out var list))
|
||||
return new[]
|
||||
{
|
||||
nothing,
|
||||
|
|
|
|||
|
|
@ -60,12 +60,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.Id}-{obj.WeaponType.Id}-{obj.Variant})");
|
||||
ImGuiUtil.RightAlign($"({obj.PrimaryId.Id}-{obj.SecondaryId.Id}-{obj.Variant})");
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected override bool IsVisible(int globalIndex, LowerString filter)
|
||||
=> base.IsVisible(globalIndex, filter) || filter.IsContained(Items[globalIndex].ModelId.Id.ToString());
|
||||
=> base.IsVisible(globalIndex, filter) || filter.IsContained(Items[globalIndex].PrimaryId.Id.ToString());
|
||||
|
||||
protected override string ToString(EquipItem obj)
|
||||
=> obj.Name;
|
||||
|
|
@ -80,14 +80,14 @@ public sealed class WeaponCombo : FilterComboCache<EquipItem>
|
|||
var enumerable = Array.Empty<EquipItem>().AsEnumerable();
|
||||
foreach (var t in Enum.GetValues<FullEquipType>().Where(e => e.ToSlot() is EquipSlot.MainHand))
|
||||
{
|
||||
if (items.ItemService.AwaitedService.TryGetValue(t, out var l))
|
||||
if (items.ItemData.ByType.TryGetValue(t, out var l))
|
||||
enumerable = enumerable.Concat(l);
|
||||
}
|
||||
|
||||
return enumerable.OrderBy(e => e.Name).ToList();
|
||||
}
|
||||
|
||||
if (!items.ItemService.AwaitedService.TryGetValue(type, out var list))
|
||||
if (!items.ItemData.ByType.TryGetValue(type, out var list))
|
||||
return Array.Empty<EquipItem>();
|
||||
|
||||
if (type.AllowsNothing())
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using Glamourer.Events;
|
|||
using Glamourer.Gui.Tabs;
|
||||
using Glamourer.Gui.Tabs.ActorTab;
|
||||
using Glamourer.Gui.Tabs.AutomationTab;
|
||||
using Glamourer.Gui.Tabs.DebugTab;
|
||||
using Glamourer.Gui.Tabs.DesignTab;
|
||||
using Glamourer.Gui.Tabs.UnlocksTab;
|
||||
using ImGuiNET;
|
||||
|
|
@ -65,8 +66,8 @@ public class MainWindow : Window, IDisposable
|
|||
Messages = messages;
|
||||
_quickBar = quickBar;
|
||||
_config = config;
|
||||
_tabs = new ITab[]
|
||||
{
|
||||
_tabs =
|
||||
[
|
||||
settings,
|
||||
actors,
|
||||
designs,
|
||||
|
|
@ -74,7 +75,7 @@ public class MainWindow : Window, IDisposable
|
|||
unlocks,
|
||||
messages,
|
||||
debugTab,
|
||||
};
|
||||
];
|
||||
_event.Subscribe(OnTabSelected, TabSelected.Priority.MainWindow);
|
||||
IsOpen = _config.OpenWindowAtStart;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ public class PenumbraChangedItemTooltip : IDisposable
|
|||
{
|
||||
case ChangedItemType.ItemOffhand:
|
||||
case ChangedItemType.Item:
|
||||
if (!_items.ItemService.AwaitedService.TryGetValue(id, type is ChangedItemType.Item ? EquipSlot.MainHand : EquipSlot.OffHand, out var item))
|
||||
if (!_items.ItemData.TryGetValue(id, type is ChangedItemType.Item ? EquipSlot.MainHand : EquipSlot.OffHand, out var item))
|
||||
return;
|
||||
|
||||
CreateTooltip(item, "[Glamourer] ", false);
|
||||
|
|
@ -177,7 +177,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, main.Variant);
|
||||
var mainItem = _items.Identify(slot, main.X, main.Y, main.Variant);
|
||||
if (slot == EquipSlot.MainHand)
|
||||
return item.Type == mainItem.Type;
|
||||
|
||||
|
|
@ -197,7 +197,7 @@ public class PenumbraChangedItemTooltip : IDisposable
|
|||
if (!Player(out var state))
|
||||
return;
|
||||
|
||||
if (!_items.ItemService.AwaitedService.TryGetValue(id, type is ChangedItemType.Item ? EquipSlot.MainHand : EquipSlot.OffHand, out var item))
|
||||
if (!_items.ItemData.TryGetValue(id, type is ChangedItemType.Item ? EquipSlot.MainHand : EquipSlot.OffHand, out var item))
|
||||
return;
|
||||
|
||||
ApplyItem(state, item);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ using Glamourer.Gui.Customization;
|
|||
using Glamourer.Gui.Equipment;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.State;
|
||||
using Glamourer.Structs;
|
||||
using ImGuiNET;
|
||||
|
|
@ -21,14 +20,24 @@ using OtterGui;
|
|||
using OtterGui.Classes;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.ActorTab;
|
||||
|
||||
public class ActorPanel(ActorSelector _selector, StateManager _stateManager, CustomizationDrawer _customizationDrawer,
|
||||
EquipmentDrawer _equipmentDrawer, IdentifierService _identification, AutoDesignApplier _autoDesignApplier,
|
||||
Configuration _config, DesignConverter _converter, ObjectManager _objects, DesignManager _designManager, ImportService _importService,
|
||||
ICondition _conditions)
|
||||
public class ActorPanel(
|
||||
ActorSelector _selector,
|
||||
StateManager _stateManager,
|
||||
CustomizationDrawer _customizationDrawer,
|
||||
EquipmentDrawer _equipmentDrawer,
|
||||
AutoDesignApplier _autoDesignApplier,
|
||||
Configuration _config,
|
||||
DesignConverter _converter,
|
||||
ObjectManager _objects,
|
||||
DesignManager _designManager,
|
||||
ImportService _importService,
|
||||
ICondition _conditions,
|
||||
DictModelChara _modelChara)
|
||||
{
|
||||
private ActorIdentifier _identifier;
|
||||
private string _actorName = string.Empty;
|
||||
|
|
@ -187,7 +196,7 @@ public class ActorPanel(ActorSelector _selector, StateManager _stateManager, Cus
|
|||
|
||||
private void DrawMonsterPanel()
|
||||
{
|
||||
var names = _identification.AwaitedService.ModelCharaNames(_state!.ModelData.ModelId);
|
||||
var names = _modelChara[_state!.ModelData.ModelId];
|
||||
var turnHuman = ImGui.Button("Turn Human");
|
||||
ImGui.Separator();
|
||||
using (var box = ImRaii.ListBox("##MonsterList",
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@ public class ActorSelector
|
|||
{
|
||||
private readonly EphemeralConfig _config;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly ActorService _actors;
|
||||
private readonly ActorManager _actors;
|
||||
|
||||
private ActorIdentifier _identifier = ActorIdentifier.Invalid;
|
||||
|
||||
public ActorSelector(ObjectManager objects, ActorService actors, EphemeralConfig config)
|
||||
public ActorSelector(ObjectManager objects, ActorManager actors, EphemeralConfig config)
|
||||
{
|
||||
_objects = objects;
|
||||
_actors = actors;
|
||||
|
|
@ -93,7 +93,7 @@ public class ActorSelector
|
|||
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.UserCircle.ToIconString(), buttonWidth
|
||||
, "Select the local player character.", !_objects.Player, true))
|
||||
_identifier = _objects.Player.GetIdentifier(_actors.AwaitedService);
|
||||
_identifier = _objects.Player.GetIdentifier(_actors);
|
||||
|
||||
ImGui.SameLine();
|
||||
var (id, data) = _objects.TargetData;
|
||||
|
|
|
|||
|
|
@ -3,23 +3,23 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Dalamud.Utility;
|
||||
using Glamourer.Services;
|
||||
using ImGuiNET;
|
||||
using OtterGui.Custom;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.AutomationTab;
|
||||
|
||||
public sealed class HumanNpcCombo : FilterComboCache<(string Name, ObjectKind Kind, uint[] Ids)>
|
||||
public sealed class HumanNpcCombo(
|
||||
string label,
|
||||
DictModelChara modelCharaDict,
|
||||
DictBNpcNames bNpcNames,
|
||||
DictBNpc bNpcs,
|
||||
HumanModelList humans,
|
||||
Logger log)
|
||||
: FilterComboCache<(string Name, ObjectKind Kind, uint[] Ids)>(() => CreateList(modelCharaDict, bNpcNames, bNpcs, humans), log)
|
||||
{
|
||||
private readonly string _label;
|
||||
|
||||
public HumanNpcCombo(string label, IdentifierService service, HumanModelList humans, Logger log)
|
||||
: base(() => CreateList(service, humans), log)
|
||||
=> _label = label;
|
||||
|
||||
protected override string ToString((string Name, ObjectKind Kind, uint[] Ids) obj)
|
||||
=> obj.Name;
|
||||
|
||||
|
|
@ -36,7 +36,8 @@ public sealed class HumanNpcCombo : FilterComboCache<(string Name, ObjectKind Ki
|
|||
}
|
||||
|
||||
public bool Draw(float width)
|
||||
=> Draw(_label, CurrentSelection.Name.IsNullOrEmpty() ? "Human Non-Player-Characters..." : CurrentSelection.Name, string.Empty, width, ImGui.GetTextLineHeightWithSpacing());
|
||||
=> Draw(label, CurrentSelection.Name.IsNullOrEmpty() ? "Human Non-Player-Characters..." : CurrentSelection.Name, string.Empty, width,
|
||||
ImGui.GetTextLineHeightWithSpacing());
|
||||
|
||||
|
||||
/// <summary> Compare strings in a way that letters and numbers are sorted before any special symbols. </summary>
|
||||
|
|
@ -61,15 +62,16 @@ public sealed class HumanNpcCombo : FilterComboCache<(string Name, ObjectKind Ki
|
|||
}
|
||||
}
|
||||
|
||||
private static IReadOnlyList<(string Name, ObjectKind Kind, uint[] Ids)> CreateList(IdentifierService service, HumanModelList humans)
|
||||
private static IReadOnlyList<(string Name, ObjectKind Kind, uint[] Ids)> CreateList(DictModelChara modelCharaDict, DictBNpcNames bNpcNames,
|
||||
DictBNpc bNpcs, HumanModelList humans)
|
||||
{
|
||||
var ret = new List<(string Name, ObjectKind Kind, uint Id)>(1024);
|
||||
for (var modelChara = 0u; modelChara < service.AwaitedService.NumModelChara; ++modelChara)
|
||||
for (var modelChara = 0u; modelChara < modelCharaDict.Count; ++modelChara)
|
||||
{
|
||||
if (!humans.IsHuman(modelChara))
|
||||
continue;
|
||||
|
||||
var list = service.AwaitedService.ModelCharaNames(modelChara);
|
||||
var list = modelCharaDict[modelChara];
|
||||
if (list.Count == 0)
|
||||
continue;
|
||||
|
||||
|
|
@ -78,8 +80,8 @@ public sealed class HumanNpcCombo : FilterComboCache<(string Name, ObjectKind Ki
|
|||
switch (kind)
|
||||
{
|
||||
case ObjectKind.BattleNpc:
|
||||
var nameIds = service.AwaitedService.GetBnpcNames(id);
|
||||
ret.AddRange(nameIds.Select(nameId => (service.AwaitedService.Name(ObjectKind.BattleNpc, nameId), kind, nameId.Id)));
|
||||
var nameIds = bNpcNames[id];
|
||||
ret.AddRange(nameIds.Select(nameId => (bNpcs[nameId], kind, nameId.Id)));
|
||||
break;
|
||||
case ObjectKind.EventNpc:
|
||||
ret.Add((name, kind, id));
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Glamourer.Services;
|
||||
using ImGuiNET;
|
||||
using OtterGui.Custom;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Gui;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.String;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.AutomationTab;
|
||||
|
|
@ -12,7 +12,7 @@ public class IdentifierDrawer
|
|||
{
|
||||
private readonly WorldCombo _worldCombo;
|
||||
private readonly HumanNpcCombo _humanNpcCombo;
|
||||
private readonly ActorService _actors;
|
||||
private readonly ActorManager _actors;
|
||||
|
||||
private string _characterName = string.Empty;
|
||||
|
||||
|
|
@ -21,11 +21,12 @@ public class IdentifierDrawer
|
|||
public ActorIdentifier RetainerIdentifier { get; private set; } = ActorIdentifier.Invalid;
|
||||
public ActorIdentifier MannequinIdentifier { get; private set; } = ActorIdentifier.Invalid;
|
||||
|
||||
public IdentifierDrawer(ActorService actors, IdentifierService identifier, HumanModelList humans)
|
||||
public IdentifierDrawer(ActorManager actors, DictWorld dictWorld, DictModelChara dictModelChara, DictBNpcNames bNpcNames, DictBNpc bNpc,
|
||||
HumanModelList humans)
|
||||
{
|
||||
_actors = actors;
|
||||
_worldCombo = new WorldCombo(actors.AwaitedService.Data.Worlds, Glamourer.Log);
|
||||
_humanNpcCombo = new HumanNpcCombo("##npcs", identifier, humans, Glamourer.Log);
|
||||
_worldCombo = new WorldCombo(dictWorld, Glamourer.Log);
|
||||
_humanNpcCombo = new HumanNpcCombo("##npcs", dictModelChara, bNpcNames, bNpc, humans, Glamourer.Log);
|
||||
}
|
||||
|
||||
public void DrawName(float width)
|
||||
|
|
@ -63,13 +64,13 @@ public class IdentifierDrawer
|
|||
{
|
||||
if (ByteString.FromString(_characterName, out var byteName))
|
||||
{
|
||||
PlayerIdentifier = _actors.AwaitedService.CreatePlayer(byteName, _worldCombo.CurrentSelection.Key);
|
||||
RetainerIdentifier = _actors.AwaitedService.CreateRetainer(byteName, ActorIdentifier.RetainerType.Bell);
|
||||
MannequinIdentifier = _actors.AwaitedService.CreateRetainer(byteName, ActorIdentifier.RetainerType.Mannequin);
|
||||
PlayerIdentifier = _actors.CreatePlayer(byteName, _worldCombo.CurrentSelection.Key);
|
||||
RetainerIdentifier = _actors.CreateRetainer(byteName, ActorIdentifier.RetainerType.Bell);
|
||||
MannequinIdentifier = _actors.CreateRetainer(byteName, ActorIdentifier.RetainerType.Mannequin);
|
||||
}
|
||||
|
||||
NpcIdentifier = _humanNpcCombo.CurrentSelection.Kind is ObjectKind.EventNpc or ObjectKind.BattleNpc
|
||||
? _actors.AwaitedService.CreateNpc(_humanNpcCombo.CurrentSelection.Kind, _humanNpcCombo.CurrentSelection.Ids[0])
|
||||
? _actors.CreateNpc(_humanNpcCombo.CurrentSelection.Kind, _humanNpcCombo.CurrentSelection.Ids[0])
|
||||
: ActorIdentifier.Invalid;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -333,7 +333,7 @@ public class SetPanel
|
|||
if (!design.Design.DesignData.IsHuman)
|
||||
sb.AppendLine("The base model id can not be changed automatically to something non-human.");
|
||||
|
||||
var set = _customizations.AwaitedService.GetList(customize.Clan, customize.Gender);
|
||||
var set = _customizations.Service.GetList(customize.Clan, customize.Gender);
|
||||
foreach (var type in CustomizationExtensions.All)
|
||||
{
|
||||
var flag = type.ToFlag();
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@ using Dalamud.Interface.Utility;
|
|||
using Glamourer.Automation;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Services;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.String;
|
||||
using ImGuiClip = OtterGui.ImGuiClip;
|
||||
|
||||
|
|
@ -22,9 +22,9 @@ public class SetSelector : IDisposable
|
|||
private readonly Configuration _config;
|
||||
private readonly AutoDesignManager _manager;
|
||||
private readonly AutomationChanged _event;
|
||||
private readonly ActorService _actors;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly List<(AutoDesignSet, int)> _list = new();
|
||||
private readonly List<(AutoDesignSet, int)> _list = [];
|
||||
|
||||
public AutoDesignSet? Selection { get; private set; }
|
||||
public int SelectionIndex { get; private set; } = -1;
|
||||
|
|
@ -44,7 +44,7 @@ public class SetSelector : IDisposable
|
|||
|
||||
internal int _dragDesignIndex = -1;
|
||||
|
||||
public SetSelector(AutoDesignManager manager, AutomationChanged @event, Configuration config, ActorService actors, ObjectManager objects)
|
||||
public SetSelector(AutoDesignManager manager, AutomationChanged @event, Configuration config, ActorManager actors, ObjectManager objects)
|
||||
{
|
||||
_manager = manager;
|
||||
_event = @event;
|
||||
|
|
@ -289,9 +289,9 @@ public class SetSelector : IDisposable
|
|||
|
||||
private void NewSetButton(Vector2 size)
|
||||
{
|
||||
var id = _actors.AwaitedService.GetCurrentPlayer();
|
||||
var id = _actors.GetCurrentPlayer();
|
||||
if (!id.IsValid)
|
||||
id = _actors.AwaitedService.CreatePlayer(ByteString.FromSpanUnsafe("New Design"u8, true, false, true), ushort.MaxValue);
|
||||
id = _actors.CreatePlayer(ByteString.FromSpanUnsafe("New Design"u8, true, false, true), ushort.MaxValue);
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), size,
|
||||
$"Create a new Automatic Design Set for {id}. The associated player can be changed later.", !id.IsValid, true))
|
||||
_manager.AddDesignSet("New Design", id);
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ public class ActiveStatePanel(StateManager _stateManager, ObjectManager _objectM
|
|||
static string ItemString(in DesignData data, EquipSlot slot)
|
||||
{
|
||||
var item = data.Item(slot);
|
||||
return $"{item.Name} ({item.ModelId.Id}{(item.WeaponType != 0 ? $"-{item.WeaponType.Id}" : string.Empty)}-{item.Variant})";
|
||||
return $"{item.Name} ({item.PrimaryId.Id}{(item.SecondaryId != 0 ? $"-{item.SecondaryId.Id}" : string.Empty)}-{item.Variant})";
|
||||
}
|
||||
|
||||
PrintRow("Model ID", state.BaseData.ModelId, state.ModelData.ModelId, state[ActorState.MetaIndex.ModelId]);
|
||||
|
|
|
|||
|
|
@ -1,23 +1,23 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Glamourer.Services;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using ImGuiClip = OtterGui.ImGuiClip;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class ActorServicePanel(ActorService _actors, ItemManager _items) : IDebugTabTree
|
||||
public class ActorManagerPanel(ActorManager _actors, DictBNpcNames _bNpcNames) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Actor Service";
|
||||
|
||||
public bool Disabled
|
||||
=> !_actors.Valid;
|
||||
=> !_actors.Awaiter.IsCompletedSuccessfully;
|
||||
|
||||
private string _bnpcFilter = string.Empty;
|
||||
private string _enpcFilter = string.Empty;
|
||||
|
|
@ -29,11 +29,11 @@ public class ActorServicePanel(ActorService _actors, ItemManager _items) : IDebu
|
|||
public void Draw()
|
||||
{
|
||||
DrawBnpcTable();
|
||||
DebugTab.DrawNameTable("ENPCs", ref _enpcFilter, _actors.AwaitedService.Data.ENpcs.Select(kvp => (kvp.Key, kvp.Value)));
|
||||
DebugTab.DrawNameTable("Companions", ref _companionFilter, _actors.AwaitedService.Data.Companions.Select(kvp => (kvp.Key, kvp.Value)));
|
||||
DebugTab.DrawNameTable("Mounts", ref _mountFilter, _actors.AwaitedService.Data.Mounts.Select(kvp => (kvp.Key, kvp.Value)));
|
||||
DebugTab.DrawNameTable("Ornaments", ref _ornamentFilter, _actors.AwaitedService.Data.Ornaments.Select(kvp => (kvp.Key, kvp.Value)));
|
||||
DebugTab.DrawNameTable("Worlds", ref _worldFilter, _actors.AwaitedService.Data.Worlds.Select(kvp => ((uint)kvp.Key, kvp.Value)));
|
||||
DebugTab.DrawNameTable("ENPCs", ref _enpcFilter, _actors.Data.ENpcs.Select(kvp => (kvp.Key.Id, kvp.Value)));
|
||||
DebugTab.DrawNameTable("Companions", ref _companionFilter, _actors.Data.Companions.Select(kvp => (kvp.Key.Id, kvp.Value)));
|
||||
DebugTab.DrawNameTable("Mounts", ref _mountFilter, _actors.Data.Mounts.Select(kvp => (kvp.Key.Id, kvp.Value)));
|
||||
DebugTab.DrawNameTable("Ornaments", ref _ornamentFilter, _actors.Data.Ornaments.Select(kvp => (kvp.Key.Id, kvp.Value)));
|
||||
DebugTab.DrawNameTable("Worlds", ref _worldFilter, _actors.Data.Worlds.Select(kvp => ((uint)kvp.Key.Id, kvp.Value)));
|
||||
}
|
||||
|
||||
private void DrawBnpcTable()
|
||||
|
|
@ -58,15 +58,15 @@ public class ActorServicePanel(ActorService _actors, ItemManager _items) : IDebu
|
|||
ImGui.TableNextColumn();
|
||||
var skips = ImGuiClip.GetNecessarySkips(height);
|
||||
ImGui.TableNextRow();
|
||||
var data = _actors.AwaitedService.Data.BNpcs.Select(kvp => (kvp.Key, kvp.Key.ToString("D5"), kvp.Value));
|
||||
var data = _actors.Data.BNpcs.Select(kvp => (kvp.Key, kvp.Key.Id.ToString("D5"), kvp.Value));
|
||||
var remainder = ImGuiClip.FilteredClippedDraw(data, skips,
|
||||
p => p.Item2.Contains(_bnpcFilter) || p.Item3.Contains(_bnpcFilter, StringComparison.OrdinalIgnoreCase),
|
||||
p => p.Item2.Contains(_bnpcFilter) || p.Value.Contains(_bnpcFilter, StringComparison.OrdinalIgnoreCase),
|
||||
p =>
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(p.Item2);
|
||||
ImGuiUtil.DrawTableColumn(p.Item3);
|
||||
var bnpcs = _items.IdentifierService.AwaitedService.GetBnpcsFromName(p.Item1);
|
||||
ImGuiUtil.DrawTableColumn(string.Join(", ", bnpcs.Select(b => b.Id.ToString())));
|
||||
ImGuiUtil.DrawTableColumn(p.Value);
|
||||
var bNpcs = _bNpcNames.GetBNpcsFromName(p.Key.BNpcNameId);
|
||||
ImGuiUtil.DrawTableColumn(string.Join(", ", bNpcs.Select(b => b.Id.ToString())));
|
||||
});
|
||||
ImGuiClip.DrawEndDummy(remainder, height);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,15 +13,15 @@ public class CustomizationServicePanel(CustomizationService _customization) : ID
|
|||
=> "Customization Service";
|
||||
|
||||
public bool Disabled
|
||||
=> !_customization.Valid;
|
||||
=> !_customization.Awaiter.IsCompletedSuccessfully;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
foreach (var clan in _customization.AwaitedService.Clans)
|
||||
foreach (var clan in _customization.Service.Clans)
|
||||
{
|
||||
foreach (var gender in _customization.AwaitedService.Genders)
|
||||
foreach (var gender in _customization.Service.Genders)
|
||||
{
|
||||
var set = _customization.AwaitedService.GetList(clan, gender);
|
||||
var set = _customization.Service.GetList(clan, gender);
|
||||
DrawCustomizationInfo(set);
|
||||
DrawNpcCustomizationInfo(set);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@ using System.Collections.Generic;
|
|||
using ImGuiNET;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Services;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public interface IDebugTabTree
|
||||
public interface IDebugTabTree : IService
|
||||
{
|
||||
public string Label { get; }
|
||||
public void Draw();
|
||||
|
|
@ -54,7 +55,7 @@ public class DebugTabHeader(string label, params IDebugTabTree[] subTrees)
|
|||
"Game Data",
|
||||
provider.GetRequiredService<IdentifierPanel>(),
|
||||
provider.GetRequiredService<RestrictedGearPanel>(),
|
||||
provider.GetRequiredService<ActorServicePanel>(),
|
||||
provider.GetRequiredService<ActorManagerPanel>(),
|
||||
provider.GetRequiredService<ItemManagerPanel>(),
|
||||
provider.GetRequiredService<StainPanel>(),
|
||||
provider.GetRequiredService<CustomizationServicePanel>(),
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ using Glamourer.Structs;
|
|||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
|
|
|||
|
|
@ -3,18 +3,19 @@ using Dalamud.Interface.Utility;
|
|||
using Glamourer.Services;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class IdentifierPanel(ItemManager _items) : IDebugTabTree
|
||||
public class IdentifierPanel(ItemManager _items, GamePathParser _gamePathParser) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Identifier Service";
|
||||
|
||||
public bool Disabled
|
||||
=> !_items.IdentifierService.Valid;
|
||||
=> !_items.ObjectIdentification.Awaiter.IsCompletedSuccessfully;
|
||||
|
||||
private string _gamePath = string.Empty;
|
||||
private int _setId;
|
||||
|
|
@ -33,10 +34,10 @@ public class IdentifierPanel(ItemManager _items) : IDebugTabTree
|
|||
ImGui.SameLine();
|
||||
ImGui.SetNextItemWidth(300 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.InputTextWithHint("##gamePath", "Enter game path...", ref _gamePath, 256);
|
||||
var fileInfo = _items.IdentifierService.AwaitedService.GamePathParser.GetFileInfo(_gamePath);
|
||||
var fileInfo = _gamePathParser.GetFileInfo(_gamePath);
|
||||
ImGui.TextUnformatted(
|
||||
$"{fileInfo.ObjectType} {fileInfo.EquipSlot} {fileInfo.PrimaryId} {fileInfo.SecondaryId} {fileInfo.Variant} {fileInfo.BodySlot} {fileInfo.CustomizationType}");
|
||||
Text(string.Join("\n", _items.IdentifierService.AwaitedService.Identify(_gamePath).Keys));
|
||||
Text(string.Join("\n", _items.ObjectIdentification.Identify(_gamePath).Keys));
|
||||
|
||||
ImGui.Separator();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
|
|
@ -46,16 +47,16 @@ public class IdentifierPanel(ItemManager _items) : IDebugTabTree
|
|||
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||
{
|
||||
var identified = _items.Identify(slot, (SetId)_setId, (Variant)_variant);
|
||||
var identified = _items.Identify(slot, (PrimaryId)_setId, 0, (Variant)_variant);
|
||||
Text(identified.Name);
|
||||
ImGuiUtil.HoverTooltip(string.Join("\n",
|
||||
_items.IdentifierService.AwaitedService.Identify((SetId)_setId, (Variant)_variant, slot)
|
||||
_items.ObjectIdentification.Identify((PrimaryId)_setId, 0, (Variant)_variant, slot)
|
||||
.Select(i => $"{i.Name} {i.Id} {i.ItemId} {i.IconId}")));
|
||||
}
|
||||
|
||||
var weapon = _items.Identify(EquipSlot.MainHand, (SetId)_setId, (WeaponType)_secondaryId, (Variant)_variant);
|
||||
var weapon = _items.Identify(EquipSlot.MainHand, (PrimaryId)_setId, (SecondaryId)_secondaryId, (Variant)_variant);
|
||||
Text(weapon.Name);
|
||||
ImGuiUtil.HoverTooltip(string.Join("\n",
|
||||
_items.IdentifierService.AwaitedService.Identify((SetId)_setId, (WeaponType)_secondaryId, (Variant)_variant, EquipSlot.MainHand)));
|
||||
_items.ObjectIdentification.Identify((PrimaryId)_setId, (SecondaryId)_secondaryId, (Variant)_variant, EquipSlot.MainHand)));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ public class ItemManagerPanel(ItemManager _items) : IDebugTabTree
|
|||
=> "Item Manager";
|
||||
|
||||
public bool Disabled
|
||||
=> !_items.ItemService.Valid;
|
||||
=> !_items.ItemData.Awaiter.IsCompletedSuccessfully;
|
||||
|
||||
private string _itemFilter = string.Empty;
|
||||
|
||||
|
|
@ -22,18 +22,18 @@ public class ItemManagerPanel(ItemManager _items) : IDebugTabTree
|
|||
ImRaii.TreeNode($"Default Sword: {_items.DefaultSword.Name} ({_items.DefaultSword.ItemId}) ({_items.DefaultSword.Weapon()})",
|
||||
ImGuiTreeNodeFlags.Leaf).Dispose();
|
||||
DebugTab.DrawNameTable("All Items (Main)", ref _itemFilter,
|
||||
_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())})"))
|
||||
_items.ItemData.AllItems(true).Select(p => (p.Item1.Id,
|
||||
$"{p.Item2.Name} ({(p.Item2.SecondaryId == 0 ? p.Item2.Armor().ToString() : p.Item2.Weapon().ToString())})"))
|
||||
.OrderBy(p => p.Item1));
|
||||
DebugTab.DrawNameTable("All Items (Off)", ref _itemFilter,
|
||||
_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())})"))
|
||||
_items.ItemData.AllItems(false).Select(p => (p.Item1.Id,
|
||||
$"{p.Item2.Name} ({(p.Item2.SecondaryId == 0 ? p.Item2.Armor().ToString() : p.Item2.Weapon().ToString())})"))
|
||||
.OrderBy(p => p.Item1));
|
||||
foreach (var type in Enum.GetValues<FullEquipType>().Skip(1))
|
||||
{
|
||||
DebugTab.DrawNameTable(type.ToName(), ref _itemFilter,
|
||||
_items.ItemService.AwaitedService[type]
|
||||
.Select(p => (p.ItemId.Id, $"{p.Name} ({(p.WeaponType == 0 ? p.Armor().ToString() : p.Weapon().ToString())})")));
|
||||
_items.ItemData.ByType[type]
|
||||
.Select(p => (p.ItemId.Id, $"{p.Name} ({(p.SecondaryId.Id == 0 ? p.Armor().ToString() : p.Weapon().ToString())})")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public class ItemUnlockPanel(ItemUnlockManager _itemUnlocks, ItemManager _items)
|
|||
var remainder = ImGuiClip.ClippedDraw(_itemUnlocks, skips, t =>
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(t.Key.ToString());
|
||||
if (_items.ItemService.AwaitedService.TryGetValue(t.Key, EquipSlot.MainHand, out var equip))
|
||||
if (_items.ItemData.TryGetValue(t.Key, EquipSlot.MainHand, out var equip))
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(equip.Name);
|
||||
ImGuiUtil.DrawTableColumn(equip.Type.ToName());
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ public unsafe class ModelEvaluationPanel(
|
|||
|
||||
if (ImGui.SmallButton("Change Piece"))
|
||||
_updateSlotService.UpdateArmor(model, slot,
|
||||
new CharacterArmor((SetId)(slot == EquipSlot.Hands ? 6064 : slot == EquipSlot.Head ? 6072 : 1), 1, 0));
|
||||
new CharacterArmor((PrimaryId)(slot == EquipSlot.Hands ? 6064 : slot == EquipSlot.Head ? 6072 : 1), 1, 0));
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("Change Stain"))
|
||||
_updateSlotService.UpdateStain(model, slot, 5);
|
||||
|
|
@ -213,11 +213,11 @@ public unsafe class ModelEvaluationPanel(
|
|||
{
|
||||
using var id = ImRaii.PushId("Customize");
|
||||
var actorCustomize = new Customize(actor.IsCharacter
|
||||
? *(Penumbra.GameData.Structs.CustomizeData*)&actor.AsCharacter->DrawData.CustomizeData
|
||||
: new Penumbra.GameData.Structs.CustomizeData());
|
||||
? *(CustomizeArray*)&actor.AsCharacter->DrawData.CustomizeData
|
||||
: new CustomizeArray());
|
||||
var modelCustomize = new Customize(model.IsHuman
|
||||
? *(Penumbra.GameData.Structs.CustomizeData*)model.AsHuman->Customize.Data
|
||||
: new Penumbra.GameData.Structs.CustomizeData());
|
||||
? *(CustomizeArray*)model.AsHuman->Customize.Data
|
||||
: new CustomizeArray());
|
||||
foreach (var type in Enum.GetValues<CustomizeIndex>())
|
||||
{
|
||||
using var id2 = ImRaii.PushId((int)type);
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ public class NpcAppearancePanel(NpcCombo _npcCombo, StateManager _state, ObjectM
|
|||
|
||||
return;
|
||||
|
||||
void Draw(CustomizationNpcOptions.NpcData data)
|
||||
void Draw(NpcData data)
|
||||
{
|
||||
using var id = ImRaii.PushId(idx++);
|
||||
var disabled = !_state.GetOrCreate(_objectManager.Player, out var state);
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ using System.Globalization;
|
|||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Services;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Actors;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class ObjectManagerPanel(ObjectManager _objectManager, ActorService _actors) : IDebugTabTree
|
||||
public class ObjectManagerPanel(ObjectManager _objectManager, ActorManager _actors) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Object Manager";
|
||||
|
|
@ -33,7 +33,7 @@ public class ObjectManagerPanel(ObjectManager _objectManager, ActorService _acto
|
|||
ImGui.TableNextColumn();
|
||||
|
||||
ImGuiUtil.DrawTableColumn("World");
|
||||
ImGuiUtil.DrawTableColumn(_actors.Valid ? _actors.AwaitedService.Data.ToWorldName(_objectManager.World) : "Service Missing");
|
||||
ImGuiUtil.DrawTableColumn(_actors.Awaiter.IsCompletedSuccessfully ? _actors.Data.ToWorldName(_objectManager.World) : "Service Missing");
|
||||
ImGuiUtil.DrawTableColumn(_objectManager.World.ToString());
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Player Character");
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ public unsafe class PenumbraPanel(PenumbraService _penumbra, PenumbraChangedItem
|
|||
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.InputInt("##CutsceneIndex", ref _gameObjectIndex, 0, 0);
|
||||
ImGuiUtil.DrawTableColumn(_penumbra.Available
|
||||
? _penumbra.CutsceneParent(_gameObjectIndex).ToString()
|
||||
? _penumbra.CutsceneParent((ushort) _gameObjectIndex).ToString()
|
||||
: "Penumbra Unavailable");
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Redraw Object");
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public class RestrictedGearPanel(ItemManager _items) : IDebugTabTree
|
|||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||
{
|
||||
var (replaced, model) =
|
||||
_items.RestrictedGear.ResolveRestricted(new CharacterArmor((SetId)_setId, (Variant)_variant, 0), slot, race, gender);
|
||||
_items.RestrictedGear.ResolveRestricted(new CharacterArmor((PrimaryId)_setId, (Variant)_variant, 0), slot, race, gender);
|
||||
if (replaced)
|
||||
ImGui.TextUnformatted($"{race.ToName()} - {gender} - {slot.ToName()} resolves to {model}.");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ public class UnlockableItemsPanel(ItemUnlockManager _itemUnlocks, ItemManager _i
|
|||
var remainder = ImGuiClip.ClippedDraw(_itemUnlocks.Unlockable, skips, t =>
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(t.Key.ToString());
|
||||
if (_items.ItemService.AwaitedService.TryGetValue(t.Key, EquipSlot.MainHand, out var equip))
|
||||
if (_items.ItemData.TryGetValue(t.Key, EquipSlot.MainHand, out var equip))
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(equip.Name);
|
||||
ImGuiUtil.DrawTableColumn(equip.Type.ToName());
|
||||
|
|
|
|||
|
|
@ -1,36 +1,11 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Customization;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.GameData;
|
||||
|
||||
namespace Glamourer.Gui.Tabs;
|
||||
|
||||
public class NpcCombo(ActorService actorManager, IdentifierService identifier, IDataManager data)
|
||||
: FilterComboBase<CustomizationNpcOptions.NpcData>(new LazyList(actorManager, identifier, data), false, Glamourer.Log)
|
||||
public class NpcCombo(NpcCustomizeSet npcCustomizeSet)
|
||||
: FilterComboCache<NpcData>(npcCustomizeSet, Glamourer.Log)
|
||||
{
|
||||
private class LazyList(ActorService actorManager, IdentifierService identifier, IDataManager data)
|
||||
: IReadOnlyList<CustomizationNpcOptions.NpcData>
|
||||
{
|
||||
private readonly Task<IReadOnlyList<CustomizationNpcOptions.NpcData>> _task
|
||||
= Task.Run(() => CustomizationNpcOptions.CreateNpcData(actorManager.AwaitedService.Data.ENpcs, actorManager.AwaitedService.Data.BNpcs, identifier.AwaitedService, data));
|
||||
|
||||
public IEnumerator<CustomizationNpcOptions.NpcData> GetEnumerator()
|
||||
=> _task.Result.GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
=> GetEnumerator();
|
||||
|
||||
public int Count
|
||||
=> _task.Result.Count;
|
||||
|
||||
public CustomizationNpcOptions.NpcData this[int index]
|
||||
=> _task.Result[index];
|
||||
}
|
||||
|
||||
protected override string ToString(CustomizationNpcOptions.NpcData obj)
|
||||
protected override string ToString(NpcData obj)
|
||||
=> obj.Name;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ public class SettingsTab : ITab
|
|||
if (!child)
|
||||
return;
|
||||
|
||||
Checkbox("Enable Auto Designs", "Enable the application of designs associated to characters to be applied automatically.",
|
||||
Checkbox("Enable Auto Designs", "Enable the application of designs associated to characters in the Automation tab to be applied automatically.",
|
||||
_config.EnableAutoDesigns, v => _config.EnableAutoDesigns = v);
|
||||
ImGui.NewLine();
|
||||
ImGui.NewLine();
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ public class UnlockOverview
|
|||
|
||||
foreach (var type in Enum.GetValues<FullEquipType>())
|
||||
{
|
||||
if (type.IsOffhandType() || !_items.ItemService.AwaitedService.TryGetValue(type, out var items) || items.Count == 0)
|
||||
if (type.IsOffhandType() || !_items.ItemData.ByType.TryGetValue(type, out var items) || items.Count == 0)
|
||||
continue;
|
||||
|
||||
if (ImGui.Selectable(type.ToName(), _selected1 == type))
|
||||
|
|
@ -52,11 +52,11 @@ public class UnlockOverview
|
|||
}
|
||||
}
|
||||
|
||||
foreach (var clan in _customizations.AwaitedService.Clans)
|
||||
foreach (var clan in _customizations.Service.Clans)
|
||||
{
|
||||
foreach (var gender in _customizations.AwaitedService.Genders)
|
||||
foreach (var gender in _customizations.Service.Genders)
|
||||
{
|
||||
if (_customizations.AwaitedService.GetList(clan, gender).HairStyles.Count == 0)
|
||||
if (_customizations.Service.GetList(clan, gender).HairStyles.Count == 0)
|
||||
continue;
|
||||
|
||||
if (ImGui.Selectable($"{(gender is Gender.Male ? '♂' : '♀')} {clan.ToShortName()} Hair & Paint",
|
||||
|
|
@ -107,7 +107,7 @@ public class UnlockOverview
|
|||
|
||||
private void DrawCustomizations()
|
||||
{
|
||||
var set = _customizations.AwaitedService.GetList(_selected2, _selected3);
|
||||
var set = _customizations.Service.GetList(_selected2, _selected3);
|
||||
|
||||
var spacing = IconSpacing;
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing);
|
||||
|
|
@ -121,7 +121,7 @@ public class UnlockOverview
|
|||
continue;
|
||||
|
||||
var unlocked = _customizeUnlocks.IsUnlocked(customize, out var time);
|
||||
var icon = _customizations.AwaitedService.GetIcon(customize.IconId);
|
||||
var icon = _customizations.Service.GetIcon(customize.IconId);
|
||||
|
||||
ImGui.Image(icon.ImGuiHandle, iconSize, Vector2.Zero, Vector2.One,
|
||||
unlocked || _codes.EnabledShirts ? Vector4.One : UnavailableTint);
|
||||
|
|
@ -150,7 +150,7 @@ public class UnlockOverview
|
|||
|
||||
private void DrawItems()
|
||||
{
|
||||
if (!_items.ItemService.AwaitedService.TryGetValue(_selected1, out var items))
|
||||
if (!_items.ItemData.ByType.TryGetValue(_selected1, out var items))
|
||||
return;
|
||||
|
||||
var spacing = IconSpacing;
|
||||
|
|
@ -160,6 +160,30 @@ public class UnlockOverview
|
|||
var numRows = (items.Count + iconsPerRow - 1) / iconsPerRow;
|
||||
var numVisibleRows = (int)(Math.Ceiling(ImGui.GetContentRegionAvail().Y / (iconSize.Y + spacing.Y)) + 0.5f) + 1;
|
||||
|
||||
var skips = ImGuiClip.GetNecessarySkips(iconSize.Y + spacing.Y);
|
||||
var end = Math.Min(numVisibleRows * iconsPerRow + skips * iconsPerRow, items.Count);
|
||||
var counter = 0;
|
||||
for (var idx = skips * iconsPerRow; idx < end; ++idx)
|
||||
{
|
||||
DrawItem(items[idx]);
|
||||
if (counter != iconsPerRow - 1)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
++counter;
|
||||
}
|
||||
else
|
||||
{
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui.GetCursorPosX() != 0)
|
||||
ImGui.NewLine();
|
||||
var remainder = numRows - numVisibleRows - skips;
|
||||
if (remainder > 0)
|
||||
ImGuiClip.DrawEndDummy(remainder, iconSize.Y + spacing.Y);
|
||||
return;
|
||||
|
||||
void DrawItem(EquipItem item)
|
||||
{
|
||||
var unlocked = _itemUnlocks.IsUnlocked(item.Id, out var time);
|
||||
|
|
@ -189,7 +213,7 @@ public class UnlockOverview
|
|||
ImGui.TextUnformatted($"{item.Type.ToName()} ({slot.ToName()})");
|
||||
if (item.Type.ValidOffhand().IsOffhandType())
|
||||
ImGui.TextUnformatted(
|
||||
$"{item.Weapon()}{(_items.ItemService.AwaitedService.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand) ? $" | {offhand.Weapon()}" : string.Empty)}");
|
||||
$"{item.Weapon()}{(_items.ItemData.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand) ? $" | {offhand.Weapon()}" : string.Empty)}");
|
||||
else
|
||||
ImGui.TextUnformatted(slot is EquipSlot.MainHand ? $"{item.Weapon()}" : $"{item.Armor()}");
|
||||
ImGui.TextUnformatted(
|
||||
|
|
@ -219,29 +243,6 @@ public class UnlockOverview
|
|||
_tooltip.CreateTooltip(item, string.Empty, false);
|
||||
}
|
||||
}
|
||||
|
||||
var skips = ImGuiClip.GetNecessarySkips(iconSize.Y + spacing.Y);
|
||||
var end = Math.Min(numVisibleRows * iconsPerRow + skips * iconsPerRow, items.Count);
|
||||
var counter = 0;
|
||||
for (var idx = skips * iconsPerRow; idx < end; ++idx)
|
||||
{
|
||||
DrawItem(items[idx]);
|
||||
if (counter != iconsPerRow - 1)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
++counter;
|
||||
}
|
||||
else
|
||||
{
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui.GetCursorPosX() != 0)
|
||||
ImGui.NewLine();
|
||||
var remainder = numRows - numVisibleRows - skips;
|
||||
if (remainder > 0)
|
||||
ImGuiClip.DrawEndDummy(remainder, iconSize.Y + spacing.Y);
|
||||
}
|
||||
|
||||
private static Vector2 IconSpacing
|
||||
|
|
|
|||
|
|
@ -278,7 +278,7 @@ public class UnlockTable : Table<EquipItem>, IDisposable
|
|||
ImGuiUtil.RightAlign(item.ModelString);
|
||||
if (ImGui.IsItemHovered()
|
||||
&& item.Type.ValidOffhand().IsOffhandType()
|
||||
&& _items.ItemService.AwaitedService.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand))
|
||||
&& _items.ItemData.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand))
|
||||
{
|
||||
using var tt = ImRaii.Tooltip();
|
||||
ImGui.TextUnformatted("Offhand: " + offhand.ModelString);
|
||||
|
|
@ -297,7 +297,7 @@ public class UnlockTable : Table<EquipItem>, IDisposable
|
|||
return true;
|
||||
|
||||
if (item.Type.ValidOffhand().IsOffhandType()
|
||||
&& _items.ItemService.AwaitedService.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand))
|
||||
&& _items.ItemData.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand))
|
||||
return FilterRegex?.IsMatch(offhand.ModelString)
|
||||
?? offhand.ModelString.Contains(FilterValue, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
|
|
@ -411,21 +411,16 @@ public class UnlockTable : Table<EquipItem>, IDisposable
|
|||
=> item.Flags.HasFlag(ItemFlags.IsCrestWorthy);
|
||||
}
|
||||
|
||||
private sealed class ItemList : IReadOnlyCollection<EquipItem>
|
||||
private sealed class ItemList(ItemManager items) : IReadOnlyCollection<EquipItem>
|
||||
{
|
||||
private readonly ItemManager _items;
|
||||
|
||||
public ItemList(ItemManager items)
|
||||
=> _items = items;
|
||||
|
||||
public IEnumerator<EquipItem> GetEnumerator()
|
||||
=> _items.ItemService.AwaitedService.AllItems(true).Select(i => i.Item2).GetEnumerator();
|
||||
=> items.ItemData.AllItems(true).Select(i => i.Item2).GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
=> GetEnumerator();
|
||||
|
||||
public int Count
|
||||
=> _items.ItemService.AwaitedService.TotalItemCount(true);
|
||||
=> items.ItemData.Primary.Count;
|
||||
}
|
||||
|
||||
private void OnObjectUnlock(ObjectUnlocked.Type _1, uint _2, DateTimeOffset _3)
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ public static class UiHelpers
|
|||
|
||||
public static void DrawIcon(this EquipItem item, TextureService textures, Vector2 size, EquipSlot slot)
|
||||
{
|
||||
var isEmpty = item.ModelId.Id == 0;
|
||||
var isEmpty = item.PrimaryId.Id == 0;
|
||||
var (ptr, textureSize, empty) = textures.GetIcon(item, slot);
|
||||
if (empty)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
|
|
@ -7,7 +6,7 @@ using Glamourer.Customization;
|
|||
using Glamourer.Events;
|
||||
using Glamourer.Interop.Structs;
|
||||
using OtterGui.Classes;
|
||||
using CustomizeData = Penumbra.GameData.Structs.CustomizeData;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Interop;
|
||||
|
||||
|
|
@ -64,7 +63,7 @@ public unsafe class ChangeCustomizeService : EventWrapper<Action<Model, Ref<Cust
|
|||
|
||||
private Hook<ChangeCustomizeDelegate> _changeCustomizeHook;
|
||||
|
||||
public bool UpdateCustomize(Model model, CustomizeData customize)
|
||||
public bool UpdateCustomize(Model model, CustomizeArray customize)
|
||||
{
|
||||
if (!model.IsHuman)
|
||||
return false;
|
||||
|
|
@ -75,14 +74,14 @@ public unsafe class ChangeCustomizeService : EventWrapper<Action<Model, Ref<Cust
|
|||
return ret;
|
||||
}
|
||||
|
||||
public bool UpdateCustomize(Actor actor, CustomizeData customize)
|
||||
public bool UpdateCustomize(Actor actor, CustomizeArray customize)
|
||||
=> UpdateCustomize(actor.Model, customize);
|
||||
|
||||
private bool ChangeCustomizeDetour(Human* human, byte* data, byte skipEquipment)
|
||||
{
|
||||
if (!InUpdate.InMethod)
|
||||
{
|
||||
var customize = new Ref<Customize>(new Customize(*(CustomizeData*)data));
|
||||
var customize = new Ref<Customize>(new Customize(*(CustomizeArray*)data));
|
||||
Invoke(this, (Model)human, customize);
|
||||
((Customize*)data)->Load(customize.Value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,8 +78,8 @@ public sealed class CmaFile
|
|||
return;
|
||||
}
|
||||
|
||||
var set = mainhand["Item1"]?.ToObject<ushort>() ?? items.DefaultSword.ModelId;
|
||||
var type = mainhand["Item2"]?.ToObject<ushort>() ?? items.DefaultSword.WeaponType;
|
||||
var set = mainhand["Item1"]?.ToObject<ushort>() ?? items.DefaultSword.PrimaryId;
|
||||
var type = mainhand["Item2"]?.ToObject<ushort>() ?? items.DefaultSword.SecondaryId;
|
||||
var variant = mainhand["Item3"]?.ToObject<byte>() ?? items.DefaultSword.Variant;
|
||||
var stain = mainhand["Item4"]?.ToObject<byte>() ?? 0;
|
||||
var item = items.Identify(EquipSlot.MainHand, set, type, variant);
|
||||
|
|
@ -95,17 +95,17 @@ public sealed class CmaFile
|
|||
if (offhand == null)
|
||||
{
|
||||
data.SetItem(EquipSlot.MainHand, defaultOffhand);
|
||||
data.SetStain(EquipSlot.MainHand, defaultOffhand.ModelId.Id == 0 ? 0 : data.Stain(EquipSlot.MainHand));
|
||||
data.SetStain(EquipSlot.MainHand, defaultOffhand.PrimaryId.Id == 0 ? 0 : data.Stain(EquipSlot.MainHand));
|
||||
return;
|
||||
}
|
||||
|
||||
var set = offhand["Item1"]?.ToObject<ushort>() ?? items.DefaultSword.ModelId;
|
||||
var type = offhand["Item2"]?.ToObject<ushort>() ?? items.DefaultSword.WeaponType;
|
||||
var set = offhand["Item1"]?.ToObject<ushort>() ?? items.DefaultSword.PrimaryId;
|
||||
var type = offhand["Item2"]?.ToObject<ushort>() ?? items.DefaultSword.SecondaryId;
|
||||
var variant = offhand["Item3"]?.ToObject<byte>() ?? items.DefaultSword.Variant;
|
||||
var stain = offhand["Item4"]?.ToObject<byte>() ?? 0;
|
||||
var item = items.Identify(EquipSlot.OffHand, set, type, variant, data.MainhandType);
|
||||
|
||||
data.SetItem(EquipSlot.OffHand, item.Valid ? item : defaultOffhand);
|
||||
data.SetStain(EquipSlot.OffHand, defaultOffhand.ModelId.Id == 0 ? 0 : (StainId)stain);
|
||||
data.SetStain(EquipSlot.OffHand, defaultOffhand.PrimaryId.Id == 0 ? 0 : (StainId)stain);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ public class ContextMenuService : IDisposable
|
|||
if (itemId > 500000)
|
||||
itemId -= 500000;
|
||||
|
||||
if (!_items.ItemService.AwaitedService.TryGetValue(itemId, EquipSlot.MainHand, out var item))
|
||||
if (!_items.ItemData.TryGetValue(itemId, EquipSlot.MainHand, out var item))
|
||||
return null;
|
||||
|
||||
return new InventoryContextMenuItem(TryOnString, GetInventoryAction(item));
|
||||
|
|
@ -80,7 +80,7 @@ public class ContextMenuService : IDisposable
|
|||
if (itemId > 500000)
|
||||
itemId -= 500000;
|
||||
|
||||
if (!_items.ItemService.AwaitedService.TryGetValue(itemId, EquipSlot.MainHand, out var item))
|
||||
if (!_items.ItemData.TryGetValue(itemId, EquipSlot.MainHand, out var item))
|
||||
return null;
|
||||
|
||||
return new GameObjectContextMenuItem(TryOnString, GetGameObjectAction(item));
|
||||
|
|
@ -122,10 +122,10 @@ public class ContextMenuService : IDisposable
|
|||
_state.ChangeEquip(state, slot, item, 0, StateChanged.Source.Manual);
|
||||
if (item.Type.ValidOffhand().IsOffhandType())
|
||||
{
|
||||
if (item.ModelId.Id is > 1600 and < 1651
|
||||
&& _items.ItemService.AwaitedService.TryGetValue(item.ItemId, EquipSlot.Hands, out var gauntlets))
|
||||
if (item.PrimaryId.Id is > 1600 and < 1651
|
||||
&& _items.ItemData.TryGetValue(item.ItemId, EquipSlot.Hands, out var gauntlets))
|
||||
_state.ChangeEquip(state, EquipSlot.Hands, gauntlets, 0, StateChanged.Source.Manual);
|
||||
if (_items.ItemService.AwaitedService.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand))
|
||||
if (_items.ItemData.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand))
|
||||
_state.ChangeEquip(state, EquipSlot.OffHand, offhand, 0, StateChanged.Source.Manual);
|
||||
}
|
||||
};
|
||||
|
|
@ -146,10 +146,10 @@ public class ContextMenuService : IDisposable
|
|||
_state.ChangeEquip(state, slot, item, 0, StateChanged.Source.Manual);
|
||||
if (item.Type.ValidOffhand().IsOffhandType())
|
||||
{
|
||||
if (item.ModelId.Id is > 1600 and < 1651
|
||||
&& _items.ItemService.AwaitedService.TryGetValue(item.ItemId, EquipSlot.Hands, out var gauntlets))
|
||||
if (item.PrimaryId.Id is > 1600 and < 1651
|
||||
&& _items.ItemData.TryGetValue(item.ItemId, EquipSlot.Hands, out var gauntlets))
|
||||
_state.ChangeEquip(state, EquipSlot.Hands, gauntlets, 0, StateChanged.Source.Manual);
|
||||
if (_items.ItemService.AwaitedService.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand))
|
||||
if (_items.ItemData.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand))
|
||||
_state.ChangeEquip(state, EquipSlot.OffHand, offhand, 0, StateChanged.Source.Manual);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ public class ImportService(CustomizationService _customizations, IDragDropManage
|
|||
if (input.BodyType.Value != 1)
|
||||
return false;
|
||||
|
||||
var set = _customizations.AwaitedService.GetList(input.Clan, input.Gender);
|
||||
var set = _customizations.Service.GetList(input.Clan, input.Gender);
|
||||
voice = set.Voices[0];
|
||||
if (inputVoice.HasValue && !set.Voices.Contains(inputVoice.Value))
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ using Dalamud.Game.ClientState.Objects;
|
|||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Control;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.Services;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Interop;
|
||||
|
||||
|
|
@ -15,13 +15,13 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
|||
private readonly IFramework _framework;
|
||||
private readonly IClientState _clientState;
|
||||
private readonly IObjectTable _objects;
|
||||
private readonly ActorService _actors;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly ITargetManager _targets;
|
||||
|
||||
public IObjectTable Objects
|
||||
=> _objects;
|
||||
|
||||
public ObjectManager(IFramework framework, IClientState clientState, IObjectTable objects, ActorService actors, ITargetManager targets)
|
||||
public ObjectManager(IFramework framework, IClientState clientState, IObjectTable objects, ActorManager actors, ITargetManager targets)
|
||||
{
|
||||
_framework = framework;
|
||||
_clientState = clientState;
|
||||
|
|
@ -57,7 +57,7 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
|||
for (var i = 0; i < (int)ScreenActor.CutsceneStart; ++i)
|
||||
{
|
||||
Actor character = _objects.GetObjectAddress(i);
|
||||
if (character.Identifier(_actors.AwaitedService, out var identifier))
|
||||
if (character.Identifier(_actors, out var identifier))
|
||||
HandleIdentifier(identifier, character);
|
||||
}
|
||||
|
||||
|
|
@ -70,13 +70,13 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
|||
if (!character.Valid && i == (int)ScreenActor.CutsceneStart)
|
||||
break;
|
||||
|
||||
HandleIdentifier(character.GetIdentifier(_actors.AwaitedService), character);
|
||||
HandleIdentifier(character.GetIdentifier(_actors), character);
|
||||
}
|
||||
|
||||
void AddSpecial(ScreenActor idx, string label)
|
||||
{
|
||||
Actor actor = _objects.GetObjectAddress((int)idx);
|
||||
if (actor.Identifier(_actors.AwaitedService, out var ident))
|
||||
if (actor.Identifier(_actors, out var ident))
|
||||
{
|
||||
var data = new ActorData(actor, label);
|
||||
_identifiers.Add(ident, data);
|
||||
|
|
@ -95,7 +95,7 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
|||
for (var i = (int)ScreenActor.ScreenEnd; i < _objects.Length; ++i)
|
||||
{
|
||||
Actor character = _objects.GetObjectAddress(i);
|
||||
if (character.Identifier(_actors.AwaitedService, out var identifier))
|
||||
if (character.Identifier(_actors, out var identifier))
|
||||
HandleIdentifier(identifier, character);
|
||||
}
|
||||
|
||||
|
|
@ -120,7 +120,7 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
|||
|
||||
if (identifier.Type is IdentifierType.Player or IdentifierType.Owned)
|
||||
{
|
||||
var allWorld = _actors.AwaitedService.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, ushort.MaxValue,
|
||||
var allWorld = _actors.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, ushort.MaxValue,
|
||||
identifier.Kind,
|
||||
identifier.DataId);
|
||||
|
||||
|
|
@ -137,7 +137,7 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
|||
|
||||
if (identifier.Type is IdentifierType.Owned)
|
||||
{
|
||||
var nonOwned = _actors.AwaitedService.CreateNpc(identifier.Kind, identifier.DataId);
|
||||
var nonOwned = _actors.CreateNpc(identifier.Kind, identifier.DataId);
|
||||
if (!_nonOwnedIdentifiers.TryGetValue(nonOwned, out var nonOwnedData))
|
||||
{
|
||||
nonOwnedData = new ActorData(character, nonOwned.ToString());
|
||||
|
|
@ -170,7 +170,7 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
|||
get
|
||||
{
|
||||
Update();
|
||||
return Player.Identifier(_actors.AwaitedService, out var ident) && _identifiers.TryGetValue(ident, out var data)
|
||||
return Player.Identifier(_actors, out var ident) && _identifiers.TryGetValue(ident, out var data)
|
||||
? (ident, data)
|
||||
: (ident, ActorData.Invalid);
|
||||
}
|
||||
|
|
@ -181,7 +181,7 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
|||
get
|
||||
{
|
||||
Update();
|
||||
return Target.Identifier(_actors.AwaitedService, out var ident) && _identifiers.TryGetValue(ident, out var data)
|
||||
return Target.Identifier(_actors, out var ident) && _identifiers.TryGetValue(ident, out var data)
|
||||
? (ident, data)
|
||||
: (ident, ActorData.Invalid);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -221,8 +221,8 @@ public unsafe class PenumbraService : IDisposable
|
|||
=> Available ? _drawObjectInfo.Invoke(drawObject.Address).Item1 : Actor.Null;
|
||||
|
||||
/// <summary> Obtain the parent of a cutscene actor if it is known. </summary>
|
||||
public int CutsceneParent(int idx)
|
||||
=> Available ? _cutsceneParent.Invoke(idx) : -1;
|
||||
public short CutsceneParent(ushort idx)
|
||||
=> (short) (Available ? _cutsceneParent.Invoke(idx) : -1);
|
||||
|
||||
/// <summary> Try to redraw the given actor. </summary>
|
||||
public void RedrawObject(Actor actor, RedrawType settings)
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ public unsafe class WeaponService : IDisposable
|
|||
|
||||
if (tmpWeapon.Value != weapon.Value)
|
||||
{
|
||||
if (tmpWeapon.Set.Id == 0)
|
||||
if (tmpWeapon.X.Id == 0)
|
||||
tmpWeapon.Stain = 0;
|
||||
_loadWeaponHook.Original(drawData, slot, tmpWeapon.Value, 1, unk2, 1, unk4);
|
||||
}
|
||||
|
|
@ -119,7 +119,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.Id == 0 ? 0 : stain);
|
||||
var weapon = value.With(value.X.Id == 0 ? 0 : stain);
|
||||
LoadWeapon(character, slot, weapon);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ using ImGuiNET;
|
|||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Services;
|
||||
|
||||
|
|
@ -27,7 +28,7 @@ public class CommandService : IDisposable
|
|||
private readonly ICommandManager _commands;
|
||||
private readonly MainWindow _mainWindow;
|
||||
private readonly IChatGui _chat;
|
||||
private readonly ActorService _actors;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly StateManager _stateManager;
|
||||
private readonly AutoDesignApplier _autoDesignApplier;
|
||||
|
|
@ -37,7 +38,7 @@ public class CommandService : IDisposable
|
|||
private readonly DesignFileSystem _designFileSystem;
|
||||
private readonly Configuration _config;
|
||||
|
||||
public CommandService(ICommandManager commands, MainWindow mainWindow, IChatGui chat, ActorService actors, ObjectManager objects,
|
||||
public CommandService(ICommandManager commands, MainWindow mainWindow, IChatGui chat, ActorManager actors, ObjectManager objects,
|
||||
AutoDesignApplier autoDesignApplier, StateManager stateManager, DesignManager designManager, DesignConverter converter,
|
||||
DesignFileSystem designFileSystem, AutoDesignManager autoDesignManager, Configuration config)
|
||||
{
|
||||
|
|
@ -402,7 +403,7 @@ public class CommandService : IDisposable
|
|||
{
|
||||
foreach (var actor in actors.Objects)
|
||||
{
|
||||
if (_stateManager.GetOrCreate(actor.GetIdentifier(_actors.AwaitedService), actor, out var state))
|
||||
if (_stateManager.GetOrCreate(actor.GetIdentifier(_actors), actor, out var state))
|
||||
_stateManager.ApplyDesign(design, state, StateChanged.Source.Manual);
|
||||
}
|
||||
}
|
||||
|
|
@ -537,7 +538,7 @@ public class CommandService : IDisposable
|
|||
{
|
||||
if (_objects.GetName(argument.ToLowerInvariant(), out var obj))
|
||||
{
|
||||
var identifier = _actors.AwaitedService.FromObject(obj.AsObject, out _, true, true, true);
|
||||
var identifier = _actors.FromObject(obj.AsObject, out _, true, true, true);
|
||||
if (!identifier.IsValid)
|
||||
{
|
||||
_chat.Print(new SeStringBuilder().AddText("The placeholder ").AddGreen(argument)
|
||||
|
|
@ -547,7 +548,7 @@ public class CommandService : IDisposable
|
|||
}
|
||||
|
||||
if (allowIndex && identifier.Type is IdentifierType.Npc)
|
||||
identifier = _actors.AwaitedService.CreateNpc(identifier.Kind, identifier.DataId, obj.Index);
|
||||
identifier = _actors.CreateNpc(identifier.Kind, identifier.DataId, obj.Index);
|
||||
identifiers = new[]
|
||||
{
|
||||
identifier,
|
||||
|
|
@ -555,7 +556,7 @@ public class CommandService : IDisposable
|
|||
}
|
||||
else
|
||||
{
|
||||
identifiers = _actors.AwaitedService.FromUserString(argument, allowIndex);
|
||||
identifiers = _actors.FromUserString(argument, allowIndex);
|
||||
if (!allowAnyWorld
|
||||
&& identifiers[0].Type is IdentifierType.Player or IdentifierType.Owned
|
||||
&& identifiers[0].HomeWorld == ushort.MaxValue)
|
||||
|
|
|
|||
|
|
@ -1,19 +1,34 @@
|
|||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Customization;
|
||||
using Penumbra.GameData.Data;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Services;
|
||||
|
||||
public sealed class CustomizationService : AsyncServiceWrapper<ICustomizationManager>
|
||||
public sealed class CustomizationService(
|
||||
ITextureProvider textures,
|
||||
IDataManager gameData,
|
||||
HumanModelList humanModels,
|
||||
IPluginLog log,
|
||||
NpcCustomizeSet npcCustomizeSet)
|
||||
: IAsyncService
|
||||
{
|
||||
public readonly HumanModelList HumanModels;
|
||||
public readonly HumanModelList HumanModels = humanModels;
|
||||
|
||||
public CustomizationService(ITextureProvider textures, IDataManager gameData, HumanModelList humanModels, IPluginLog log)
|
||||
: base(nameof(CustomizationService), () => CustomizationManager.Create(textures, gameData, log))
|
||||
=> HumanModels = humanModels;
|
||||
private ICustomizationManager? _service;
|
||||
|
||||
private readonly Task<ICustomizationManager> _task = Task.WhenAll(humanModels.Awaiter, npcCustomizeSet.Awaiter)
|
||||
.ContinueWith(_ => CustomizationManager.Create(textures, gameData, log, npcCustomizeSet));
|
||||
|
||||
public ICustomizationManager Service
|
||||
=> _service ??= _task.Result;
|
||||
|
||||
public Task Awaiter
|
||||
=> _task;
|
||||
|
||||
public (Customize NewValue, CustomizeFlag Applied, CustomizeFlag Changed) Combine(Customize oldValues, Customize newValues,
|
||||
CustomizeFlag applyWhich, bool allowUnknown)
|
||||
|
|
@ -36,7 +51,7 @@ public sealed class CustomizationService : AsyncServiceWrapper<ICustomizationMan
|
|||
}
|
||||
|
||||
|
||||
var set = AwaitedService.GetList(ret.Clan, ret.Gender);
|
||||
var set = Service.GetList(ret.Clan, ret.Gender);
|
||||
applyWhich = applyWhich.FixApplication(set);
|
||||
foreach (var index in CustomizationExtensions.AllBasic)
|
||||
{
|
||||
|
|
@ -66,38 +81,38 @@ public sealed class CustomizationService : AsyncServiceWrapper<ICustomizationMan
|
|||
gender = Gender.Male;
|
||||
return (gender, race) switch
|
||||
{
|
||||
(Gender.Male, SubRace.Midlander) => AwaitedService.GetName(CustomName.MidlanderM),
|
||||
(Gender.Male, SubRace.Highlander) => AwaitedService.GetName(CustomName.HighlanderM),
|
||||
(Gender.Male, SubRace.Wildwood) => AwaitedService.GetName(CustomName.WildwoodM),
|
||||
(Gender.Male, SubRace.Duskwight) => AwaitedService.GetName(CustomName.DuskwightM),
|
||||
(Gender.Male, SubRace.Plainsfolk) => AwaitedService.GetName(CustomName.PlainsfolkM),
|
||||
(Gender.Male, SubRace.Dunesfolk) => AwaitedService.GetName(CustomName.DunesfolkM),
|
||||
(Gender.Male, SubRace.SeekerOfTheSun) => AwaitedService.GetName(CustomName.SeekerOfTheSunM),
|
||||
(Gender.Male, SubRace.KeeperOfTheMoon) => AwaitedService.GetName(CustomName.KeeperOfTheMoonM),
|
||||
(Gender.Male, SubRace.Seawolf) => AwaitedService.GetName(CustomName.SeawolfM),
|
||||
(Gender.Male, SubRace.Hellsguard) => AwaitedService.GetName(CustomName.HellsguardM),
|
||||
(Gender.Male, SubRace.Raen) => AwaitedService.GetName(CustomName.RaenM),
|
||||
(Gender.Male, SubRace.Xaela) => AwaitedService.GetName(CustomName.XaelaM),
|
||||
(Gender.Male, SubRace.Helion) => AwaitedService.GetName(CustomName.HelionM),
|
||||
(Gender.Male, SubRace.Lost) => AwaitedService.GetName(CustomName.LostM),
|
||||
(Gender.Male, SubRace.Rava) => AwaitedService.GetName(CustomName.RavaM),
|
||||
(Gender.Male, SubRace.Veena) => AwaitedService.GetName(CustomName.VeenaM),
|
||||
(Gender.Female, SubRace.Midlander) => AwaitedService.GetName(CustomName.MidlanderF),
|
||||
(Gender.Female, SubRace.Highlander) => AwaitedService.GetName(CustomName.HighlanderF),
|
||||
(Gender.Female, SubRace.Wildwood) => AwaitedService.GetName(CustomName.WildwoodF),
|
||||
(Gender.Female, SubRace.Duskwight) => AwaitedService.GetName(CustomName.DuskwightF),
|
||||
(Gender.Female, SubRace.Plainsfolk) => AwaitedService.GetName(CustomName.PlainsfolkF),
|
||||
(Gender.Female, SubRace.Dunesfolk) => AwaitedService.GetName(CustomName.DunesfolkF),
|
||||
(Gender.Female, SubRace.SeekerOfTheSun) => AwaitedService.GetName(CustomName.SeekerOfTheSunF),
|
||||
(Gender.Female, SubRace.KeeperOfTheMoon) => AwaitedService.GetName(CustomName.KeeperOfTheMoonF),
|
||||
(Gender.Female, SubRace.Seawolf) => AwaitedService.GetName(CustomName.SeawolfF),
|
||||
(Gender.Female, SubRace.Hellsguard) => AwaitedService.GetName(CustomName.HellsguardF),
|
||||
(Gender.Female, SubRace.Raen) => AwaitedService.GetName(CustomName.RaenF),
|
||||
(Gender.Female, SubRace.Xaela) => AwaitedService.GetName(CustomName.XaelaF),
|
||||
(Gender.Female, SubRace.Helion) => AwaitedService.GetName(CustomName.HelionM),
|
||||
(Gender.Female, SubRace.Lost) => AwaitedService.GetName(CustomName.LostM),
|
||||
(Gender.Female, SubRace.Rava) => AwaitedService.GetName(CustomName.RavaF),
|
||||
(Gender.Female, SubRace.Veena) => AwaitedService.GetName(CustomName.VeenaF),
|
||||
(Gender.Male, SubRace.Midlander) => Service.GetName(CustomName.MidlanderM),
|
||||
(Gender.Male, SubRace.Highlander) => Service.GetName(CustomName.HighlanderM),
|
||||
(Gender.Male, SubRace.Wildwood) => Service.GetName(CustomName.WildwoodM),
|
||||
(Gender.Male, SubRace.Duskwight) => Service.GetName(CustomName.DuskwightM),
|
||||
(Gender.Male, SubRace.Plainsfolk) => Service.GetName(CustomName.PlainsfolkM),
|
||||
(Gender.Male, SubRace.Dunesfolk) => Service.GetName(CustomName.DunesfolkM),
|
||||
(Gender.Male, SubRace.SeekerOfTheSun) => Service.GetName(CustomName.SeekerOfTheSunM),
|
||||
(Gender.Male, SubRace.KeeperOfTheMoon) => Service.GetName(CustomName.KeeperOfTheMoonM),
|
||||
(Gender.Male, SubRace.Seawolf) => Service.GetName(CustomName.SeawolfM),
|
||||
(Gender.Male, SubRace.Hellsguard) => Service.GetName(CustomName.HellsguardM),
|
||||
(Gender.Male, SubRace.Raen) => Service.GetName(CustomName.RaenM),
|
||||
(Gender.Male, SubRace.Xaela) => Service.GetName(CustomName.XaelaM),
|
||||
(Gender.Male, SubRace.Helion) => Service.GetName(CustomName.HelionM),
|
||||
(Gender.Male, SubRace.Lost) => Service.GetName(CustomName.LostM),
|
||||
(Gender.Male, SubRace.Rava) => Service.GetName(CustomName.RavaM),
|
||||
(Gender.Male, SubRace.Veena) => Service.GetName(CustomName.VeenaM),
|
||||
(Gender.Female, SubRace.Midlander) => Service.GetName(CustomName.MidlanderF),
|
||||
(Gender.Female, SubRace.Highlander) => Service.GetName(CustomName.HighlanderF),
|
||||
(Gender.Female, SubRace.Wildwood) => Service.GetName(CustomName.WildwoodF),
|
||||
(Gender.Female, SubRace.Duskwight) => Service.GetName(CustomName.DuskwightF),
|
||||
(Gender.Female, SubRace.Plainsfolk) => Service.GetName(CustomName.PlainsfolkF),
|
||||
(Gender.Female, SubRace.Dunesfolk) => Service.GetName(CustomName.DunesfolkF),
|
||||
(Gender.Female, SubRace.SeekerOfTheSun) => Service.GetName(CustomName.SeekerOfTheSunF),
|
||||
(Gender.Female, SubRace.KeeperOfTheMoon) => Service.GetName(CustomName.KeeperOfTheMoonF),
|
||||
(Gender.Female, SubRace.Seawolf) => Service.GetName(CustomName.SeawolfF),
|
||||
(Gender.Female, SubRace.Hellsguard) => Service.GetName(CustomName.HellsguardF),
|
||||
(Gender.Female, SubRace.Raen) => Service.GetName(CustomName.RaenF),
|
||||
(Gender.Female, SubRace.Xaela) => Service.GetName(CustomName.XaelaF),
|
||||
(Gender.Female, SubRace.Helion) => Service.GetName(CustomName.HelionM),
|
||||
(Gender.Female, SubRace.Lost) => Service.GetName(CustomName.LostM),
|
||||
(Gender.Female, SubRace.Rava) => Service.GetName(CustomName.RavaF),
|
||||
(Gender.Female, SubRace.Veena) => Service.GetName(CustomName.VeenaF),
|
||||
_ => "Unknown",
|
||||
};
|
||||
}
|
||||
|
|
@ -105,12 +120,12 @@ public sealed class CustomizationService : AsyncServiceWrapper<ICustomizationMan
|
|||
/// <summary> Returns whether a clan is valid. </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public bool IsClanValid(SubRace clan)
|
||||
=> AwaitedService.Clans.Contains(clan);
|
||||
=> Service.Clans.Contains(clan);
|
||||
|
||||
/// <summary> Returns whether a gender is valid for the given race. </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public bool IsGenderValid(Race race, Gender gender)
|
||||
=> race is Race.Hrothgar ? gender == Gender.Male : AwaitedService.Genders.Contains(gender);
|
||||
=> race is Race.Hrothgar ? gender == Gender.Male : Service.Genders.Contains(gender);
|
||||
|
||||
/// <inheritdoc cref="IsCustomizationValid(CustomizationSet,CustomizeValue,CustomizeIndex,CustomizeValue, out CustomizeData?)"/>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
|
|
@ -126,7 +141,7 @@ public sealed class CustomizationService : AsyncServiceWrapper<ICustomizationMan
|
|||
/// <summary> Returns whether a customization value is valid for a given clan, gender and face. </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public bool IsCustomizationValid(SubRace race, Gender gender, CustomizeValue face, CustomizeIndex type, CustomizeValue value)
|
||||
=> IsCustomizationValid(AwaitedService.GetList(race, gender), face, type, value);
|
||||
=> IsCustomizationValid(Service.GetList(race, gender), face, type, value);
|
||||
|
||||
/// <summary>
|
||||
/// Check that the given race and clan are valid.
|
||||
|
|
@ -145,10 +160,10 @@ public sealed class CustomizationService : AsyncServiceWrapper<ICustomizationMan
|
|||
return string.Empty;
|
||||
}
|
||||
|
||||
if (AwaitedService.Races.Contains(race))
|
||||
if (Service.Races.Contains(race))
|
||||
{
|
||||
actualRace = race;
|
||||
actualClan = AwaitedService.Clans.FirstOrDefault(c => c.ToRace() == race, SubRace.Unknown);
|
||||
actualClan = Service.Clans.FirstOrDefault(c => c.ToRace() == race, SubRace.Unknown);
|
||||
// This should not happen.
|
||||
if (actualClan == SubRace.Unknown)
|
||||
{
|
||||
|
|
@ -174,7 +189,7 @@ public sealed class CustomizationService : AsyncServiceWrapper<ICustomizationMan
|
|||
/// </summary>
|
||||
public string ValidateGender(Race race, Gender gender, out Gender actualGender)
|
||||
{
|
||||
if (!AwaitedService.Genders.Contains(gender))
|
||||
if (!Service.Genders.Contains(gender))
|
||||
{
|
||||
actualGender = Gender.Male;
|
||||
return $"The gender {gender.ToName()} is unknown, reset to {Gender.Male.ToName()}.";
|
||||
|
|
@ -251,7 +266,7 @@ public sealed class CustomizationService : AsyncServiceWrapper<ICustomizationMan
|
|||
flags |= CustomizeFlag.Gender;
|
||||
}
|
||||
|
||||
var set = AwaitedService.GetList(customize.Clan, customize.Gender);
|
||||
var set = Service.GetList(customize.Clan, customize.Gender);
|
||||
return FixValues(set, ref customize) | flags;
|
||||
}
|
||||
|
||||
|
|
@ -269,7 +284,7 @@ public sealed class CustomizationService : AsyncServiceWrapper<ICustomizationMan
|
|||
return 0;
|
||||
|
||||
customize.Gender = newGender;
|
||||
var set = AwaitedService.GetList(customize.Clan, customize.Gender);
|
||||
var set = Service.GetList(customize.Clan, customize.Gender);
|
||||
return FixValues(set, ref customize) | CustomizeFlag.Gender;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,55 +1,30 @@
|
|||
using Dalamud.Game.ClientState.Objects;
|
||||
using Dalamud.Interface.DragDrop;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using OtterGui.Services;
|
||||
|
||||
namespace Glamourer.Services;
|
||||
|
||||
public class DalamudServices
|
||||
{
|
||||
public DalamudServices(DalamudPluginInterface pi)
|
||||
public static void AddServices(ServiceManager services, DalamudPluginInterface pi)
|
||||
{
|
||||
pi.Inject(this);
|
||||
services.AddExistingService(pi);
|
||||
services.AddExistingService(pi.UiBuilder);
|
||||
services.AddDalamudService<ICommandManager>(pi);
|
||||
services.AddDalamudService<IDataManager>(pi);
|
||||
services.AddDalamudService<IClientState>(pi);
|
||||
services.AddDalamudService<ICondition>(pi);
|
||||
services.AddDalamudService<IGameGui>(pi);
|
||||
services.AddDalamudService<IChatGui>(pi);
|
||||
services.AddDalamudService<IFramework>(pi);
|
||||
services.AddDalamudService<ITargetManager>(pi);
|
||||
services.AddDalamudService<IObjectTable>(pi);
|
||||
services.AddDalamudService<IKeyState>(pi);
|
||||
services.AddDalamudService<IDragDropManager>(pi);
|
||||
services.AddDalamudService<ITextureProvider>(pi);
|
||||
services.AddDalamudService<IPluginLog>(pi);
|
||||
services.AddDalamudService<IGameInteropProvider>(pi);
|
||||
}
|
||||
|
||||
public void AddServices(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton(PluginInterface);
|
||||
services.AddSingleton(Commands);
|
||||
services.AddSingleton(GameData);
|
||||
services.AddSingleton(ClientState);
|
||||
services.AddSingleton(Condition);
|
||||
services.AddSingleton(GameGui);
|
||||
services.AddSingleton(Chat);
|
||||
services.AddSingleton(Framework);
|
||||
services.AddSingleton(Targets);
|
||||
services.AddSingleton(Objects);
|
||||
services.AddSingleton(KeyState);
|
||||
services.AddSingleton(this);
|
||||
services.AddSingleton(PluginInterface.UiBuilder);
|
||||
services.AddSingleton(DragDropManager);
|
||||
services.AddSingleton(TextureProvider);
|
||||
services.AddSingleton(Log);
|
||||
services.AddSingleton(Interop);
|
||||
}
|
||||
|
||||
// @formatter:off
|
||||
[PluginService][RequiredVersion("1.0")] public DalamudPluginInterface PluginInterface { get; private set; } = null!;
|
||||
[PluginService][RequiredVersion("1.0")] public ICommandManager Commands { get; private set; } = null!;
|
||||
[PluginService][RequiredVersion("1.0")] public IDataManager GameData { get; private set; } = null!;
|
||||
[PluginService][RequiredVersion("1.0")] public IClientState ClientState { get; private set; } = null!;
|
||||
[PluginService][RequiredVersion("1.0")] public ICondition Condition { get; private set; } = null!;
|
||||
[PluginService][RequiredVersion("1.0")] public IGameGui GameGui { get; private set; } = null!;
|
||||
[PluginService][RequiredVersion("1.0")] public IChatGui Chat { get; private set; } = null!;
|
||||
[PluginService][RequiredVersion("1.0")] public IFramework Framework { get; private set; } = null!;
|
||||
[PluginService][RequiredVersion("1.0")] public ITargetManager Targets { get; private set; } = null!;
|
||||
[PluginService][RequiredVersion("1.0")] public IObjectTable Objects { get; private set; } = null!;
|
||||
[PluginService][RequiredVersion("1.0")] public IKeyState KeyState { get; private set; } = null!;
|
||||
[PluginService][RequiredVersion("1.0")] public IDragDropManager DragDropManager { get; private set; } = null!;
|
||||
[PluginService][RequiredVersion("1.0")] public ITextureProvider TextureProvider { get; private set; } = null!;
|
||||
[PluginService][RequiredVersion("1.0")] public IPluginLog Log { get; private set; } = null!;
|
||||
[PluginService][RequiredVersion("1.0")] public IGameInteropProvider Interop { get; private set; } = null!;
|
||||
// @formatter:on
|
||||
}
|
||||
|
|
|
|||
6
Glamourer/Services/IGamePathParser.cs
Normal file
6
Glamourer/Services/IGamePathParser.cs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
namespace Glamourer.Services
|
||||
{
|
||||
internal interface IGamePathParser
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,17 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Lumina.Excel;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Race = Penumbra.GameData.Enums.Race;
|
||||
|
||||
namespace Glamourer.Services;
|
||||
|
||||
public class ItemManager : IDisposable
|
||||
public class ItemManager
|
||||
{
|
||||
public const string Nothing = "Nothing";
|
||||
public const string SmallClothesNpc = "Smallclothes (NPC)";
|
||||
|
|
@ -19,32 +19,26 @@ public class ItemManager : IDisposable
|
|||
|
||||
private readonly Configuration _config;
|
||||
|
||||
public readonly IdentifierService IdentifierService;
|
||||
public readonly ObjectIdentification ObjectIdentification;
|
||||
public readonly ExcelSheet<Lumina.Excel.GeneratedSheets.Item> ItemSheet;
|
||||
public readonly StainData Stains;
|
||||
public readonly ItemService ItemService;
|
||||
public readonly DictStains Stains;
|
||||
public readonly ItemData ItemData;
|
||||
public readonly RestrictedGear RestrictedGear;
|
||||
|
||||
public readonly EquipItem DefaultSword;
|
||||
|
||||
public ItemManager(Configuration config, DalamudPluginInterface pi, IDataManager gameData, IdentifierService identifierService,
|
||||
ItemService itemService, IPluginLog log)
|
||||
public ItemManager(Configuration config, IDataManager gameData, ObjectIdentification objectIdentification,
|
||||
ItemData itemData, DictStains stains, RestrictedGear restrictedGear)
|
||||
{
|
||||
_config = config;
|
||||
ItemSheet = gameData.GetExcelSheet<Lumina.Excel.GeneratedSheets.Item>()!;
|
||||
IdentifierService = identifierService;
|
||||
Stains = new StainData(pi, gameData, gameData.Language, log);
|
||||
ItemService = itemService;
|
||||
RestrictedGear = new RestrictedGear(pi, gameData.Language, gameData, log);
|
||||
ObjectIdentification = objectIdentification;
|
||||
ItemData = itemData;
|
||||
Stains = stains;
|
||||
RestrictedGear = restrictedGear;
|
||||
DefaultSword = EquipItem.FromMainhand(ItemSheet.GetRow(1601)!); // Weathered Shortsword
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Stains.Dispose();
|
||||
RestrictedGear.Dispose();
|
||||
}
|
||||
|
||||
public (bool, CharacterArmor) ResolveRestrictedGear(CharacterArmor armor, EquipSlot slot, Race race, Gender gender)
|
||||
=> _config.UseRestrictedGearProtection ? RestrictedGear.ResolveRestricted(armor, slot, race, gender) : (false, armor);
|
||||
|
||||
|
|
@ -74,11 +68,12 @@ public class ItemManager : IDisposable
|
|||
if (itemId == SmallclothesId(slot))
|
||||
return SmallClothesItem(slot);
|
||||
|
||||
if (!itemId.IsItem || !ItemService.AwaitedService.TryGetValue(itemId.Item, slot, out var item))
|
||||
if (!itemId.IsItem || !ItemData.TryGetValue(itemId.Item, slot, out var item))
|
||||
return EquipItem.FromId(itemId);
|
||||
|
||||
if (item.Type.ToSlot() != slot)
|
||||
return new EquipItem(string.Intern($"Invalid #{itemId}"), itemId, item.IconId, item.ModelId, item.WeaponType, item.Variant, 0, 0, 0,
|
||||
return new EquipItem(string.Intern($"Invalid #{itemId}"), itemId, item.IconId, item.PrimaryId, item.SecondaryId, item.Variant, 0, 0,
|
||||
0,
|
||||
0);
|
||||
|
||||
return item;
|
||||
|
|
@ -89,12 +84,13 @@ public class ItemManager : IDisposable
|
|||
if (itemId == NothingId(type))
|
||||
return NothingItem(type);
|
||||
|
||||
if (!ItemService.AwaitedService.TryGetValue(itemId, type is FullEquipType.Shield ? EquipSlot.MainHand : EquipSlot.OffHand,
|
||||
if (!ItemData.TryGetValue(itemId, type is FullEquipType.Shield ? EquipSlot.MainHand : EquipSlot.OffHand,
|
||||
out var item))
|
||||
return EquipItem.FromId(itemId);
|
||||
|
||||
if (item.Type != type)
|
||||
return new EquipItem(string.Intern($"Invalid #{itemId}"), itemId, item.IconId, item.ModelId, item.WeaponType, item.Variant, 0, 0, 0,
|
||||
return new EquipItem(string.Intern($"Invalid #{itemId}"), itemId, item.IconId, item.PrimaryId, item.SecondaryId, item.Variant, 0, 0,
|
||||
0,
|
||||
0);
|
||||
|
||||
return item;
|
||||
|
|
@ -103,7 +99,7 @@ public class ItemManager : IDisposable
|
|||
public EquipItem Resolve(FullEquipType type, CustomItemId id)
|
||||
=> id.IsItem ? Resolve(type, id.Item) : EquipItem.FromId(id);
|
||||
|
||||
public EquipItem Identify(EquipSlot slot, SetId id, Variant variant)
|
||||
public EquipItem Identify(EquipSlot slot, PrimaryId id, Variant variant)
|
||||
{
|
||||
slot = slot.ToSlot();
|
||||
if (slot.ToIndex() == uint.MaxValue)
|
||||
|
|
@ -114,7 +110,7 @@ public class ItemManager : IDisposable
|
|||
case 0: return NothingItem(slot);
|
||||
case SmallClothesNpcModel: return SmallClothesItem(slot);
|
||||
default:
|
||||
var item = IdentifierService.AwaitedService.Identify(id, variant, slot).FirstOrDefault();
|
||||
var item = ObjectIdentification.Identify(id, 0, variant, slot).FirstOrDefault();
|
||||
return item.Valid
|
||||
? item
|
||||
: EquipItem.FromIds(0, 0, id, 0, variant, slot.ToEquipType());
|
||||
|
|
@ -131,7 +127,8 @@ public class ItemManager : IDisposable
|
|||
return NothingItem(offhandType);
|
||||
}
|
||||
|
||||
public EquipItem Identify(EquipSlot slot, SetId id, WeaponType type, Variant variant, FullEquipType mainhandType = FullEquipType.Unknown)
|
||||
public EquipItem Identify(EquipSlot slot, PrimaryId id, SecondaryId type, Variant variant,
|
||||
FullEquipType mainhandType = FullEquipType.Unknown)
|
||||
{
|
||||
if (slot is EquipSlot.OffHand)
|
||||
{
|
||||
|
|
@ -143,7 +140,7 @@ public class ItemManager : IDisposable
|
|||
if (slot is not EquipSlot.MainHand and not EquipSlot.OffHand)
|
||||
return new EquipItem($"Invalid ({id.Id}-{type.Id}-{variant})", 0, 0, id, type, variant, 0, 0, 0, 0);
|
||||
|
||||
var item = IdentifierService.AwaitedService.Identify(id, type, variant, slot).FirstOrDefault(i => i.Type.ToSlot() == slot);
|
||||
var item = ObjectIdentification.Identify(id, type, variant, slot).FirstOrDefault(i => i.Type.ToSlot() == slot);
|
||||
return item.Valid
|
||||
? item
|
||||
: EquipItem.FromIds(0, 0, id, type, variant, slot.ToEquipType());
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin;
|
||||
using Glamourer.Api;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Designs;
|
||||
|
|
@ -18,22 +15,26 @@ using Glamourer.Gui.Tabs.UnlocksTab;
|
|||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using Glamourer.State;
|
||||
using Glamourer.Structs;
|
||||
using Glamourer.Unlocks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Services;
|
||||
|
||||
public static class ServiceManager
|
||||
public static class ServiceManagerA
|
||||
{
|
||||
public static ServiceProvider CreateProvider(DalamudPluginInterface pi, Logger log)
|
||||
public static ServiceManager CreateProvider(DalamudPluginInterface pi, Logger log)
|
||||
{
|
||||
EventWrapper.ChangeLogger(log);
|
||||
var services = new ServiceCollection()
|
||||
.AddSingleton(log)
|
||||
.AddDalamud(pi)
|
||||
var services = new ServiceManager(log)
|
||||
.AddExistingService(log)
|
||||
.AddMeta()
|
||||
.AddInterop()
|
||||
.AddEvents()
|
||||
|
|
@ -41,19 +42,16 @@ public static class ServiceManager
|
|||
.AddDesigns()
|
||||
.AddState()
|
||||
.AddUi()
|
||||
.AddApi()
|
||||
.AddDebug();
|
||||
|
||||
return services.BuildServiceProvider(new ServiceProviderOptions { ValidateOnBuild = true });
|
||||
}
|
||||
|
||||
private static IServiceCollection AddDalamud(this IServiceCollection services, DalamudPluginInterface pi)
|
||||
{
|
||||
new DalamudServices(pi).AddServices(services);
|
||||
.AddApi();
|
||||
DalamudServices.AddServices(services, pi);
|
||||
services.AddIServices(typeof(EquipItem).Assembly);
|
||||
services.AddIServices(typeof(Glamourer).Assembly);
|
||||
services.AddIServices(typeof(EquipFlag).Assembly);
|
||||
services.CreateProvider();
|
||||
return services;
|
||||
}
|
||||
|
||||
private static IServiceCollection AddMeta(this IServiceCollection services)
|
||||
private static ServiceManager AddMeta(this ServiceManager services)
|
||||
=> services.AddSingleton<MessageService>()
|
||||
.AddSingleton<FilenameService>()
|
||||
.AddSingleton<BackupService>()
|
||||
|
|
@ -66,7 +64,7 @@ public static class ServiceManager
|
|||
.AddSingleton<TextureService>()
|
||||
.AddSingleton<FavoriteManager>();
|
||||
|
||||
private static IServiceCollection AddEvents(this IServiceCollection services)
|
||||
private static ServiceManager AddEvents(this ServiceManager services)
|
||||
=> services.AddSingleton<VisorStateChanged>()
|
||||
.AddSingleton<SlotUpdating>()
|
||||
.AddSingleton<DesignChanged>()
|
||||
|
|
@ -82,21 +80,23 @@ public static class ServiceManager
|
|||
.AddSingleton<GPoseService>()
|
||||
.AddSingleton<PenumbraReloaded>();
|
||||
|
||||
private static IServiceCollection AddData(this IServiceCollection services)
|
||||
=> services.AddSingleton<IdentifierService>()
|
||||
.AddSingleton<ItemService>()
|
||||
.AddSingleton<ActorService>()
|
||||
private static ServiceManager AddData(this ServiceManager services)
|
||||
=> services.AddSingleton<ObjectIdentification>()
|
||||
.AddSingleton<ItemData>()
|
||||
.AddSingleton<ActorManager>()
|
||||
.AddSingleton<CustomizationService>()
|
||||
.AddSingleton<ItemManager>()
|
||||
.AddSingleton<GamePathParser>()
|
||||
.AddSingleton<HumanModelList>();
|
||||
|
||||
private static IServiceCollection AddInterop(this IServiceCollection services)
|
||||
private static ServiceManager AddInterop(this ServiceManager services)
|
||||
=> services.AddSingleton<VisorService>()
|
||||
.AddSingleton<ChangeCustomizeService>()
|
||||
.AddSingleton<MetaService>()
|
||||
.AddSingleton<UpdateSlotService>()
|
||||
.AddSingleton<WeaponService>()
|
||||
.AddSingleton<PenumbraService>()
|
||||
.AddSingleton(p => new CutsceneResolver(p.GetRequiredService<PenumbraService>().CutsceneParent))
|
||||
.AddSingleton<ObjectManager>()
|
||||
.AddSingleton<PenumbraAutoRedraw>()
|
||||
.AddSingleton<JobService>()
|
||||
|
|
@ -108,7 +108,7 @@ public static class ServiceManager
|
|||
.AddSingleton<ContextMenuService>()
|
||||
.AddSingleton<ScalingService>();
|
||||
|
||||
private static IServiceCollection AddDesigns(this IServiceCollection services)
|
||||
private static ServiceManager AddDesigns(this ServiceManager services)
|
||||
=> services.AddSingleton<DesignManager>()
|
||||
.AddSingleton<DesignFileSystem>()
|
||||
.AddSingleton<AutoDesignManager>()
|
||||
|
|
@ -117,14 +117,14 @@ public static class ServiceManager
|
|||
.AddSingleton<DesignConverter>()
|
||||
.AddSingleton<DesignColors>();
|
||||
|
||||
private static IServiceCollection AddState(this IServiceCollection services)
|
||||
private static ServiceManager AddState(this ServiceManager services)
|
||||
=> services.AddSingleton<StateManager>()
|
||||
.AddSingleton<StateApplier>()
|
||||
.AddSingleton<StateEditor>()
|
||||
.AddSingleton<StateListener>()
|
||||
.AddSingleton<FunModule>();
|
||||
|
||||
private static IServiceCollection AddUi(this IServiceCollection services)
|
||||
private static ServiceManager AddUi(this ServiceManager services)
|
||||
=> services.AddSingleton<DebugTab>()
|
||||
.AddSingleton<MessagesTab>()
|
||||
.AddSingleton<SettingsTab>()
|
||||
|
|
@ -157,16 +157,7 @@ public static class ServiceManager
|
|||
.AddSingleton<DesignColorUi>()
|
||||
.AddSingleton<NpcCombo>();
|
||||
|
||||
private static IServiceCollection AddDebug(this IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton(p => new DebugTab(p));
|
||||
var iType = typeof(IDebugTabTree);
|
||||
foreach (var type in Assembly.GetAssembly(iType)!.GetTypes().Where(t => !t.IsInterface && iType.IsAssignableFrom(t)))
|
||||
services.AddSingleton(type);
|
||||
return services;
|
||||
}
|
||||
|
||||
private static IServiceCollection AddApi(this IServiceCollection services)
|
||||
private static ServiceManager AddApi(this ServiceManager services)
|
||||
=> services.AddSingleton<CommandService>()
|
||||
.AddSingleton<GlamourerIpc>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,93 +0,0 @@
|
|||
using Dalamud.Plugin;
|
||||
using Penumbra.GameData.Actors;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData;
|
||||
|
||||
namespace Glamourer.Services;
|
||||
|
||||
public abstract class AsyncServiceWrapper<T> : IDisposable
|
||||
{
|
||||
public string Name { get; }
|
||||
public T? Service { get; private set; }
|
||||
|
||||
public T AwaitedService
|
||||
{
|
||||
get
|
||||
{
|
||||
_task?.Wait();
|
||||
return Service!;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Valid
|
||||
=> Service != null && !_isDisposed;
|
||||
|
||||
public event Action? FinishedCreation;
|
||||
private Task? _task;
|
||||
|
||||
private bool _isDisposed;
|
||||
|
||||
protected AsyncServiceWrapper(string name, Func<T> factory)
|
||||
{
|
||||
Name = name;
|
||||
_task = Task.Run(() =>
|
||||
{
|
||||
var service = factory();
|
||||
if (_isDisposed)
|
||||
{
|
||||
if (service is IDisposable d)
|
||||
d.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
Service = service;
|
||||
Glamourer.Log.Verbose($"[{Name}] Created.");
|
||||
_task = null;
|
||||
}
|
||||
});
|
||||
_task.ContinueWith((t, x) =>
|
||||
{
|
||||
if (!_isDisposed)
|
||||
FinishedCreation?.Invoke();
|
||||
}, null);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_isDisposed)
|
||||
return;
|
||||
|
||||
_isDisposed = true;
|
||||
_task = null;
|
||||
if (Service is IDisposable d)
|
||||
d.Dispose();
|
||||
Glamourer.Log.Verbose($"[{Name}] Disposed.");
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class IdentifierService : AsyncServiceWrapper<IObjectIdentifier>
|
||||
{
|
||||
public IdentifierService(DalamudPluginInterface pi, IDataManager data, ItemService itemService, IPluginLog log)
|
||||
: base(nameof(IdentifierService), () => Penumbra.GameData.GameData.GetIdentifier(pi, data, itemService.AwaitedService, log))
|
||||
{ }
|
||||
}
|
||||
|
||||
public sealed class ItemService : AsyncServiceWrapper<ItemData>
|
||||
{
|
||||
public ItemService(DalamudPluginInterface pi, IDataManager gameData, IPluginLog log)
|
||||
: base(nameof(ItemService), () => new ItemData(pi, gameData, gameData.Language, log))
|
||||
{ }
|
||||
}
|
||||
|
||||
public sealed class ActorService : AsyncServiceWrapper<ActorManager>
|
||||
{
|
||||
public ActorService(DalamudPluginInterface pi, IObjectTable objects, IClientState clientState, IFramework framework, IGameInteropProvider interop, IDataManager gameData,
|
||||
IGameGui gui, PenumbraService penumbra, IPluginLog log)
|
||||
: base(nameof(ActorService),
|
||||
() => new ActorManager(pi, objects, clientState, framework, interop, gameData, gui, idx => (short)penumbra.CutsceneParent(idx), log))
|
||||
{ }
|
||||
}
|
||||
|
|
@ -164,20 +164,21 @@ public unsafe class FunModule : IDisposable
|
|||
if (!_codes.EnabledEmperor)
|
||||
return;
|
||||
|
||||
void SetItem(EquipSlot slot2, ref CharacterArmor armor)
|
||||
{
|
||||
var list = _items.ItemService.AwaitedService[slot2.ToEquipType()];
|
||||
var rng = _rng.Next(0, list.Count - 1);
|
||||
var item = list[rng];
|
||||
armor.Set = item.ModelId;
|
||||
armor.Variant = item.Variant;
|
||||
}
|
||||
|
||||
if (armors.Length == 1)
|
||||
SetItem(slot, ref armors[0]);
|
||||
else
|
||||
for (var i = 0u; i < armors.Length; ++i)
|
||||
SetItem(i.ToEquipSlot(), ref armors[(int)i]);
|
||||
return;
|
||||
|
||||
void SetItem(EquipSlot slot2, ref CharacterArmor armor)
|
||||
{
|
||||
var list = _items.ItemData.ByType[slot2.ToEquipType()];
|
||||
var rng = _rng.Next(0, list.Count - 1);
|
||||
var item = list[rng];
|
||||
armor.Set = item.PrimaryId;
|
||||
armor.Variant = item.Variant;
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyOops(ref Customize customize)
|
||||
|
|
@ -197,7 +198,7 @@ public unsafe class FunModule : IDisposable
|
|||
if (!_codes.EnabledIndividual)
|
||||
return;
|
||||
|
||||
var set = _customizations.AwaitedService.GetList(customize.Clan, customize.Gender);
|
||||
var set = _customizations.Service.GetList(customize.Clan, customize.Gender);
|
||||
foreach (var index in Enum.GetValues<CustomizeIndex>())
|
||||
{
|
||||
if (index is CustomizeIndex.Face || !set.IsAvailable(index))
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ public class StateApplier(UpdateSlotService _updateSlot, VisorService _visor, We
|
|||
/// <summary> Apply a weapon to the offhand. </summary>
|
||||
public void ChangeOffhand(ActorData data, EquipItem weapon, StainId stain)
|
||||
{
|
||||
stain = weapon.ModelId.Id == 0 ? 0 : stain;
|
||||
stain = weapon.PrimaryId.Id == 0 ? 0 : stain;
|
||||
foreach (var actor in data.Objects.Where(a => a.Model.IsHuman))
|
||||
_weapon.LoadWeapon(actor, EquipSlot.OffHand, weapon.Weapon().With(stain));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ using Glamourer.Customization;
|
|||
using Glamourer.Events;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ public class StateEditor
|
|||
|
||||
state[CustomizeIndex.Clan] = source;
|
||||
state[CustomizeIndex.Gender] = source;
|
||||
var set = _customizations.AwaitedService.GetList(state.ModelData.Customize.Clan, state.ModelData.Customize.Gender);
|
||||
var set = _customizations.Service.GetList(state.ModelData.Customize.Clan, state.ModelData.Customize.Gender);
|
||||
foreach (var index in Enum.GetValues<CustomizeIndex>().Where(set.IsAvailable))
|
||||
state[index] = source;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@ using Glamourer.Interop.Structs;
|
|||
using Glamourer.Services;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using System;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Structs;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
|
||||
namespace Glamourer.State;
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ namespace Glamourer.State;
|
|||
public class StateListener : IDisposable
|
||||
{
|
||||
private readonly Configuration _config;
|
||||
private readonly ActorService _actors;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly StateManager _manager;
|
||||
private readonly StateApplier _applier;
|
||||
|
|
@ -50,7 +50,7 @@ public class StateListener : IDisposable
|
|||
private ActorState? _creatingState;
|
||||
private CharacterWeapon _lastFistOffhand = CharacterWeapon.Empty;
|
||||
|
||||
public StateListener(StateManager manager, ItemManager items, PenumbraService penumbra, ActorService actors, Configuration config,
|
||||
public StateListener(StateManager manager, ItemManager items, PenumbraService penumbra, ActorManager actors, Configuration config,
|
||||
SlotUpdating slotUpdating, WeaponLoading weaponLoading, VisorStateChanged visorState, WeaponVisibilityChanged weaponVisibility,
|
||||
HeadGearVisibilityChanged headGearVisibility, AutoDesignApplier autoDesignApplier, FunModule funModule, HumanModelList humans,
|
||||
StateApplier applier, MovedEquipment movedEquipment, ObjectManager objects, GPoseService gPose,
|
||||
|
|
@ -111,7 +111,7 @@ public class StateListener : IDisposable
|
|||
if (_condition[ConditionFlag.CreatingCharacter] && actor.Index >= ObjectIndex.CutsceneStart)
|
||||
return;
|
||||
|
||||
_creatingIdentifier = actor.GetIdentifier(_actors.AwaitedService);
|
||||
_creatingIdentifier = actor.GetIdentifier(_actors);
|
||||
|
||||
ref var modelId = ref *(uint*)modelPtr;
|
||||
ref var customize = ref *(Customize*)customizePtr;
|
||||
|
|
@ -149,7 +149,7 @@ public class StateListener : IDisposable
|
|||
if (_condition[ConditionFlag.CreatingCharacter] && actor.Index >= ObjectIndex.CutsceneStart)
|
||||
return;
|
||||
|
||||
if (!actor.Identifier(_actors.AwaitedService, out var identifier)
|
||||
if (!actor.Identifier(_actors, out var identifier)
|
||||
|| !_manager.TryGetValue(identifier, out var state))
|
||||
return;
|
||||
|
||||
|
|
@ -169,7 +169,7 @@ public class StateListener : IDisposable
|
|||
return;
|
||||
}
|
||||
|
||||
var set = _customizations.AwaitedService.GetList(model.Clan, model.Gender);
|
||||
var set = _customizations.Service.GetList(model.Clan, model.Gender);
|
||||
foreach (var index in CustomizationExtensions.AllBasic)
|
||||
{
|
||||
if (state[index] is not StateChanged.Source.Fixed)
|
||||
|
|
@ -211,7 +211,7 @@ public class StateListener : IDisposable
|
|||
// then we do not want to use our restricted gear protection
|
||||
// since we assume the player has that gear modded to availability.
|
||||
var locked = false;
|
||||
if (actor.Identifier(_actors.AwaitedService, out var identifier)
|
||||
if (actor.Identifier(_actors, out var identifier)
|
||||
&& _manager.TryGetValue(identifier, out var state))
|
||||
{
|
||||
HandleEquipSlot(actor, state, slot, ref armor.Value);
|
||||
|
|
@ -238,7 +238,7 @@ public class StateListener : IDisposable
|
|||
var currentItem = state.BaseData.Item(slot);
|
||||
var model = state.ModelData.Weapon(slot);
|
||||
var current = currentItem.Weapon(state.BaseData.Stain(slot));
|
||||
if (model.Value == current.Value || !_items.ItemService.AwaitedService.TryGetValue(item, EquipSlot.MainHand, out var changedItem))
|
||||
if (model.Value == current.Value || !_items.ItemData.TryGetValue(item, EquipSlot.MainHand, out var changedItem))
|
||||
continue;
|
||||
|
||||
var changed = changedItem.Weapon(stain);
|
||||
|
|
@ -272,10 +272,10 @@ public class StateListener : IDisposable
|
|||
return;
|
||||
|
||||
// Fist weapon gauntlet hack.
|
||||
if (slot is EquipSlot.OffHand && weapon.Value.Variant == 0 && weapon.Value.Set.Id != 0 && _lastFistOffhand.Set.Id != 0)
|
||||
if (slot is EquipSlot.OffHand && weapon.Value.Variant == 0 && weapon.Value.Y.Id != 0 && _lastFistOffhand.Y.Id != 0)
|
||||
weapon.Value = _lastFistOffhand;
|
||||
|
||||
if (!actor.Identifier(_actors.AwaitedService, out var identifier)
|
||||
if (!actor.Identifier(_actors, out var identifier)
|
||||
|| !_manager.TryGetValue(identifier, out var state))
|
||||
return;
|
||||
|
||||
|
|
@ -308,13 +308,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.Id != 0)
|
||||
else if (actorWeapon.X.Id != 0)
|
||||
actorWeapon = actorWeapon.With(newWeapon.Stain);
|
||||
}
|
||||
|
||||
// Fist Weapon Offhand hack.
|
||||
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,
|
||||
if (slot is EquipSlot.MainHand && weapon.Value.X.Id is > 1600 and < 1651)
|
||||
_lastFistOffhand = new CharacterWeapon((PrimaryId)(weapon.Value.X.Id + 50), weapon.Value.Y, weapon.Value.Variant,
|
||||
weapon.Value.Stain);
|
||||
|
||||
_funModule.ApplyFun(actor, ref weapon.Value, slot);
|
||||
|
|
@ -329,7 +329,7 @@ public class StateListener : IDisposable
|
|||
return false;
|
||||
|
||||
var offhand = actor.GetOffhand();
|
||||
return offhand.Variant == 0 && offhand.Set.Id != 0 && armor.Set.Id == offhand.Set.Id;
|
||||
return offhand.Variant == 0 && offhand.Y.Id != 0 && armor.Set.Id == offhand.Y.Id;
|
||||
}
|
||||
|
||||
var actorArmor = actor.GetArmor(slot);
|
||||
|
|
@ -413,7 +413,7 @@ public class StateListener : IDisposable
|
|||
if (_condition[ConditionFlag.CreatingCharacter] && actor.Index >= ObjectIndex.CutsceneStart)
|
||||
return;
|
||||
|
||||
if (!actor.Identifier(_actors.AwaitedService, out var identifier)
|
||||
if (!actor.Identifier(_actors, out var identifier)
|
||||
|| !_manager.TryGetValue(identifier, out var state))
|
||||
return;
|
||||
|
||||
|
|
@ -439,7 +439,7 @@ public class StateListener : IDisposable
|
|||
if (_condition[ConditionFlag.CreatingCharacter] && actor.Index >= ObjectIndex.CutsceneStart)
|
||||
return;
|
||||
|
||||
if (!actor.Identifier(_actors.AwaitedService, out var identifier)
|
||||
if (!actor.Identifier(_actors, out var identifier)
|
||||
|| !_manager.TryGetValue(identifier, out var state))
|
||||
return;
|
||||
|
||||
|
|
@ -474,7 +474,7 @@ public class StateListener : IDisposable
|
|||
var change = UpdateState.NoChange;
|
||||
|
||||
// Fist weapon bug hack
|
||||
if (slot is EquipSlot.OffHand && weapon.Value == 0 && actor.GetMainhand().Set.Id is > 1600 and < 1651)
|
||||
if (slot is EquipSlot.OffHand && weapon.Value == 0 && actor.GetMainhand().X.Id is > 1600 and < 1651)
|
||||
return UpdateState.NoChange;
|
||||
|
||||
if (baseData.Stain != weapon.Stain)
|
||||
|
|
@ -483,9 +483,9 @@ public class StateListener : IDisposable
|
|||
change = UpdateState.Change;
|
||||
}
|
||||
|
||||
if (baseData.Set.Id != weapon.Set.Id || baseData.Type.Id != weapon.Type.Id || baseData.Variant != weapon.Variant)
|
||||
if (baseData.X.Id != weapon.X.Id || baseData.Y.Id != weapon.Y.Id || baseData.Variant != weapon.Variant)
|
||||
{
|
||||
var item = _items.Identify(slot, weapon.Set, weapon.Type, weapon.Variant,
|
||||
var item = _items.Identify(slot, weapon.X, weapon.Y, weapon.Variant,
|
||||
slot is EquipSlot.OffHand ? state.BaseData.Item(EquipSlot.MainHand).Type : FullEquipType.Unknown);
|
||||
state.BaseData.SetItem(slot, item);
|
||||
change = UpdateState.Change;
|
||||
|
|
@ -555,7 +555,7 @@ public class StateListener : IDisposable
|
|||
if (_condition[ConditionFlag.CreatingCharacter] && actor.Index >= ObjectIndex.CutsceneStart)
|
||||
return;
|
||||
|
||||
if (!actor.Identifier(_actors.AwaitedService, out var identifier))
|
||||
if (!actor.Identifier(_actors, out var identifier))
|
||||
return;
|
||||
|
||||
if (!_manager.TryGetValue(identifier, out var state))
|
||||
|
|
@ -588,7 +588,7 @@ public class StateListener : IDisposable
|
|||
// We do not need to handle fixed designs,
|
||||
// if there is no model that caused a fixed design to exist yet,
|
||||
// we also do not care about the invisible model.
|
||||
if (!actor.Identifier(_actors.AwaitedService, out var identifier))
|
||||
if (!actor.Identifier(_actors, out var identifier))
|
||||
return;
|
||||
|
||||
if (!_manager.TryGetValue(identifier, out var state))
|
||||
|
|
@ -621,7 +621,7 @@ public class StateListener : IDisposable
|
|||
// We do not need to handle fixed designs,
|
||||
// if there is no model that caused a fixed design to exist yet,
|
||||
// we also do not care about the invisible model.
|
||||
if (!actor.Identifier(_actors.AwaitedService, out var identifier))
|
||||
if (!actor.Identifier(_actors, out var identifier))
|
||||
return;
|
||||
|
||||
if (!_manager.TryGetValue(identifier, out var state))
|
||||
|
|
|
|||
|
|
@ -12,17 +12,17 @@ using Glamourer.Interop.Structs;
|
|||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.State;
|
||||
|
||||
public class StateManager(ActorService _actors, ItemManager _items, StateChanged _event, StateApplier _applier, StateEditor _editor,
|
||||
public class StateManager(ActorManager _actors, ItemManager _items, StateChanged _event, StateApplier _applier, StateEditor _editor,
|
||||
HumanModelList _humans, ICondition _condition, IClientState _clientState)
|
||||
: IReadOnlyDictionary<ActorIdentifier, ActorState>
|
||||
{
|
||||
private readonly Dictionary<ActorIdentifier, ActorState> _states = new();
|
||||
private readonly Dictionary<ActorIdentifier, ActorState> _states = [];
|
||||
|
||||
public IEnumerator<KeyValuePair<ActorIdentifier, ActorState>> GetEnumerator()
|
||||
=> _states.GetEnumerator();
|
||||
|
|
@ -50,7 +50,7 @@ public class StateManager(ActorService _actors, ItemManager _items, StateChanged
|
|||
|
||||
/// <inheritdoc cref="GetOrCreate(ActorIdentifier, Actor, out ActorState?)"/>
|
||||
public bool GetOrCreate(Actor actor, [NotNullWhen(true)] out ActorState? state)
|
||||
=> GetOrCreate(actor.GetIdentifier(_actors.AwaitedService), actor, out state);
|
||||
=> GetOrCreate(actor.GetIdentifier(_actors), actor, out state);
|
||||
|
||||
/// <summary> Try to obtain or create a new state for an existing actor. Returns false if no state could be created. </summary>
|
||||
public unsafe bool GetOrCreate(ActorIdentifier identifier, Actor actor, [NotNullWhen(true)] out ActorState? state)
|
||||
|
|
@ -170,8 +170,8 @@ public class StateManager(ActorService _actors, ItemManager _items, StateChanged
|
|||
}
|
||||
|
||||
// Set the weapons regardless of source.
|
||||
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);
|
||||
var mainItem = _items.Identify(EquipSlot.MainHand, main.Skeleton, main.Weapon, main.Variant);
|
||||
var offItem = _items.Identify(EquipSlot.OffHand, off.Skeleton, off.Weapon, off.Variant, mainItem.Type);
|
||||
ret.SetItem(EquipSlot.MainHand, mainItem);
|
||||
ret.SetStain(EquipSlot.MainHand, main.Stain);
|
||||
ret.SetItem(EquipSlot.OffHand, offItem);
|
||||
|
|
@ -190,13 +190,13 @@ public class StateManager(ActorService _actors, ItemManager _items, StateChanged
|
|||
/// <summary> This is hardcoded in the game. </summary>
|
||||
private void FistWeaponHack(ref DesignData ret, ref CharacterWeapon mainhand, ref CharacterWeapon offhand)
|
||||
{
|
||||
if (mainhand.Set.Id is < 1601 or >= 1651)
|
||||
if (mainhand.Skeleton.Id is < 1601 or >= 1651)
|
||||
return;
|
||||
|
||||
var gauntlets = _items.Identify(EquipSlot.Hands, offhand.Set, (Variant)offhand.Type.Id);
|
||||
offhand.Set = (SetId)(mainhand.Set.Id + 50);
|
||||
var gauntlets = _items.Identify(EquipSlot.Hands, offhand.Skeleton, (Variant)offhand.Weapon.Id);
|
||||
offhand.Skeleton = (PrimaryId)(mainhand.Skeleton.Id + 50);
|
||||
offhand.Variant = mainhand.Variant;
|
||||
offhand.Type = mainhand.Type;
|
||||
offhand.Weapon = mainhand.Weapon;
|
||||
ret.SetItem(EquipSlot.Hands, gauntlets);
|
||||
ret.SetStain(EquipSlot.Hands, mainhand.Stain);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -178,11 +178,11 @@ public class CustomizeUnlockManager : IDisposable, ISavable
|
|||
{
|
||||
var ret = new Dictionary<CustomizeData, (uint Data, string Name)>();
|
||||
var sheet = gameData.GetExcelSheet<CharaMakeCustomize>(ClientLanguage.English)!;
|
||||
foreach (var clan in customizations.AwaitedService.Clans)
|
||||
foreach (var clan in customizations.Service.Clans)
|
||||
{
|
||||
foreach (var gender in customizations.AwaitedService.Genders)
|
||||
foreach (var gender in customizations.Service.Genders)
|
||||
{
|
||||
var list = customizations.AwaitedService.GetList(clan, gender);
|
||||
var list = customizations.Service.GetList(clan, gender);
|
||||
foreach (var hair in list.HairStyles)
|
||||
{
|
||||
var x = sheet.FirstOrDefault(f => f.FeatureID == hair.Value.Value);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using FFXIVClientStructs.FFXIV.Client.Game.UI;
|
|||
using Glamourer.Events;
|
||||
using Glamourer.Services;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Cabinet = Lumina.Excel.GeneratedSheets.Cabinet;
|
||||
|
|
@ -22,7 +23,7 @@ public class ItemUnlockManager : ISavable, IDisposable, IReadOnlyDictionary<Item
|
|||
private readonly IClientState _clientState;
|
||||
private readonly IFramework _framework;
|
||||
private readonly ObjectUnlocked _event;
|
||||
private readonly IdentifierService _identifier;
|
||||
private readonly ObjectIdentification _identifier;
|
||||
|
||||
private readonly Dictionary<uint, long> _unlocked = new();
|
||||
|
||||
|
|
@ -45,7 +46,7 @@ public class ItemUnlockManager : ISavable, IDisposable, IReadOnlyDictionary<Item
|
|||
public readonly IReadOnlyDictionary<ItemId, UnlockRequirements> Unlockable;
|
||||
|
||||
public ItemUnlockManager(SaveService saveService, ItemManager items, IClientState clientState, IDataManager gameData, IFramework framework,
|
||||
ObjectUnlocked @event, IdentifierService identifier, IGameInteropProvider interop)
|
||||
ObjectUnlocked @event, ObjectIdentification identifier, IGameInteropProvider interop)
|
||||
{
|
||||
interop.InitializeFromAttributes(this);
|
||||
_saveService = saveService;
|
||||
|
|
@ -100,12 +101,12 @@ public class ItemUnlockManager : ISavable, IDisposable, IReadOnlyDictionary<Item
|
|||
private bool AddItem(ItemId itemId, long time)
|
||||
{
|
||||
itemId = itemId.StripModifiers;
|
||||
if (!_items.ItemService.AwaitedService.TryGetValue(itemId, EquipSlot.MainHand, out var equip)
|
||||
if (!_items.ItemData.TryGetValue(itemId, EquipSlot.MainHand, out var equip)
|
||||
|| !_unlocked.TryAdd(equip.ItemId.Id, time))
|
||||
return false;
|
||||
|
||||
_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());
|
||||
var ident = _identifier.Identify(equip.PrimaryId, equip.SecondaryId, equip.Variant, equip.Type.ToSlot());
|
||||
foreach (var item in ident)
|
||||
{
|
||||
if (_unlocked.TryAdd(item.ItemId.Id, time))
|
||||
|
|
@ -272,7 +273,7 @@ public class ItemUnlockManager : ISavable, IDisposable, IReadOnlyDictionary<Item
|
|||
private void Load()
|
||||
{
|
||||
var version = UnlockDictionaryHelpers.Load(ToFilename(_saveService.FileNames), _unlocked,
|
||||
id => _items.ItemService.AwaitedService.TryGetValue(id, EquipSlot.MainHand, out _), "item");
|
||||
id => _items.ItemData.TryGetValue(id, EquipSlot.MainHand, out _), "item");
|
||||
UpdateModels(version);
|
||||
}
|
||||
|
||||
|
|
@ -282,7 +283,7 @@ public class ItemUnlockManager : ISavable, IDisposable, IReadOnlyDictionary<Item
|
|||
var cabinet = gameData.GetExcelSheet<Cabinet>()!;
|
||||
foreach (var row in cabinet)
|
||||
{
|
||||
if (items.ItemService.AwaitedService.TryGetValue(row.Item.Row, EquipSlot.MainHand, out var item))
|
||||
if (items.ItemData.TryGetValue(row.Item.Row, EquipSlot.MainHand, out var item))
|
||||
ret.TryAdd(item.ItemId, new UnlockRequirements(row.RowId, 0, 0, 0, UnlockType.Cabinet));
|
||||
}
|
||||
|
||||
|
|
@ -290,7 +291,7 @@ public class ItemUnlockManager : ISavable, IDisposable, IReadOnlyDictionary<Item
|
|||
var gilShop = gameData.GetExcelSheet<GilShop>()!;
|
||||
foreach (var row in gilShopItem)
|
||||
{
|
||||
if (!items.ItemService.AwaitedService.TryGetValue(row.Item.Row, EquipSlot.MainHand, out var item))
|
||||
if (!items.ItemData.TryGetValue(row.Item.Row, EquipSlot.MainHand, out var item))
|
||||
continue;
|
||||
|
||||
var quest1 = row.QuestRequired[0].Row;
|
||||
|
|
@ -323,10 +324,10 @@ public class ItemUnlockManager : ISavable, IDisposable, IReadOnlyDictionary<Item
|
|||
|
||||
foreach (var (item, time) in _unlocked.ToArray())
|
||||
{
|
||||
if (!_items.ItemService.AwaitedService.TryGetValue(item, EquipSlot.MainHand, out var equip))
|
||||
if (!_items.ItemData.TryGetValue(item, EquipSlot.MainHand, out var equip))
|
||||
continue;
|
||||
|
||||
var ident = _identifier.AwaitedService.Identify(equip.ModelId, equip.WeaponType, equip.Variant, equip.Type.ToSlot());
|
||||
var ident = _identifier.Identify(equip.PrimaryId, equip.SecondaryId, equip.Variant, equip.Type.ToSlot());
|
||||
foreach (var item2 in ident)
|
||||
{
|
||||
if (_unlocked.TryAdd(item2.ItemId.Id, time))
|
||||
|
|
|
|||
2
OtterGui
2
OtterGui
|
|
@ -1 +1 @@
|
|||
Subproject commit 6a73878abbb477dc441ade70ad40352e2da9cc4c
|
||||
Subproject commit 197d23eee167c232000f22ef40a7a2bded913b6c
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit ffdb966fec5a657893289e655c641ceb3af1d59f
|
||||
Subproject commit 37b9bcf6727bd902fdb19a0a8b9d80b94f4cdd10
|
||||
Loading…
Add table
Add a link
Reference in a new issue