Accept all existing facepaints.

This commit is contained in:
Ottermandias 2025-01-30 13:36:06 +01:00
parent b3afa2067c
commit 2a067ef60b
5 changed files with 63 additions and 23 deletions

View file

@ -11,7 +11,7 @@ namespace Glamourer.GameData;
/// </summary> /// </summary>
public class CustomizeSet public class CustomizeSet
{ {
private NpcCustomizeSet _npcCustomizations; private readonly NpcCustomizeSet _npcCustomizations;
internal CustomizeSet(NpcCustomizeSet npcCustomizations, SubRace clan, Gender gender) internal CustomizeSet(NpcCustomizeSet npcCustomizations, SubRace clan, Gender gender)
{ {
@ -88,7 +88,7 @@ public class CustomizeSet
{ {
if (IsAvailable(index)) if (IsAvailable(index))
return DataByValue(index, value, out custom, face) >= 0 return DataByValue(index, value, out custom, face) >= 0
|| _npcCustomizations.CheckColor(index, value) || _npcCustomizations.CheckValue(index, value)
|| NpcOptions.Any(t => t.Type == index && t.Value == value); || NpcOptions.Any(t => t.Type == index && t.Value == value);
custom = null; custom = null;

View file

@ -76,7 +76,6 @@ internal class CustomizeSetFactory(
CustomizeIndex.Hairstyle, CustomizeIndex.Hairstyle,
CustomizeIndex.LipColor, CustomizeIndex.LipColor,
CustomizeIndex.SkinColor, CustomizeIndex.SkinColor,
CustomizeIndex.FacePaint,
CustomizeIndex.TailShape, CustomizeIndex.TailShape,
}; };

View file

@ -3,6 +3,7 @@ using Dalamud.Utility;
using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.Game.Object;
using Lumina.Excel.Sheets; using Lumina.Excel.Sheets;
using OtterGui.Services; using OtterGui.Services;
using Penumbra.GameData.Data;
using Penumbra.GameData.DataContainers; using Penumbra.GameData.DataContainers;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
@ -40,17 +41,19 @@ public class NpcCustomizeSet : IAsyncDataContainer, IReadOnlyList<NpcData>
private readonly BitArray _eyeColors = new(256); private readonly BitArray _eyeColors = new(256);
private readonly BitArray _facepaintColors = new(256); private readonly BitArray _facepaintColors = new(256);
private readonly BitArray _tattooColors = new(256); private readonly BitArray _tattooColors = new(256);
private readonly BitArray _facepaints = new(128);
public bool CheckColor(CustomizeIndex type, CustomizeValue value) public bool CheckValue(CustomizeIndex type, CustomizeValue value)
=> type switch => type switch
{ {
CustomizeIndex.HairColor => _hairColors[value.Value], CustomizeIndex.HairColor => _hairColors[value.Value],
CustomizeIndex.HighlightsColor => _hairColors[value.Value], CustomizeIndex.HighlightsColor => _hairColors[value.Value],
CustomizeIndex.EyeColorLeft => _eyeColors[value.Value], CustomizeIndex.EyeColorLeft => _eyeColors[value.Value],
CustomizeIndex.EyeColorRight => _eyeColors[value.Value], CustomizeIndex.EyeColorRight => _eyeColors[value.Value],
CustomizeIndex.FacePaintColor => _facepaintColors[value.Value], CustomizeIndex.FacePaintColor => _facepaintColors[value.Value],
CustomizeIndex.TattooColor => _tattooColors[value.Value], CustomizeIndex.TattooColor => _tattooColors[value.Value],
_ => false, CustomizeIndex.FacePaint when value.Value < 128 => _facepaints[value.Value],
_ => false,
}; };
/// <summary> Create the data when ready. </summary> /// <summary> Create the data when ready. </summary>
@ -58,13 +61,14 @@ public class NpcCustomizeSet : IAsyncDataContainer, IReadOnlyList<NpcData>
{ {
var waitTask = Task.WhenAll(eNpcs.Awaiter, bNpcs.Awaiter, bNpcNames.Awaiter); var waitTask = Task.WhenAll(eNpcs.Awaiter, bNpcs.Awaiter, bNpcNames.Awaiter);
Awaiter = waitTask.ContinueWith(_ => Awaiter = waitTask.ContinueWith(_ =>
{ {
var watch = Stopwatch.StartNew(); var watch = Stopwatch.StartNew();
var eNpcTask = Task.Run(() => CreateEnpcData(data, eNpcs)); var eNpcTask = Task.Run(() => CreateEnpcData(data, eNpcs));
var bNpcTask = Task.Run(() => CreateBnpcData(data, bNpcs, bNpcNames)); var bNpcTask = Task.Run(() => CreateBnpcData(data, bNpcs, bNpcNames));
FilterAndOrderNpcData(eNpcTask.Result, bNpcTask.Result); FilterAndOrderNpcData(eNpcTask.Result, bNpcTask.Result);
Time = watch.ElapsedMilliseconds; Time = watch.ElapsedMilliseconds;
}); })
.ContinueWith(_ => CheckFacepaintFiles(data, _facepaints));
} }
/// <summary> Create data from event NPCs. </summary> /// <summary> Create data from event NPCs. </summary>
@ -323,6 +327,17 @@ public class NpcCustomizeSet : IAsyncDataContainer, IReadOnlyList<NpcData>
return (true, customize); return (true, customize);
} }
/// <summary> Check decal files for existence. </summary>
private static void CheckFacepaintFiles(IDataManager data, BitArray facepaints)
{
for (var i = 0; i < 128; ++i)
{
var path = GamePaths.Character.Tex.DecalPath("face", (PrimaryId)i);
if (data.FileExists(path))
facepaints[i] = true;
}
}
/// <inheritdoc/> /// <inheritdoc/>
public IEnumerator<NpcData> GetEnumerator() public IEnumerator<NpcData> GetEnumerator()
=> _data.GetEnumerator(); => _data.GetEnumerator();

View file

@ -28,9 +28,35 @@ public class CustomizationServicePanel(CustomizeService customize) : IGameDataDr
DrawNpcCustomizationInfo(set); DrawNpcCustomizationInfo(set);
} }
DrawFacepaintInfo();
DrawColorInfo(); DrawColorInfo();
} }
private void DrawFacepaintInfo()
{
using var tree = ImUtf8.TreeNode("NPC Facepaints"u8);
if (!tree)
return;
using var table = ImUtf8.Table("data"u8, 2, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg);
if (!table)
return;
ImGui.TableNextColumn();
ImUtf8.TableHeader("Id"u8);
ImGui.TableNextColumn();
ImUtf8.TableHeader("Facepaint"u8);
for (var i = 0; i < 128; ++i)
{
var index = new CustomizeValue((byte)i);
ImUtf8.DrawTableColumn($"{i:D3}");
using var font = ImRaii.PushFont(UiBuilder.IconFont);
ImUtf8.DrawTableColumn(customize.NpcCustomizeSet.CheckValue(CustomizeIndex.FacePaint, index)
? FontAwesomeIcon.Check.ToIconString()
: FontAwesomeIcon.Times.ToIconString());
}
}
private void DrawColorInfo() private void DrawColorInfo()
{ {
using var tree = ImUtf8.TreeNode("NPC Colors"u8); using var tree = ImUtf8.TreeNode("NPC Colors"u8);
@ -57,16 +83,16 @@ public class CustomizationServicePanel(CustomizeService customize) : IGameDataDr
var index = new CustomizeValue((byte)i); var index = new CustomizeValue((byte)i);
ImUtf8.DrawTableColumn($"{i:D3}"); ImUtf8.DrawTableColumn($"{i:D3}");
using var font = ImRaii.PushFont(UiBuilder.IconFont); using var font = ImRaii.PushFont(UiBuilder.IconFont);
ImUtf8.DrawTableColumn(customize.NpcCustomizeSet.CheckColor(CustomizeIndex.HairColor, index) ImUtf8.DrawTableColumn(customize.NpcCustomizeSet.CheckValue(CustomizeIndex.HairColor, index)
? FontAwesomeIcon.Check.ToIconString() ? FontAwesomeIcon.Check.ToIconString()
: FontAwesomeIcon.Times.ToIconString()); : FontAwesomeIcon.Times.ToIconString());
ImUtf8.DrawTableColumn(customize.NpcCustomizeSet.CheckColor(CustomizeIndex.EyeColorLeft, index) ImUtf8.DrawTableColumn(customize.NpcCustomizeSet.CheckValue(CustomizeIndex.EyeColorLeft, index)
? FontAwesomeIcon.Check.ToIconString() ? FontAwesomeIcon.Check.ToIconString()
: FontAwesomeIcon.Times.ToIconString()); : FontAwesomeIcon.Times.ToIconString());
ImUtf8.DrawTableColumn(customize.NpcCustomizeSet.CheckColor(CustomizeIndex.FacePaintColor, index) ImUtf8.DrawTableColumn(customize.NpcCustomizeSet.CheckValue(CustomizeIndex.FacePaintColor, index)
? FontAwesomeIcon.Check.ToIconString() ? FontAwesomeIcon.Check.ToIconString()
: FontAwesomeIcon.Times.ToIconString()); : FontAwesomeIcon.Times.ToIconString());
ImUtf8.DrawTableColumn(customize.NpcCustomizeSet.CheckColor(CustomizeIndex.TattooColor, index) ImUtf8.DrawTableColumn(customize.NpcCustomizeSet.CheckValue(CustomizeIndex.TattooColor, index)
? FontAwesomeIcon.Check.ToIconString() ? FontAwesomeIcon.Check.ToIconString()
: FontAwesomeIcon.Times.ToIconString()); : FontAwesomeIcon.Times.ToIconString());
} }

@ -1 +1 @@
Subproject commit bb596141bb582505ae9fae1dd2914773503f4fe7 Subproject commit 488043381efd42238e9c1328ccab3b80abd81ea7