Add some valid options for material values.

This commit is contained in:
Ottermandias 2024-02-17 15:01:26 +01:00
parent ef2d9ba207
commit 0bc9fc872e
3 changed files with 52 additions and 18 deletions

View file

@ -57,7 +57,7 @@ public class GlamourerChangelog
.RegisterEntry(
"This was a considerable backend change on both automation sets and design application. I may have messed up and introduced bugs. Please let me know if something does not work right anymore.",
1)
.RegisterHighlight("Added advanced dye options for equipment. You can now runtime-edit the color sets of your gear.")
.RegisterHighlight("Added advanced dye options for equipment. You can now live-edit the color sets of your gear.")
.RegisterEntry(
"The logic for this is very complicated and may interfere with other options or not update correctly, it will need a lot of testing.",
1)

View file

@ -1,7 +1,7 @@
using System.Reflection.Metadata.Ecma335;
using Dalamud.Interface;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
using FFXIVClientStructs.Interop;
using Glamourer.Designs;
using Glamourer.Interop.Material;
@ -13,6 +13,7 @@ using OtterGui.Raii;
using OtterGui.Services;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Files;
using Penumbra.String;
namespace Glamourer.Gui.Materials;
@ -68,6 +69,20 @@ public sealed unsafe class AdvancedDyePopup(
ImGuiUtil.HoverTooltip("Open advanced dyes for this slot.");
}
private (string Path, string GamePath) ResourceName(MaterialValueIndex index)
{
var materialHandle = (MaterialResourceHandle*)_actor.Model.AsCharacterBase->MaterialsSpan[
index.MaterialIndex + index.SlotIndex * MaterialService.MaterialsPerModel].Value;
var model = _actor.Model.AsCharacterBase->ModelsSpan[index.SlotIndex].Value;
var modelHandle = model == null ? null : model->ModelResourceHandle;
var path = materialHandle == null
? string.Empty
: ByteString.FromSpanUnsafe(materialHandle->ResourceHandle.FileName.AsSpan(), true).ToString();
var gamePath = modelHandle == null
? string.Empty
: modelHandle->GetMaterialFileNameBySlotAsString(index.MaterialIndex);
return (path, gamePath);
}
private void DrawTabBar(ReadOnlySpan<Pointer<Texture>> textures, ref bool firstAvailable)
{
@ -79,6 +94,7 @@ public sealed unsafe class AdvancedDyePopup(
{
var index = _drawIndex!.Value with { MaterialIndex = i };
var available = index.TryGetTexture(textures, out var texture) && index.TryGetColorTable(texture, out var table);
if (index == preview.LastValueIndex with { RowIndex = 0 })
table = preview.LastOriginalColorTable;
@ -91,11 +107,16 @@ public sealed unsafe class AdvancedDyePopup(
firstAvailable = false;
using var tab = _label.TabItem(i, select);
if (!available)
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
{
using var disabled = ImRaii.Enabled();
ImGuiUtil.HoverTooltip("This material does not exist or does not have an associated color set.",
ImGuiHoveredFlags.AllowWhenDisabled);
using var enabled = ImRaii.Enabled();
var (path, gamePath) = ResourceName(index);
if (gamePath.Length == 0 || path.Length == 0)
ImGui.SetTooltip("This material does not exist.");
else if (!available)
ImGui.SetTooltip($"This material does not have an associated color set.\n\n{gamePath}\n{path}");
else
ImGui.SetTooltip($"{gamePath}\n{path}");
}
if ((tab.Success || select is ImGuiTabItemFlags.SetSelected) && available)
@ -186,7 +207,7 @@ public sealed unsafe class AdvancedDyePopup(
if (!changed)
{
var internalRow = new ColorRow(row);
var slot = index.ToSlot();
var slot = index.ToEquipSlot();
var weapon = slot is EquipSlot.MainHand or EquipSlot.OffHand
? _state.ModelData.Weapon(slot)
: _state.ModelData.Armor(slot).ToWeapon(0);

View file

@ -20,7 +20,7 @@ public readonly record struct MaterialValueIndex(
=> ToKey(DrawObject, SlotIndex, MaterialIndex, RowIndex);
public bool Valid
=> Validate(DrawObject) && ValidateSlot(SlotIndex) && ValidateMaterial(MaterialIndex) && ValidateRow(RowIndex);
=> Validate(DrawObject) && ValidateSlot(DrawObject, SlotIndex) && ValidateMaterial(MaterialIndex) && ValidateRow(RowIndex);
public static bool FromKey(uint key, out MaterialValueIndex index)
{
@ -42,7 +42,7 @@ public readonly record struct MaterialValueIndex(
return Invalid;
}
public EquipSlot ToSlot()
public EquipSlot ToEquipSlot()
=> DrawObject switch
{
DrawObjectType.Human when SlotIndex < 10 => ((uint)SlotIndex).ToEquipSlot(),
@ -155,8 +155,14 @@ public readonly record struct MaterialValueIndex(
public static bool Validate(DrawObjectType type)
=> type is not DrawObjectType.Invalid && Enum.IsDefined(type);
public static bool ValidateSlot(byte slotIndex)
=> slotIndex < 10;
public static bool ValidateSlot(DrawObjectType type, byte slotIndex)
=> type switch
{
DrawObjectType.Human => slotIndex < 14,
DrawObjectType.Mainhand => slotIndex == 0,
DrawObjectType.Offhand => slotIndex == 0,
_ => false,
};
public static bool ValidateMaterial(byte materialIndex)
=> materialIndex < MaterialService.MaterialsPerModel;
@ -178,12 +184,19 @@ public readonly record struct MaterialValueIndex(
{ }
public override string ToString()
{
var slot = ToSlot();
return slot is EquipSlot.Unknown
? $"{DrawObject} Slot {SlotIndex} Material #{MaterialIndex + 1} Row #{RowIndex + 1}"
: $"{slot.ToName()} Material #{MaterialIndex + 1} Row #{RowIndex + 1}";
}
=> DrawObject switch
{
DrawObjectType.Invalid => "Invalid",
DrawObjectType.Human when SlotIndex < 10 =>
$"{((uint)SlotIndex).ToEquipSlot().ToName()} Material #{MaterialIndex + 1} Row #{RowIndex + 1}",
DrawObjectType.Human when SlotIndex == 10 => $"BodySlot.Hair.ToString() Material #{MaterialIndex + 1} Row #{RowIndex + 1}",
DrawObjectType.Human when SlotIndex == 11 => $"BodySlot.Face.ToString() Material #{MaterialIndex + 1} Row #{RowIndex + 1}",
DrawObjectType.Human when SlotIndex == 12 => $"{BodySlot.Tail} / {BodySlot.Ear} Material #{MaterialIndex + 1} Row #{RowIndex + 1}",
DrawObjectType.Human when SlotIndex == 13 => $"Connectors Material #{MaterialIndex + 1} Row #{RowIndex + 1}",
DrawObjectType.Mainhand when SlotIndex == 0 => $"{EquipSlot.MainHand.ToName()} Material #{MaterialIndex + 1} Row #{RowIndex + 1}",
DrawObjectType.Offhand when SlotIndex == 0 => $"{EquipSlot.OffHand.ToName()} Material #{MaterialIndex + 1} Row #{RowIndex + 1}",
_ => $"{DrawObject} Slot {SlotIndex} Material #{MaterialIndex + 1} Row #{RowIndex + 1}",
};
private class Converter : JsonConverter<MaterialValueIndex>
{