mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
tmp
This commit is contained in:
parent
196ca2ce39
commit
361082813b
16 changed files with 1008 additions and 660 deletions
|
|
@ -7,7 +7,7 @@ using ImcEntry = Penumbra.GameData.Structs.ImcEntry;
|
||||||
namespace Penumbra.Meta.Manipulations;
|
namespace Penumbra.Meta.Manipulations;
|
||||||
|
|
||||||
[JsonConverter(typeof(Converter))]
|
[JsonConverter(typeof(Converter))]
|
||||||
public sealed class MetaDictionary : IEnumerable<MetaManipulation>
|
public class MetaDictionary : IEnumerable<MetaManipulation>
|
||||||
{
|
{
|
||||||
private readonly Dictionary<ImcIdentifier, ImcEntry> _imc = [];
|
private readonly Dictionary<ImcIdentifier, ImcEntry> _imc = [];
|
||||||
private readonly Dictionary<EqpIdentifier, EqpEntryInternal> _eqp = [];
|
private readonly Dictionary<EqpIdentifier, EqpEntryInternal> _eqp = [];
|
||||||
|
|
@ -17,8 +17,37 @@ public sealed class MetaDictionary : IEnumerable<MetaManipulation>
|
||||||
private readonly Dictionary<GmpIdentifier, GmpEntry> _gmp = [];
|
private readonly Dictionary<GmpIdentifier, GmpEntry> _gmp = [];
|
||||||
private readonly HashSet<GlobalEqpManipulation> _globalEqp = [];
|
private readonly HashSet<GlobalEqpManipulation> _globalEqp = [];
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<ImcIdentifier, ImcEntry> Imc
|
||||||
|
=> _imc;
|
||||||
|
|
||||||
public int Count { get; private set; }
|
public int Count { get; private set; }
|
||||||
|
|
||||||
|
public int GetCount(MetaManipulation.Type type)
|
||||||
|
=> type switch
|
||||||
|
{
|
||||||
|
MetaManipulation.Type.Imc => _imc.Count,
|
||||||
|
MetaManipulation.Type.Eqdp => _eqdp.Count,
|
||||||
|
MetaManipulation.Type.Eqp => _eqp.Count,
|
||||||
|
MetaManipulation.Type.Est => _est.Count,
|
||||||
|
MetaManipulation.Type.Gmp => _gmp.Count,
|
||||||
|
MetaManipulation.Type.Rsp => _rsp.Count,
|
||||||
|
MetaManipulation.Type.GlobalEqp => _globalEqp.Count,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
public bool CanAdd(IMetaIdentifier identifier)
|
||||||
|
=> identifier switch
|
||||||
|
{
|
||||||
|
EqdpIdentifier eqdpIdentifier => !_eqdp.ContainsKey(eqdpIdentifier),
|
||||||
|
EqpIdentifier eqpIdentifier => !_eqp.ContainsKey(eqpIdentifier),
|
||||||
|
EstIdentifier estIdentifier => !_est.ContainsKey(estIdentifier),
|
||||||
|
GlobalEqpManipulation globalEqpManipulation => !_globalEqp.Contains(globalEqpManipulation),
|
||||||
|
GmpIdentifier gmpIdentifier => !_gmp.ContainsKey(gmpIdentifier),
|
||||||
|
ImcIdentifier imcIdentifier => !_imc.ContainsKey(imcIdentifier),
|
||||||
|
RspIdentifier rspIdentifier => !_rsp.ContainsKey(rspIdentifier),
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
_imc.Clear();
|
_imc.Clear();
|
||||||
|
|
@ -123,6 +152,68 @@ public sealed class MetaDictionary : IEnumerable<MetaManipulation>
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool Update(ImcIdentifier identifier, ImcEntry entry)
|
||||||
|
{
|
||||||
|
if (!_imc.ContainsKey(identifier))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_imc[identifier] = entry;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool Update(EqpIdentifier identifier, EqpEntryInternal entry)
|
||||||
|
{
|
||||||
|
if (!_eqp.ContainsKey(identifier))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_eqp[identifier] = entry;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Update(EqpIdentifier identifier, EqpEntry entry)
|
||||||
|
=> Update(identifier, new EqpEntryInternal(entry, identifier.Slot));
|
||||||
|
|
||||||
|
|
||||||
|
public bool Update(EqdpIdentifier identifier, EqdpEntryInternal entry)
|
||||||
|
{
|
||||||
|
if (!_eqdp.ContainsKey(identifier))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_eqdp[identifier] = entry;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Update(EqdpIdentifier identifier, EqdpEntry entry)
|
||||||
|
=> Update(identifier, new EqdpEntryInternal(entry, identifier.Slot));
|
||||||
|
|
||||||
|
public bool Update(EstIdentifier identifier, EstEntry entry)
|
||||||
|
{
|
||||||
|
if (!_est.ContainsKey(identifier))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_est[identifier] = entry;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Update(GmpIdentifier identifier, GmpEntry entry)
|
||||||
|
{
|
||||||
|
if (!_gmp.ContainsKey(identifier))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_gmp[identifier] = entry;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Update(RspIdentifier identifier, RspEntry entry)
|
||||||
|
{
|
||||||
|
if (!_rsp.ContainsKey(identifier))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_rsp[identifier] = entry;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public void UnionWith(MetaDictionary manips)
|
public void UnionWith(MetaDictionary manips)
|
||||||
{
|
{
|
||||||
foreach (var (identifier, entry) in manips._imc)
|
foreach (var (identifier, entry) in manips._imc)
|
||||||
|
|
@ -148,70 +239,52 @@ public sealed class MetaDictionary : IEnumerable<MetaManipulation>
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Try to merge all manipulations from manips into this, and return the first failure, if any. </summary>
|
/// <summary> Try to merge all manipulations from manips into this, and return the first failure, if any. </summary>
|
||||||
public bool MergeForced(MetaDictionary manips, out IMetaIdentifier failedIdentifier)
|
public bool MergeForced(MetaDictionary manips, out IMetaIdentifier? failedIdentifier)
|
||||||
{
|
{
|
||||||
foreach (var (identifier, entry) in manips._imc)
|
foreach (var (identifier, _) in manips._imc.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
||||||
{
|
{
|
||||||
if (!TryAdd(identifier, entry))
|
failedIdentifier = identifier;
|
||||||
{
|
return false;
|
||||||
failedIdentifier = identifier;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (identifier, entry) in manips._eqp)
|
foreach (var (identifier, _) in manips._eqp.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
||||||
{
|
{
|
||||||
if (!TryAdd(identifier, entry))
|
failedIdentifier = identifier;
|
||||||
{
|
return false;
|
||||||
failedIdentifier = identifier;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (identifier, entry) in manips._eqdp)
|
foreach (var (identifier, _) in manips._eqdp.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
||||||
{
|
{
|
||||||
if (!TryAdd(identifier, entry))
|
failedIdentifier = identifier;
|
||||||
{
|
return false;
|
||||||
failedIdentifier = identifier;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (identifier, entry) in manips._gmp)
|
foreach (var (identifier, _) in manips._gmp.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
||||||
{
|
{
|
||||||
if (!TryAdd(identifier, entry))
|
failedIdentifier = identifier;
|
||||||
{
|
return false;
|
||||||
failedIdentifier = identifier;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (identifier, entry) in manips._rsp)
|
foreach (var (identifier, _) in manips._rsp.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
||||||
{
|
{
|
||||||
if (!TryAdd(identifier, entry))
|
failedIdentifier = identifier;
|
||||||
{
|
return false;
|
||||||
failedIdentifier = identifier;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (identifier, entry) in manips._est)
|
foreach (var (identifier, _) in manips._est.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
||||||
{
|
{
|
||||||
if (!TryAdd(identifier, entry))
|
failedIdentifier = identifier;
|
||||||
{
|
return false;
|
||||||
failedIdentifier = identifier;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var identifier in manips._globalEqp)
|
foreach (var identifier in manips._globalEqp.Where(identifier => !TryAdd(identifier)))
|
||||||
{
|
{
|
||||||
if (!TryAdd(identifier))
|
failedIdentifier = identifier;
|
||||||
{
|
return false;
|
||||||
failedIdentifier = identifier;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
failedIdentifier = default;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetValue(EstIdentifier identifier, out EstEntry value)
|
public bool TryGetValue(EstIdentifier identifier, out EstEntry value)
|
||||||
|
|
@ -244,6 +317,18 @@ public sealed class MetaDictionary : IEnumerable<MetaManipulation>
|
||||||
Count = _imc.Count + _eqp.Count + _eqdp.Count + _est.Count + _rsp.Count + _gmp.Count + _globalEqp.Count;
|
Count = _imc.Count + _eqp.Count + _eqdp.Count + _est.Count + _rsp.Count + _gmp.Count + _globalEqp.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateTo(MetaDictionary other)
|
||||||
|
{
|
||||||
|
_imc.UpdateTo(other._imc);
|
||||||
|
_eqp.UpdateTo(other._eqp);
|
||||||
|
_eqdp.UpdateTo(other._eqdp);
|
||||||
|
_est.UpdateTo(other._est);
|
||||||
|
_rsp.UpdateTo(other._rsp);
|
||||||
|
_gmp.UpdateTo(other._gmp);
|
||||||
|
_globalEqp.UnionWith(other._globalEqp);
|
||||||
|
Count = _imc.Count + _eqp.Count + _eqdp.Count + _est.Count + _rsp.Count + _gmp.Count + _globalEqp.Count;
|
||||||
|
}
|
||||||
|
|
||||||
public MetaDictionary Clone()
|
public MetaDictionary Clone()
|
||||||
{
|
{
|
||||||
var ret = new MetaDictionary();
|
var ret = new MetaDictionary();
|
||||||
|
|
@ -251,6 +336,31 @@ public sealed class MetaDictionary : IEnumerable<MetaManipulation>
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void WriteJson(JsonWriter writer, JsonSerializer serializer, IMetaIdentifier identifier, object entry)
|
||||||
|
{
|
||||||
|
var type = identifier switch
|
||||||
|
{
|
||||||
|
ImcIdentifier => "Imc",
|
||||||
|
EqdpIdentifier => "Eqdp",
|
||||||
|
EqpIdentifier => "Eqp",
|
||||||
|
EstIdentifier => "Est",
|
||||||
|
GmpIdentifier => "Gmp",
|
||||||
|
RspIdentifier => "Rsp",
|
||||||
|
GlobalEqpManipulation => "GlobalEqp",
|
||||||
|
_ => string.Empty,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (type.Length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
writer.WriteStartObject();
|
||||||
|
writer.WritePropertyName("Type");
|
||||||
|
writer.WriteValue(type);
|
||||||
|
writer.WritePropertyName("Manipulation");
|
||||||
|
|
||||||
|
writer.WriteEndObject();
|
||||||
|
}
|
||||||
|
|
||||||
private class Converter : JsonConverter<MetaDictionary>
|
private class Converter : JsonConverter<MetaDictionary>
|
||||||
{
|
{
|
||||||
public override void WriteJson(JsonWriter writer, MetaDictionary? value, JsonSerializer serializer)
|
public override void WriteJson(JsonWriter writer, MetaDictionary? value, JsonSerializer serializer)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,148 @@
|
||||||
|
using Dalamud.Interface;
|
||||||
|
using ImGuiNET;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Converters;
|
using Newtonsoft.Json.Converters;
|
||||||
|
using OtterGui;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.Interop.Structs;
|
using Penumbra.Interop.Structs;
|
||||||
|
using Penumbra.Mods.Editor;
|
||||||
using Penumbra.String.Functions;
|
using Penumbra.String.Functions;
|
||||||
|
using Penumbra.UI;
|
||||||
|
using Penumbra.UI.ModsTab;
|
||||||
|
|
||||||
namespace Penumbra.Meta.Manipulations;
|
namespace Penumbra.Meta.Manipulations;
|
||||||
|
|
||||||
|
#if false
|
||||||
|
private static class ImcRow
|
||||||
|
{
|
||||||
|
private static ImcIdentifier _newIdentifier = ImcIdentifier.Default;
|
||||||
|
|
||||||
|
private static float IdWidth
|
||||||
|
=> 80 * UiHelpers.Scale;
|
||||||
|
|
||||||
|
private static float SmallIdWidth
|
||||||
|
=> 45 * UiHelpers.Scale;
|
||||||
|
|
||||||
|
public static void DrawNew(MetaFileManager metaFileManager, ModEditor editor, Vector2 iconSize)
|
||||||
|
{
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
CopyToClipboardButton("Copy all current IMC manipulations to clipboard.", iconSize,
|
||||||
|
editor.MetaEditor.Imc.Select(m => (MetaManipulation)m));
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
var (defaultEntry, fileExists, _) = metaFileManager.ImcChecker.GetDefaultEntry(_newIdentifier, true);
|
||||||
|
var manip = (MetaManipulation)new ImcManipulation(_newIdentifier, defaultEntry);
|
||||||
|
var canAdd = fileExists && editor.MetaEditor.CanAdd(manip);
|
||||||
|
var tt = canAdd ? "Stage this edit." : !fileExists ? "This IMC file does not exist." : "This entry is already edited.";
|
||||||
|
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), iconSize, tt, !canAdd, true))
|
||||||
|
editor.MetaEditor.Add(manip);
|
||||||
|
|
||||||
|
// Identifier
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
var change = ImcManipulationDrawer.DrawObjectType(ref _newIdentifier);
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
change |= ImcManipulationDrawer.DrawPrimaryId(ref _newIdentifier);
|
||||||
|
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing,
|
||||||
|
new Vector2(3 * UiHelpers.Scale, ImGui.GetStyle().ItemSpacing.Y));
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
// Equipment and accessories are slightly different imcs than other types.
|
||||||
|
if (_newIdentifier.ObjectType is ObjectType.Equipment or ObjectType.Accessory)
|
||||||
|
change |= ImcManipulationDrawer.DrawSlot(ref _newIdentifier);
|
||||||
|
else
|
||||||
|
change |= ImcManipulationDrawer.DrawSecondaryId(ref _newIdentifier);
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
change |= ImcManipulationDrawer.DrawVariant(ref _newIdentifier);
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
if (_newIdentifier.ObjectType is ObjectType.DemiHuman)
|
||||||
|
change |= ImcManipulationDrawer.DrawSlot(ref _newIdentifier, 70);
|
||||||
|
else
|
||||||
|
ImUtf8.ScaledDummy(new Vector2(70 * UiHelpers.Scale, 0));
|
||||||
|
|
||||||
|
if (change)
|
||||||
|
defaultEntry = metaFileManager.ImcChecker.GetDefaultEntry(_newIdentifier, true).Entry;
|
||||||
|
// Values
|
||||||
|
using var disabled = ImRaii.Disabled();
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImcManipulationDrawer.DrawMaterialId(defaultEntry, ref defaultEntry, false);
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImcManipulationDrawer.DrawMaterialAnimationId(defaultEntry, ref defaultEntry, false);
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImcManipulationDrawer.DrawDecalId(defaultEntry, ref defaultEntry, false);
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImcManipulationDrawer.DrawVfxId(defaultEntry, ref defaultEntry, false);
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImcManipulationDrawer.DrawSoundId(defaultEntry, ref defaultEntry, false);
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImcManipulationDrawer.DrawAttributes(defaultEntry, ref defaultEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Draw(MetaFileManager metaFileManager, ImcManipulation meta, ModEditor editor, Vector2 iconSize)
|
||||||
|
{
|
||||||
|
DrawMetaButtons(meta, editor, iconSize);
|
||||||
|
|
||||||
|
// Identifier
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + ImGui.GetStyle().FramePadding.X);
|
||||||
|
ImGui.TextUnformatted(meta.ObjectType.ToName());
|
||||||
|
ImGuiUtil.HoverTooltip(ObjectTypeTooltip);
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + ImGui.GetStyle().FramePadding.X);
|
||||||
|
ImGui.TextUnformatted(meta.PrimaryId.ToString());
|
||||||
|
ImGuiUtil.HoverTooltip(PrimaryIdTooltipShort);
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + ImGui.GetStyle().FramePadding.X);
|
||||||
|
if (meta.ObjectType is ObjectType.Equipment or ObjectType.Accessory)
|
||||||
|
{
|
||||||
|
ImGui.TextUnformatted(meta.EquipSlot.ToName());
|
||||||
|
ImGuiUtil.HoverTooltip(EquipSlotTooltip);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.TextUnformatted(meta.SecondaryId.ToString());
|
||||||
|
ImGuiUtil.HoverTooltip(SecondaryIdTooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + ImGui.GetStyle().FramePadding.X);
|
||||||
|
ImGui.TextUnformatted(meta.Variant.ToString());
|
||||||
|
ImGuiUtil.HoverTooltip(VariantIdTooltip);
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + ImGui.GetStyle().FramePadding.X);
|
||||||
|
if (meta.ObjectType is ObjectType.DemiHuman)
|
||||||
|
{
|
||||||
|
ImGui.TextUnformatted(meta.EquipSlot.ToName());
|
||||||
|
ImGuiUtil.HoverTooltip(EquipSlotTooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Values
|
||||||
|
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing,
|
||||||
|
new Vector2(3 * UiHelpers.Scale, ImGui.GetStyle().ItemSpacing.Y));
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
var defaultEntry = metaFileManager.ImcChecker.GetDefaultEntry(meta.Identifier, true).Entry;
|
||||||
|
var newEntry = meta.Entry;
|
||||||
|
var changes = ImcManipulationDrawer.DrawMaterialId(defaultEntry, ref newEntry, true);
|
||||||
|
ImGui.SameLine();
|
||||||
|
changes |= ImcManipulationDrawer.DrawMaterialAnimationId(defaultEntry, ref newEntry, true);
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
changes |= ImcManipulationDrawer.DrawDecalId(defaultEntry, ref newEntry, true);
|
||||||
|
ImGui.SameLine();
|
||||||
|
changes |= ImcManipulationDrawer.DrawVfxId(defaultEntry, ref newEntry, true);
|
||||||
|
ImGui.SameLine();
|
||||||
|
changes |= ImcManipulationDrawer.DrawSoundId(defaultEntry, ref newEntry, true);
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
changes |= ImcManipulationDrawer.DrawAttributes(defaultEntry, ref newEntry);
|
||||||
|
|
||||||
|
if (changes)
|
||||||
|
editor.MetaEditor.Change(meta.Copy(newEntry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
public interface IMetaManipulation
|
public interface IMetaManipulation
|
||||||
{
|
{
|
||||||
|
|
@ -315,3 +454,4 @@ public readonly struct MetaManipulation : IEquatable<MetaManipulation>, ICompara
|
||||||
public static bool operator >=(MetaManipulation left, MetaManipulation right)
|
public static bool operator >=(MetaManipulation left, MetaManipulation right)
|
||||||
=> left.CompareTo(right) >= 0;
|
=> left.CompareTo(right) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -162,12 +162,9 @@ public class ModMerger : IDisposable
|
||||||
|
|
||||||
foreach (var originalOption in mergeOptions)
|
foreach (var originalOption in mergeOptions)
|
||||||
{
|
{
|
||||||
foreach (var manip in originalOption.Manipulations)
|
if (!manips.MergeForced(originalOption.Manipulations, out var failed))
|
||||||
{
|
throw new Exception(
|
||||||
if (!manips.Add(manip))
|
$"Could not add meta manipulation {failed} from {originalOption.GetFullName()} to {option.GetFullName()} because another manipulation of the same data already exists in this option.");
|
||||||
throw new Exception(
|
|
||||||
$"Could not add meta manipulation {manip} from {originalOption.GetFullName()} to {option.GetFullName()} because another manipulation of the same data already exists in this option.");
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var (swapA, swapB) in originalOption.FileSwaps)
|
foreach (var (swapA, swapB) in originalOption.FileSwaps)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,24 @@
|
||||||
using System.Collections.Frozen;
|
using System.Collections.Frozen;
|
||||||
|
using OtterGui.Services;
|
||||||
using Penumbra.Meta.Manipulations;
|
using Penumbra.Meta.Manipulations;
|
||||||
using Penumbra.Mods.Manager;
|
using Penumbra.Mods.Manager;
|
||||||
using Penumbra.Mods.SubMods;
|
using Penumbra.Mods.SubMods;
|
||||||
|
|
||||||
namespace Penumbra.Mods.Editor;
|
namespace Penumbra.Mods.Editor;
|
||||||
|
|
||||||
public class ModMetaEditor(ModManager modManager)
|
public class ModMetaEditor(ModManager modManager) : MetaDictionary, IService
|
||||||
{
|
{
|
||||||
private readonly HashSet<ImcManipulation> _imc = [];
|
|
||||||
private readonly HashSet<EqpManipulation> _eqp = [];
|
|
||||||
private readonly HashSet<EqdpManipulation> _eqdp = [];
|
|
||||||
private readonly HashSet<GmpManipulation> _gmp = [];
|
|
||||||
private readonly HashSet<EstManipulation> _est = [];
|
|
||||||
private readonly HashSet<RspManipulation> _rsp = [];
|
|
||||||
private readonly HashSet<GlobalEqpManipulation> _globalEqp = [];
|
|
||||||
|
|
||||||
public sealed class OtherOptionData : HashSet<string>
|
public sealed class OtherOptionData : HashSet<string>
|
||||||
{
|
{
|
||||||
public int TotalCount;
|
public int TotalCount;
|
||||||
|
|
||||||
|
public void Add(string name, int count)
|
||||||
|
{
|
||||||
|
if (count > 0)
|
||||||
|
Add(name);
|
||||||
|
TotalCount += count;
|
||||||
|
}
|
||||||
|
|
||||||
public new void Clear()
|
public new void Clear()
|
||||||
{
|
{
|
||||||
TotalCount = 0;
|
TotalCount = 0;
|
||||||
|
|
@ -31,91 +31,9 @@ public class ModMetaEditor(ModManager modManager)
|
||||||
|
|
||||||
public bool Changes { get; private set; }
|
public bool Changes { get; private set; }
|
||||||
|
|
||||||
public IReadOnlySet<ImcManipulation> Imc
|
public new void Clear()
|
||||||
=> _imc;
|
|
||||||
|
|
||||||
public IReadOnlySet<EqpManipulation> Eqp
|
|
||||||
=> _eqp;
|
|
||||||
|
|
||||||
public IReadOnlySet<EqdpManipulation> Eqdp
|
|
||||||
=> _eqdp;
|
|
||||||
|
|
||||||
public IReadOnlySet<GmpManipulation> Gmp
|
|
||||||
=> _gmp;
|
|
||||||
|
|
||||||
public IReadOnlySet<EstManipulation> Est
|
|
||||||
=> _est;
|
|
||||||
|
|
||||||
public IReadOnlySet<RspManipulation> Rsp
|
|
||||||
=> _rsp;
|
|
||||||
|
|
||||||
public IReadOnlySet<GlobalEqpManipulation> GlobalEqp
|
|
||||||
=> _globalEqp;
|
|
||||||
|
|
||||||
public bool CanAdd(MetaManipulation m)
|
|
||||||
{
|
{
|
||||||
return m.ManipulationType switch
|
base.Clear();
|
||||||
{
|
|
||||||
MetaManipulation.Type.Imc => !_imc.Contains(m.Imc),
|
|
||||||
MetaManipulation.Type.Eqdp => !_eqdp.Contains(m.Eqdp),
|
|
||||||
MetaManipulation.Type.Eqp => !_eqp.Contains(m.Eqp),
|
|
||||||
MetaManipulation.Type.Est => !_est.Contains(m.Est),
|
|
||||||
MetaManipulation.Type.Gmp => !_gmp.Contains(m.Gmp),
|
|
||||||
MetaManipulation.Type.Rsp => !_rsp.Contains(m.Rsp),
|
|
||||||
MetaManipulation.Type.GlobalEqp => !_globalEqp.Contains(m.GlobalEqp),
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Add(MetaManipulation m)
|
|
||||||
{
|
|
||||||
var added = m.ManipulationType switch
|
|
||||||
{
|
|
||||||
MetaManipulation.Type.Imc => _imc.Add(m.Imc),
|
|
||||||
MetaManipulation.Type.Eqdp => _eqdp.Add(m.Eqdp),
|
|
||||||
MetaManipulation.Type.Eqp => _eqp.Add(m.Eqp),
|
|
||||||
MetaManipulation.Type.Est => _est.Add(m.Est),
|
|
||||||
MetaManipulation.Type.Gmp => _gmp.Add(m.Gmp),
|
|
||||||
MetaManipulation.Type.Rsp => _rsp.Add(m.Rsp),
|
|
||||||
MetaManipulation.Type.GlobalEqp => _globalEqp.Add(m.GlobalEqp),
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
Changes |= added;
|
|
||||||
return added;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Delete(MetaManipulation m)
|
|
||||||
{
|
|
||||||
var deleted = m.ManipulationType switch
|
|
||||||
{
|
|
||||||
MetaManipulation.Type.Imc => _imc.Remove(m.Imc),
|
|
||||||
MetaManipulation.Type.Eqdp => _eqdp.Remove(m.Eqdp),
|
|
||||||
MetaManipulation.Type.Eqp => _eqp.Remove(m.Eqp),
|
|
||||||
MetaManipulation.Type.Est => _est.Remove(m.Est),
|
|
||||||
MetaManipulation.Type.Gmp => _gmp.Remove(m.Gmp),
|
|
||||||
MetaManipulation.Type.Rsp => _rsp.Remove(m.Rsp),
|
|
||||||
MetaManipulation.Type.GlobalEqp => _globalEqp.Remove(m.GlobalEqp),
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
Changes |= deleted;
|
|
||||||
return deleted;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Change(MetaManipulation m)
|
|
||||||
=> Delete(m) && Add(m);
|
|
||||||
|
|
||||||
public bool Set(MetaManipulation m)
|
|
||||||
=> Delete(m) | Add(m);
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
_imc.Clear();
|
|
||||||
_eqp.Clear();
|
|
||||||
_eqdp.Clear();
|
|
||||||
_gmp.Clear();
|
|
||||||
_est.Clear();
|
|
||||||
_rsp.Clear();
|
|
||||||
_globalEqp.Clear();
|
|
||||||
Changes = true;
|
Changes = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,15 +47,19 @@ public class ModMetaEditor(ModManager modManager)
|
||||||
if (option == currentOption)
|
if (option == currentOption)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
foreach (var manip in option.Manipulations)
|
var name = option.GetFullName();
|
||||||
{
|
OtherData[MetaManipulation.Type.Imc].Add(name, option.Manipulations.GetCount(MetaManipulation.Type.Imc));
|
||||||
var data = OtherData[manip.ManipulationType];
|
OtherData[MetaManipulation.Type.Eqp].Add(name, option.Manipulations.GetCount(MetaManipulation.Type.Eqp));
|
||||||
++data.TotalCount;
|
OtherData[MetaManipulation.Type.Eqdp].Add(name, option.Manipulations.GetCount(MetaManipulation.Type.Eqdp));
|
||||||
data.Add(option.GetFullName());
|
OtherData[MetaManipulation.Type.Gmp].Add(name, option.Manipulations.GetCount(MetaManipulation.Type.Gmp));
|
||||||
}
|
OtherData[MetaManipulation.Type.Est].Add(name, option.Manipulations.GetCount(MetaManipulation.Type.Est));
|
||||||
|
OtherData[MetaManipulation.Type.Rsp].Add(name, option.Manipulations.GetCount(MetaManipulation.Type.Rsp));
|
||||||
|
OtherData[MetaManipulation.Type.GlobalEqp].Add(name, option.Manipulations.GetCount(MetaManipulation.Type.GlobalEqp));
|
||||||
}
|
}
|
||||||
|
|
||||||
Split(currentOption.Manipulations);
|
Clear();
|
||||||
|
UnionWith(currentOption.Manipulations);
|
||||||
|
Changes = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Apply(IModDataContainer container)
|
public void Apply(IModDataContainer container)
|
||||||
|
|
@ -145,50 +67,7 @@ public class ModMetaEditor(ModManager modManager)
|
||||||
if (!Changes)
|
if (!Changes)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
modManager.OptionEditor.SetManipulations(container, [..Recombine()]);
|
modManager.OptionEditor.SetManipulations(container, this);
|
||||||
Changes = false;
|
Changes = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Split(IEnumerable<MetaManipulation> manips)
|
|
||||||
{
|
|
||||||
Clear();
|
|
||||||
foreach (var manip in manips)
|
|
||||||
{
|
|
||||||
switch (manip.ManipulationType)
|
|
||||||
{
|
|
||||||
case MetaManipulation.Type.Imc:
|
|
||||||
_imc.Add(manip.Imc);
|
|
||||||
break;
|
|
||||||
case MetaManipulation.Type.Eqdp:
|
|
||||||
_eqdp.Add(manip.Eqdp);
|
|
||||||
break;
|
|
||||||
case MetaManipulation.Type.Eqp:
|
|
||||||
_eqp.Add(manip.Eqp);
|
|
||||||
break;
|
|
||||||
case MetaManipulation.Type.Est:
|
|
||||||
_est.Add(manip.Est);
|
|
||||||
break;
|
|
||||||
case MetaManipulation.Type.Gmp:
|
|
||||||
_gmp.Add(manip.Gmp);
|
|
||||||
break;
|
|
||||||
case MetaManipulation.Type.Rsp:
|
|
||||||
_rsp.Add(manip.Rsp);
|
|
||||||
break;
|
|
||||||
case MetaManipulation.Type.GlobalEqp:
|
|
||||||
_globalEqp.Add(manip.GlobalEqp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Changes = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<MetaManipulation> Recombine()
|
|
||||||
=> _imc.Select(m => (MetaManipulation)m)
|
|
||||||
.Concat(_eqdp.Select(m => (MetaManipulation)m))
|
|
||||||
.Concat(_eqp.Select(m => (MetaManipulation)m))
|
|
||||||
.Concat(_est.Select(m => (MetaManipulation)m))
|
|
||||||
.Concat(_gmp.Select(m => (MetaManipulation)m))
|
|
||||||
.Concat(_rsp.Select(m => (MetaManipulation)m))
|
|
||||||
.Concat(_globalEqp.Select(m => (MetaManipulation)m));
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,28 +95,28 @@ public class ImcModGroup(Mod mod) : IModGroup
|
||||||
public IModGroupEditDrawer EditDrawer(ModGroupEditDrawer editDrawer)
|
public IModGroupEditDrawer EditDrawer(ModGroupEditDrawer editDrawer)
|
||||||
=> new ImcModGroupEditDrawer(editDrawer, this);
|
=> new ImcModGroupEditDrawer(editDrawer, this);
|
||||||
|
|
||||||
public ImcManipulation GetManip(ushort mask, Variant variant)
|
public ImcEntry GetEntry(ushort mask)
|
||||||
=> new(Identifier.ObjectType, Identifier.BodySlot, Identifier.PrimaryId, Identifier.SecondaryId.Id, variant.Id,
|
=> DefaultEntry with { AttributeMask = mask };
|
||||||
Identifier.EquipSlot, DefaultEntry with { AttributeMask = mask });
|
|
||||||
|
|
||||||
public void AddData(Setting setting, Dictionary<Utf8GamePath, FullPath> redirections, MetaDictionary manipulations)
|
public void AddData(Setting setting, Dictionary<Utf8GamePath, FullPath> redirections, MetaDictionary manipulations)
|
||||||
{
|
{
|
||||||
if (IsDisabled(setting))
|
if (IsDisabled(setting))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var mask = GetCurrentMask(setting);
|
var mask = GetCurrentMask(setting);
|
||||||
|
var entry = GetEntry(mask);
|
||||||
if (AllVariants)
|
if (AllVariants)
|
||||||
{
|
{
|
||||||
var count = ImcChecker.GetVariantCount(Identifier);
|
var count = ImcChecker.GetVariantCount(Identifier);
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
manipulations.Add(GetManip(mask, Identifier.Variant));
|
manipulations.TryAdd(Identifier, entry);
|
||||||
else
|
else
|
||||||
for (var i = 0; i <= count; ++i)
|
for (var i = 0; i <= count; ++i)
|
||||||
manipulations.Add(GetManip(mask, (Variant)i));
|
manipulations.TryAdd(Identifier with { Variant = (Variant)i }, entry);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
manipulations.Add(GetManip(mask, Identifier.Variant));
|
manipulations.TryAdd(Identifier, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ public class ItemSwapContainer
|
||||||
|
|
||||||
private MetaDictionary MetaResolver(ModCollection? collection)
|
private MetaDictionary MetaResolver(ModCollection? collection)
|
||||||
=> collection?.MetaCache?.Manipulations is { } cache
|
=> collection?.MetaCache?.Manipulations is { } cache
|
||||||
? [.. cache]
|
? [] // [.. cache] TODO
|
||||||
: _appliedModData.Manipulations;
|
: _appliedModData.Manipulations;
|
||||||
|
|
||||||
public EquipItem[] LoadEquipment(EquipItem from, EquipItem to, ModCollection? collection = null, bool useRightRing = true,
|
public EquipItem[] LoadEquipment(EquipItem from, EquipItem to, ModCollection? collection = null, bool useRightRing = true,
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,8 @@ public partial class ModCreator(
|
||||||
Penumbra.Log.Verbose(
|
Penumbra.Log.Verbose(
|
||||||
$"Incorporating {file} as Metadata file of {meta.MetaManipulations.Count} manipulations {deleteString}");
|
$"Incorporating {file} as Metadata file of {meta.MetaManipulations.Count} manipulations {deleteString}");
|
||||||
deleteList.Add(file.FullName);
|
deleteList.Add(file.FullName);
|
||||||
option.Manipulations.UnionWith([.. meta.MetaManipulations]);
|
// TODO
|
||||||
|
option.Manipulations.UnionWith([]);//[.. meta.MetaManipulations]);
|
||||||
}
|
}
|
||||||
else if (ext1 == ".rgsp" || ext2 == ".rgsp")
|
else if (ext1 == ".rgsp" || ext2 == ".rgsp")
|
||||||
{
|
{
|
||||||
|
|
@ -212,7 +213,8 @@ public partial class ModCreator(
|
||||||
$"Incorporating {file} as racial scaling file of {rgsp.MetaManipulations.Count} manipulations {deleteString}");
|
$"Incorporating {file} as racial scaling file of {rgsp.MetaManipulations.Count} manipulations {deleteString}");
|
||||||
deleteList.Add(file.FullName);
|
deleteList.Add(file.FullName);
|
||||||
|
|
||||||
option.Manipulations.UnionWith([.. rgsp.MetaManipulations]);
|
// TODO
|
||||||
|
option.Manipulations.UnionWith([]);//[.. rgsp.MetaManipulations]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ public static class SubMod
|
||||||
{
|
{
|
||||||
to.Files = new Dictionary<Utf8GamePath, FullPath>(from.Files);
|
to.Files = new Dictionary<Utf8GamePath, FullPath>(from.Files);
|
||||||
to.FileSwaps = new Dictionary<Utf8GamePath, FullPath>(from.FileSwaps);
|
to.FileSwaps = new Dictionary<Utf8GamePath, FullPath>(from.FileSwaps);
|
||||||
to.Manipulations = [.. from.Manipulations];
|
to.Manipulations = from.Manipulations.Clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Load all file redirections, file swaps and meta manipulations from a JToken of that option into a data container. </summary>
|
/// <summary> Load all file redirections, file swaps and meta manipulations from a JToken of that option into a data container. </summary>
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,8 @@ public class TemporaryMod : IMod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaDictionary manips = [.. collection.MetaCache?.Manipulations ?? []];
|
// TODO
|
||||||
|
MetaDictionary manips = []; // [.. collection.MetaCache?.Manipulations ?? []];
|
||||||
defaultMod.Manipulations.UnionWith(manips);
|
defaultMod.Manipulations.UnionWith(manips);
|
||||||
|
|
||||||
saveService.ImmediateSave(new ModSaveGroup(dir, defaultMod, config.ReplaceNonAsciiOnImport));
|
saveService.ImmediateSave(new ModSaveGroup(dir, defaultMod, config.ReplaceNonAsciiOnImport));
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,6 @@ public static class StaticServiceManager
|
||||||
.AddSingleton<DuplicateManager>()
|
.AddSingleton<DuplicateManager>()
|
||||||
.AddSingleton<MdlMaterialEditor>()
|
.AddSingleton<MdlMaterialEditor>()
|
||||||
.AddSingleton<ModFileEditor>()
|
.AddSingleton<ModFileEditor>()
|
||||||
.AddSingleton<ModMetaEditor>()
|
|
||||||
.AddSingleton<ModSwapEditor>()
|
.AddSingleton<ModSwapEditor>()
|
||||||
.AddSingleton<ModNormalizer>()
|
.AddSingleton<ModNormalizer>()
|
||||||
.AddSingleton<ModMerger>()
|
.AddSingleton<ModMerger>()
|
||||||
|
|
|
||||||
353
Penumbra/UI/AdvancedWindow/Meta/ImcMetaDrawer.cs
Normal file
353
Penumbra/UI/AdvancedWindow/Meta/ImcMetaDrawer.cs
Normal file
|
|
@ -0,0 +1,353 @@
|
||||||
|
using Dalamud.Interface;
|
||||||
|
using ImGuiNET;
|
||||||
|
using OtterGui.Raii;
|
||||||
|
using OtterGui.Services;
|
||||||
|
using OtterGui.Text;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
|
using Penumbra.GameData.Structs;
|
||||||
|
using Penumbra.Meta;
|
||||||
|
using Penumbra.Meta.Manipulations;
|
||||||
|
using Penumbra.Mods.Editor;
|
||||||
|
using Penumbra.UI.Classes;
|
||||||
|
|
||||||
|
namespace Penumbra.UI.AdvancedWindow.Meta;
|
||||||
|
|
||||||
|
public sealed class ImcMetaDrawer(ModEditor editor, MetaFileManager metaFiles)
|
||||||
|
: MetaDrawer<ImcIdentifier, ImcEntry>(editor, metaFiles), IService
|
||||||
|
{
|
||||||
|
private bool _fileExists;
|
||||||
|
|
||||||
|
private const string ModelSetIdTooltipShort = "Model Set ID";
|
||||||
|
private const string EquipSlotTooltip = "Equip Slot";
|
||||||
|
private const string ModelRaceTooltip = "Model Race";
|
||||||
|
private const string GenderTooltip = "Gender";
|
||||||
|
private const string ObjectTypeTooltip = "Object Type";
|
||||||
|
private const string SecondaryIdTooltip = "Secondary ID";
|
||||||
|
private const string PrimaryIdTooltipShort = "Primary ID";
|
||||||
|
private const string VariantIdTooltip = "Variant ID";
|
||||||
|
private const string EstTypeTooltip = "EST Type";
|
||||||
|
private const string RacialTribeTooltip = "Racial Tribe";
|
||||||
|
private const string ScalingTypeTooltip = "Scaling Type";
|
||||||
|
|
||||||
|
protected override void Initialize()
|
||||||
|
{
|
||||||
|
Identifier = ImcIdentifier.Default;
|
||||||
|
UpdateEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateEntry()
|
||||||
|
=> (Entry, _fileExists, _) = MetaFiles.ImcChecker.GetDefaultEntry(Identifier, true);
|
||||||
|
|
||||||
|
protected override void DrawNew()
|
||||||
|
{
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
// Copy To Clipboard
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
var canAdd = _fileExists && Editor.MetaEditor.CanAdd(Identifier);
|
||||||
|
var tt = canAdd ? "Stage this edit."u8 : !_fileExists ? "This IMC file does not exist."u8 : "This entry is already edited."u8;
|
||||||
|
if (ImUtf8.IconButton(FontAwesomeIcon.Plus, tt, disabled: !canAdd))
|
||||||
|
Editor.MetaEditor.TryAdd(Identifier, Entry);
|
||||||
|
|
||||||
|
if (DrawIdentifier(ref Identifier))
|
||||||
|
UpdateEntry();
|
||||||
|
|
||||||
|
using var disabled = ImRaii.Disabled();
|
||||||
|
DrawEntry(Entry, ref Entry, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DrawEntry(ImcIdentifier identifier, ImcEntry entry)
|
||||||
|
{
|
||||||
|
const uint frameColor = 0;
|
||||||
|
// Meta Buttons
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImUtf8.TextFramed(identifier.ObjectType.ToName(), frameColor);
|
||||||
|
ImUtf8.HoverTooltip("Object Type"u8);
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImUtf8.TextFramed($"{identifier.PrimaryId.Id}", frameColor);
|
||||||
|
ImUtf8.HoverTooltip("Primary ID");
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
if (identifier.ObjectType is ObjectType.Equipment or ObjectType.Accessory)
|
||||||
|
{
|
||||||
|
ImUtf8.TextFramed(identifier.EquipSlot.ToName(), frameColor);
|
||||||
|
ImUtf8.HoverTooltip("Equip Slot"u8);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImUtf8.TextFramed($"{identifier.SecondaryId.Id}", frameColor);
|
||||||
|
ImUtf8.HoverTooltip("Secondary ID"u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImUtf8.TextFramed($"{identifier.Variant.Id}", frameColor);
|
||||||
|
ImUtf8.HoverTooltip("Variant"u8);
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
if (identifier.ObjectType is ObjectType.DemiHuman)
|
||||||
|
{
|
||||||
|
ImUtf8.TextFramed(identifier.EquipSlot.ToName(), frameColor);
|
||||||
|
ImUtf8.HoverTooltip("Equip Slot"u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultEntry = MetaFiles.ImcChecker.GetDefaultEntry(identifier, true).Entry;
|
||||||
|
if (DrawEntry(defaultEntry, ref entry, true))
|
||||||
|
Editor.MetaEditor.Update(identifier, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool DrawIdentifier(ref ImcIdentifier identifier)
|
||||||
|
{
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
var change = DrawObjectType(ref identifier);
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
change |= DrawPrimaryId(ref identifier);
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
if (identifier.ObjectType is ObjectType.Equipment or ObjectType.Accessory)
|
||||||
|
change |= DrawSlot(ref identifier);
|
||||||
|
else
|
||||||
|
change |= DrawSecondaryId(ref identifier);
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
change |= DrawVariant(ref identifier);
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
if (identifier.ObjectType is ObjectType.DemiHuman)
|
||||||
|
change |= DrawSlot(ref identifier, 70f);
|
||||||
|
else
|
||||||
|
ImUtf8.ScaledDummy(70f);
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool DrawEntry(ImcEntry defaultEntry, ref ImcEntry entry, bool addDefault)
|
||||||
|
{
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
var change = DrawMaterialId(defaultEntry, ref entry, addDefault);
|
||||||
|
ImUtf8.SameLineInner();
|
||||||
|
change |= DrawMaterialAnimationId(defaultEntry, ref entry, addDefault);
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
change |= DrawDecalId(defaultEntry, ref entry, addDefault);
|
||||||
|
ImUtf8.SameLineInner();
|
||||||
|
change |= DrawVfxId(defaultEntry, ref entry, addDefault);
|
||||||
|
ImUtf8.SameLineInner();
|
||||||
|
change |= DrawSoundId(defaultEntry, ref entry, addDefault);
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
change |= DrawAttributes(defaultEntry, ref entry);
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected override IEnumerable<(ImcIdentifier, ImcEntry)> Enumerate()
|
||||||
|
=> Editor.MetaEditor.Imc.Select(kvp => (kvp.Key, kvp.Value));
|
||||||
|
|
||||||
|
public static bool DrawObjectType(ref ImcIdentifier identifier, float width = 110)
|
||||||
|
{
|
||||||
|
var ret = Combos.ImcType("##imcType", identifier.ObjectType, out var type, width);
|
||||||
|
ImUtf8.HoverTooltip("Object Type"u8);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
var equipSlot = type switch
|
||||||
|
{
|
||||||
|
ObjectType.Equipment => identifier.EquipSlot.IsEquipment() ? identifier.EquipSlot : EquipSlot.Head,
|
||||||
|
ObjectType.DemiHuman => identifier.EquipSlot.IsEquipment() ? identifier.EquipSlot : EquipSlot.Head,
|
||||||
|
ObjectType.Accessory => identifier.EquipSlot.IsAccessory() ? identifier.EquipSlot : EquipSlot.Ears,
|
||||||
|
_ => EquipSlot.Unknown,
|
||||||
|
};
|
||||||
|
identifier = identifier with
|
||||||
|
{
|
||||||
|
ObjectType = type,
|
||||||
|
EquipSlot = equipSlot,
|
||||||
|
SecondaryId = identifier.SecondaryId == 0 ? 1 : identifier.SecondaryId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool DrawPrimaryId(ref ImcIdentifier identifier, float unscaledWidth = 80)
|
||||||
|
{
|
||||||
|
var ret = IdInput("##imcPrimaryId"u8, unscaledWidth, identifier.PrimaryId.Id, out var newId, 0, ushort.MaxValue,
|
||||||
|
identifier.PrimaryId.Id <= 1);
|
||||||
|
ImUtf8.HoverTooltip("Primary ID - You can usually find this as the 'x####' part of an item path.\n"u8
|
||||||
|
+ "This should generally not be left <= 1 unless you explicitly want that."u8);
|
||||||
|
if (ret)
|
||||||
|
identifier = identifier with { PrimaryId = newId };
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool DrawSecondaryId(ref ImcIdentifier identifier, float unscaledWidth = 100)
|
||||||
|
{
|
||||||
|
var ret = IdInput("##imcSecondaryId"u8, unscaledWidth, identifier.SecondaryId.Id, out var newId, 0, ushort.MaxValue, false);
|
||||||
|
ImUtf8.HoverTooltip("Secondary ID"u8);
|
||||||
|
if (ret)
|
||||||
|
identifier = identifier with { SecondaryId = newId };
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool DrawVariant(ref ImcIdentifier identifier, float unscaledWidth = 45)
|
||||||
|
{
|
||||||
|
var ret = IdInput("##imcVariant"u8, unscaledWidth, identifier.Variant.Id, out var newId, 0, byte.MaxValue, false);
|
||||||
|
ImUtf8.HoverTooltip("Variant ID"u8);
|
||||||
|
if (ret)
|
||||||
|
identifier = identifier with { Variant = (byte)newId };
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool DrawSlot(ref ImcIdentifier identifier, float unscaledWidth = 100)
|
||||||
|
{
|
||||||
|
bool ret;
|
||||||
|
EquipSlot slot;
|
||||||
|
switch (identifier.ObjectType)
|
||||||
|
{
|
||||||
|
case ObjectType.Equipment:
|
||||||
|
case ObjectType.DemiHuman:
|
||||||
|
ret = Combos.EqpEquipSlot("##slot", identifier.EquipSlot, out slot, unscaledWidth);
|
||||||
|
break;
|
||||||
|
case ObjectType.Accessory:
|
||||||
|
ret = Combos.AccessorySlot("##slot", identifier.EquipSlot, out slot, unscaledWidth);
|
||||||
|
break;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImUtf8.HoverTooltip("Equip Slot"u8);
|
||||||
|
if (ret)
|
||||||
|
identifier = identifier with { EquipSlot = slot };
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool DrawMaterialId(ImcEntry defaultEntry, ref ImcEntry entry, bool addDefault, float unscaledWidth = 45)
|
||||||
|
{
|
||||||
|
if (!DragInput("##materialId"u8, "Material ID"u8, unscaledWidth * ImUtf8.GlobalScale, entry.MaterialId, defaultEntry.MaterialId,
|
||||||
|
out var newValue, (byte)1, byte.MaxValue, 0.01f, addDefault))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
entry = entry with { MaterialId = newValue };
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool DrawMaterialAnimationId(ImcEntry defaultEntry, ref ImcEntry entry, bool addDefault, float unscaledWidth = 45)
|
||||||
|
{
|
||||||
|
if (!DragInput("##mAnimId"u8, "Material Animation ID"u8, unscaledWidth * ImUtf8.GlobalScale, entry.MaterialAnimationId,
|
||||||
|
defaultEntry.MaterialAnimationId, out var newValue, (byte)0, byte.MaxValue, 0.01f, addDefault))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
entry = entry with { MaterialAnimationId = newValue };
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool DrawDecalId(ImcEntry defaultEntry, ref ImcEntry entry, bool addDefault, float unscaledWidth = 45)
|
||||||
|
{
|
||||||
|
if (!DragInput("##decalId"u8, "Decal ID"u8, unscaledWidth * ImUtf8.GlobalScale, entry.DecalId, defaultEntry.DecalId, out var newValue,
|
||||||
|
(byte)0, byte.MaxValue, 0.01f, addDefault))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
entry = entry with { DecalId = newValue };
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool DrawVfxId(ImcEntry defaultEntry, ref ImcEntry entry, bool addDefault, float unscaledWidth = 45)
|
||||||
|
{
|
||||||
|
if (!DragInput("##vfxId"u8, "VFX ID"u8, unscaledWidth * ImUtf8.GlobalScale, entry.VfxId, defaultEntry.VfxId, out var newValue, (byte)0,
|
||||||
|
byte.MaxValue, 0.01f, addDefault))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
entry = entry with { VfxId = newValue };
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool DrawSoundId(ImcEntry defaultEntry, ref ImcEntry entry, bool addDefault, float unscaledWidth = 45)
|
||||||
|
{
|
||||||
|
if (!DragInput("##soundId"u8, "Sound ID"u8, unscaledWidth * ImUtf8.GlobalScale, entry.SoundId, defaultEntry.SoundId, out var newValue,
|
||||||
|
(byte)0, byte.MaxValue, 0.01f, addDefault))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
entry = entry with { SoundId = newValue };
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool DrawAttributes(ImcEntry defaultEntry, ref ImcEntry entry)
|
||||||
|
{
|
||||||
|
var changes = false;
|
||||||
|
for (var i = 0; i < ImcEntry.NumAttributes; ++i)
|
||||||
|
{
|
||||||
|
using var id = ImRaii.PushId(i);
|
||||||
|
var flag = 1 << i;
|
||||||
|
var value = (entry.AttributeMask & flag) != 0;
|
||||||
|
var def = (defaultEntry.AttributeMask & flag) != 0;
|
||||||
|
if (Checkmark("##attribute"u8, "ABCDEFGHIJ"u8.Slice(i, 1), value, def, out var newValue))
|
||||||
|
{
|
||||||
|
var newMask = (ushort)(newValue ? entry.AttributeMask | flag : entry.AttributeMask & ~flag);
|
||||||
|
entry = entry with { AttributeMask = newMask };
|
||||||
|
changes = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < ImcEntry.NumAttributes - 1)
|
||||||
|
ImUtf8.SameLineInner();
|
||||||
|
}
|
||||||
|
|
||||||
|
return changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A number input for ids with an optional max id of given width.
|
||||||
|
/// Returns true if newId changed against currentId.
|
||||||
|
/// </summary>
|
||||||
|
private static bool IdInput(ReadOnlySpan<byte> label, float unscaledWidth, ushort currentId, out ushort newId, int minId, int maxId,
|
||||||
|
bool border)
|
||||||
|
{
|
||||||
|
int tmp = currentId;
|
||||||
|
ImGui.SetNextItemWidth(unscaledWidth * ImUtf8.GlobalScale);
|
||||||
|
using var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, UiHelpers.Scale, border);
|
||||||
|
using var color = ImRaii.PushColor(ImGuiCol.Border, Colors.RegexWarningBorder, border);
|
||||||
|
if (ImUtf8.InputScalar(label, ref tmp))
|
||||||
|
tmp = Math.Clamp(tmp, minId, maxId);
|
||||||
|
|
||||||
|
newId = (ushort)tmp;
|
||||||
|
return newId != currentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A dragging int input of given width that compares against a default value, shows a tooltip and clamps against min and max.
|
||||||
|
/// Returns true if newValue changed against currentValue.
|
||||||
|
/// </summary>
|
||||||
|
private static bool DragInput<T>(ReadOnlySpan<byte> label, ReadOnlySpan<byte> tooltip, float width, T currentValue, T defaultValue,
|
||||||
|
out T newValue, T minValue, T maxValue, float speed, bool addDefault) where T : unmanaged, INumber<T>
|
||||||
|
{
|
||||||
|
newValue = currentValue;
|
||||||
|
using var color = ImRaii.PushColor(ImGuiCol.FrameBg,
|
||||||
|
defaultValue > currentValue ? ColorId.DecreasedMetaValue.Value() : ColorId.IncreasedMetaValue.Value(),
|
||||||
|
defaultValue != currentValue);
|
||||||
|
ImGui.SetNextItemWidth(width);
|
||||||
|
if (ImUtf8.DragScalar(label, ref newValue, minValue, maxValue, speed))
|
||||||
|
newValue = newValue <= minValue ? minValue : newValue >= maxValue ? maxValue : newValue;
|
||||||
|
|
||||||
|
if (addDefault)
|
||||||
|
ImUtf8.HoverTooltip($"{tooltip}\nDefault Value: {defaultValue}");
|
||||||
|
else
|
||||||
|
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, tooltip);
|
||||||
|
|
||||||
|
return newValue != currentValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A checkmark that compares against a default value and shows a tooltip.
|
||||||
|
/// Returns true if newValue is changed against currentValue.
|
||||||
|
/// </summary>
|
||||||
|
private static bool Checkmark(ReadOnlySpan<byte> label, ReadOnlySpan<byte> tooltip, bool currentValue, bool defaultValue,
|
||||||
|
out bool newValue)
|
||||||
|
{
|
||||||
|
using var color = ImRaii.PushColor(ImGuiCol.FrameBg,
|
||||||
|
defaultValue ? ColorId.DecreasedMetaValue.Value() : ColorId.IncreasedMetaValue.Value(),
|
||||||
|
defaultValue != currentValue);
|
||||||
|
newValue = currentValue;
|
||||||
|
ImUtf8.Checkbox(label, ref newValue);
|
||||||
|
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, tooltip);
|
||||||
|
return newValue != currentValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
|
using System.Reflection.Emit;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
using OtterGui.Raii;
|
using OtterGui.Raii;
|
||||||
using OtterGui.Text;
|
using OtterGui.Text;
|
||||||
|
using OtterGui.Text.EndObjects;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
|
||||||
using Penumbra.Interop.Structs;
|
using Penumbra.Interop.Structs;
|
||||||
using Penumbra.Meta;
|
using Penumbra.Meta;
|
||||||
using Penumbra.Meta.Files;
|
using Penumbra.Meta.Files;
|
||||||
|
|
@ -20,17 +21,7 @@ public partial class ModEditWindow
|
||||||
private const string ModelSetIdTooltip =
|
private const string ModelSetIdTooltip =
|
||||||
"Model Set ID - You can usually find this as the 'e####' part of an item path.\nThis should generally not be left <= 1 unless you explicitly want that.";
|
"Model Set ID - You can usually find this as the 'e####' part of an item path.\nThis should generally not be left <= 1 unless you explicitly want that.";
|
||||||
|
|
||||||
private const string ModelSetIdTooltipShort = "Model Set ID";
|
|
||||||
private const string EquipSlotTooltip = "Equip Slot";
|
|
||||||
private const string ModelRaceTooltip = "Model Race";
|
|
||||||
private const string GenderTooltip = "Gender";
|
|
||||||
private const string ObjectTypeTooltip = "Object Type";
|
|
||||||
private const string SecondaryIdTooltip = "Secondary ID";
|
|
||||||
private const string PrimaryIdTooltipShort = "Primary ID";
|
|
||||||
private const string VariantIdTooltip = "Variant ID";
|
|
||||||
private const string EstTypeTooltip = "EST Type";
|
|
||||||
private const string RacialTribeTooltip = "Racial Tribe";
|
|
||||||
private const string ScalingTypeTooltip = "Scaling Type";
|
|
||||||
|
|
||||||
private void DrawMetaTab()
|
private void DrawMetaTab()
|
||||||
{
|
{
|
||||||
|
|
@ -56,7 +47,7 @@ public partial class ModEditWindow
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
SetFromClipboardButton();
|
SetFromClipboardButton();
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
CopyToClipboardButton("Copy all current manipulations to clipboard.", _iconSize, _editor.MetaEditor.Recombine());
|
CopyToClipboardButton("Copy all current manipulations to clipboard.", _iconSize, _editor.MetaEditor);
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
if (ImGui.Button("Write as TexTools Files"))
|
if (ImGui.Button("Write as TexTools Files"))
|
||||||
_metaFileManager.WriteAllTexToolsMeta(Mod!);
|
_metaFileManager.WriteAllTexToolsMeta(Mod!);
|
||||||
|
|
@ -65,71 +56,103 @@ public partial class ModEditWindow
|
||||||
if (!child)
|
if (!child)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DrawEditHeader(_editor.MetaEditor.Eqp, "Equipment Parameter Edits (EQP)###EQP", 5, EqpRow.Draw, EqpRow.DrawNew,
|
DrawEditHeader(MetaManipulation.Type.Eqp);
|
||||||
_editor.MetaEditor.OtherData[MetaManipulation.Type.Eqp]);
|
DrawEditHeader(MetaManipulation.Type.Eqdp);
|
||||||
DrawEditHeader(_editor.MetaEditor.Eqdp, "Racial Model Edits (EQDP)###EQDP", 7, EqdpRow.Draw, EqdpRow.DrawNew,
|
DrawEditHeader(MetaManipulation.Type.Imc);
|
||||||
_editor.MetaEditor.OtherData[MetaManipulation.Type.Eqdp]);
|
DrawEditHeader(MetaManipulation.Type.Est);
|
||||||
DrawEditHeader(_editor.MetaEditor.Imc, "Variant Edits (IMC)###IMC", 10, ImcRow.Draw, ImcRow.DrawNew,
|
DrawEditHeader(MetaManipulation.Type.Gmp);
|
||||||
_editor.MetaEditor.OtherData[MetaManipulation.Type.Imc]);
|
DrawEditHeader(MetaManipulation.Type.Rsp);
|
||||||
DrawEditHeader(_editor.MetaEditor.Est, "Extra Skeleton Parameters (EST)###EST", 7, EstRow.Draw, EstRow.DrawNew,
|
DrawEditHeader(MetaManipulation.Type.GlobalEqp);
|
||||||
_editor.MetaEditor.OtherData[MetaManipulation.Type.Est]);
|
|
||||||
DrawEditHeader(_editor.MetaEditor.Gmp, "Visor/Gimmick Edits (GMP)###GMP", 7, GmpRow.Draw, GmpRow.DrawNew,
|
|
||||||
_editor.MetaEditor.OtherData[MetaManipulation.Type.Gmp]);
|
|
||||||
DrawEditHeader(_editor.MetaEditor.Rsp, "Racial Scaling Edits (RSP)###RSP", 5, RspRow.Draw, RspRow.DrawNew,
|
|
||||||
_editor.MetaEditor.OtherData[MetaManipulation.Type.Rsp]);
|
|
||||||
DrawEditHeader(_editor.MetaEditor.GlobalEqp, "Global Equipment Parameter Edits (Global EQP)###GEQP", 4, GlobalEqpRow.Draw,
|
|
||||||
GlobalEqpRow.DrawNew, _editor.MetaEditor.OtherData[MetaManipulation.Type.GlobalEqp]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ReadOnlySpan<byte> Label(MetaManipulation.Type type)
|
||||||
/// <summary> The headers for the different meta changes all have basically the same structure for different types.</summary>
|
=> type switch
|
||||||
private void DrawEditHeader<T>(IReadOnlyCollection<T> items, string label, int numColumns,
|
|
||||||
Action<MetaFileManager, T, ModEditor, Vector2> draw, Action<MetaFileManager, ModEditor, Vector2> drawNew,
|
|
||||||
ModMetaEditor.OtherOptionData otherOptionData)
|
|
||||||
{
|
|
||||||
const ImGuiTableFlags flags = ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.BordersInnerV;
|
|
||||||
|
|
||||||
var oldPos = ImGui.GetCursorPosY();
|
|
||||||
var header = ImGui.CollapsingHeader($"{items.Count} {label}");
|
|
||||||
var newPos = ImGui.GetCursorPos();
|
|
||||||
if (otherOptionData.TotalCount > 0)
|
|
||||||
{
|
{
|
||||||
var text = $"{otherOptionData.TotalCount} Edits in other Options";
|
MetaManipulation.Type.Imc => "Variant Edits (IMC)###IMC"u8,
|
||||||
var size = ImGui.CalcTextSize(text).X;
|
MetaManipulation.Type.Eqdp => "Racial Model Edits (EQDP)###EQDP"u8,
|
||||||
ImGui.SetCursorPos(new Vector2(ImGui.GetContentRegionAvail().X - size, oldPos + ImGui.GetStyle().FramePadding.Y));
|
MetaManipulation.Type.Eqp => "Equipment Parameter Edits (EQP)###EQP"u8,
|
||||||
ImGuiUtil.TextColored(ColorId.RedundantAssignment.Value() | 0xFF000000, text);
|
MetaManipulation.Type.Est => "Extra Skeleton Parameters (EST)###EST"u8,
|
||||||
if (ImGui.IsItemHovered())
|
MetaManipulation.Type.Gmp => "Visor/Gimmick Edits (GMP)###GMP"u8,
|
||||||
{
|
MetaManipulation.Type.Rsp => "Racial Scaling Edits (RSP)###RSP"u8,
|
||||||
using var tt = ImUtf8.Tooltip();
|
MetaManipulation.Type.GlobalEqp => "Global Equipment Parameter Edits (Global EQP)###GEQP"u8,
|
||||||
foreach (var name in otherOptionData)
|
_ => "\0"u8,
|
||||||
ImUtf8.Text(name);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.SetCursorPos(newPos);
|
private static int ColumnCount(MetaManipulation.Type type)
|
||||||
}
|
=> type switch
|
||||||
|
{
|
||||||
|
MetaManipulation.Type.Imc => 10,
|
||||||
|
MetaManipulation.Type.Eqdp => 7,
|
||||||
|
MetaManipulation.Type.Eqp => 5,
|
||||||
|
MetaManipulation.Type.Est => 7,
|
||||||
|
MetaManipulation.Type.Gmp => 7,
|
||||||
|
MetaManipulation.Type.Rsp => 5,
|
||||||
|
MetaManipulation.Type.GlobalEqp => 4,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
private void DrawEditHeader(MetaManipulation.Type type)
|
||||||
|
{
|
||||||
|
var oldPos = ImGui.GetCursorPosY();
|
||||||
|
var header = ImUtf8.CollapsingHeader($"{_editor.MetaEditor.GetCount(type)} {Label(type)}");
|
||||||
|
DrawOtherOptionData(type, oldPos, ImGui.GetCursorPos());
|
||||||
if (!header)
|
if (!header)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using (var table = ImRaii.Table(label, numColumns, flags))
|
DrawTable(type);
|
||||||
{
|
}
|
||||||
if (table)
|
|
||||||
{
|
|
||||||
drawNew(_metaFileManager, _editor, _iconSize);
|
|
||||||
foreach (var (item, index) in items.ToArray().WithIndex())
|
|
||||||
{
|
|
||||||
using var id = ImRaii.PushId(index);
|
|
||||||
draw(_metaFileManager, item, _editor, _iconSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private IMetaDrawer? Drawer(MetaManipulation.Type type)
|
||||||
|
=> type switch
|
||||||
|
{
|
||||||
|
//MetaManipulation.Type.Imc => expr,
|
||||||
|
//MetaManipulation.Type.Eqdp => expr,
|
||||||
|
//MetaManipulation.Type.Eqp => expr,
|
||||||
|
//MetaManipulation.Type.Est => expr,
|
||||||
|
//MetaManipulation.Type.Gmp => expr,
|
||||||
|
//MetaManipulation.Type.Rsp => expr,
|
||||||
|
//MetaManipulation.Type.GlobalEqp => expr,
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
|
|
||||||
|
private void DrawTable(MetaManipulation.Type type)
|
||||||
|
{
|
||||||
|
const ImGuiTableFlags flags = ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.BordersInnerV;
|
||||||
|
using var table = ImUtf8.Table(Label(type), ColumnCount(type), flags);
|
||||||
|
if (!table)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Drawer(type) is not { } drawer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
drawer.Draw();
|
||||||
ImGui.NewLine();
|
ImGui.NewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DrawOtherOptionData(MetaManipulation.Type type, float oldPos, Vector2 newPos)
|
||||||
|
{
|
||||||
|
var otherOptionData = _editor.MetaEditor.OtherData[type];
|
||||||
|
if (otherOptionData.TotalCount <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var text = $"{otherOptionData.TotalCount} Edits in other Options";
|
||||||
|
var size = ImGui.CalcTextSize(text).X;
|
||||||
|
ImGui.SetCursorPos(new Vector2(ImGui.GetContentRegionAvail().X - size, oldPos + ImGui.GetStyle().FramePadding.Y));
|
||||||
|
ImGuiUtil.TextColored(ColorId.RedundantAssignment.Value() | 0xFF000000, text);
|
||||||
|
if (ImGui.IsItemHovered())
|
||||||
|
{
|
||||||
|
using var tt = ImUtf8.Tooltip();
|
||||||
|
foreach (var name in otherOptionData)
|
||||||
|
ImUtf8.Text(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SetCursorPos(newPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if false
|
||||||
private static class EqpRow
|
private static class EqpRow
|
||||||
{
|
{
|
||||||
private static EqpManipulation _new = new(Eqp.DefaultEntry, EquipSlot.Head, 1);
|
private static EqpIdentifier _newIdentifier = new(1, EquipSlot.Body);
|
||||||
|
|
||||||
private static float IdWidth
|
private static float IdWidth
|
||||||
=> 100 * UiHelpers.Scale;
|
=> 100 * UiHelpers.Scale;
|
||||||
|
|
@ -140,8 +163,8 @@ public partial class ModEditWindow
|
||||||
CopyToClipboardButton("Copy all current EQP manipulations to clipboard.", iconSize,
|
CopyToClipboardButton("Copy all current EQP manipulations to clipboard.", iconSize,
|
||||||
editor.MetaEditor.Eqp.Select(m => (MetaManipulation)m));
|
editor.MetaEditor.Eqp.Select(m => (MetaManipulation)m));
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
var canAdd = editor.MetaEditor.CanAdd(_new);
|
var canAdd = editor.MetaEditor.CanAdd(_new);
|
||||||
var tt = canAdd ? "Stage this edit." : "This entry is already edited.";
|
var tt = canAdd ? "Stage this edit." : "This entry is already edited.";
|
||||||
var defaultEntry = ExpandedEqpFile.GetDefault(metaFileManager, _new.SetId);
|
var defaultEntry = ExpandedEqpFile.GetDefault(metaFileManager, _new.SetId);
|
||||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), iconSize, tt, !canAdd, true))
|
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), iconSize, tt, !canAdd, true))
|
||||||
editor.MetaEditor.Add(_new.Copy(defaultEntry));
|
editor.MetaEditor.Add(_new.Copy(defaultEntry));
|
||||||
|
|
@ -197,7 +220,7 @@ public partial class ModEditWindow
|
||||||
var idx = 0;
|
var idx = 0;
|
||||||
foreach (var flag in Eqp.EqpAttributes[meta.Slot])
|
foreach (var flag in Eqp.EqpAttributes[meta.Slot])
|
||||||
{
|
{
|
||||||
using var id = ImRaii.PushId(idx++);
|
using var id = ImRaii.PushId(idx++);
|
||||||
var defaultValue = defaultEntry.HasFlag(flag);
|
var defaultValue = defaultEntry.HasFlag(flag);
|
||||||
var currentValue = meta.Entry.HasFlag(flag);
|
var currentValue = meta.Entry.HasFlag(flag);
|
||||||
if (Checkmark("##eqp", flag.ToLocalName(), currentValue, defaultValue, out var value))
|
if (Checkmark("##eqp", flag.ToLocalName(), currentValue, defaultValue, out var value))
|
||||||
|
|
@ -209,8 +232,6 @@ public partial class ModEditWindow
|
||||||
ImGui.NewLine();
|
ImGui.NewLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class EqdpRow
|
private static class EqdpRow
|
||||||
{
|
{
|
||||||
private static EqdpManipulation _new = new(EqdpEntry.Invalid, EquipSlot.Head, Gender.Male, ModelRace.Midlander, 1);
|
private static EqdpManipulation _new = new(EqdpEntry.Invalid, EquipSlot.Head, Gender.Male, ModelRace.Midlander, 1);
|
||||||
|
|
@ -224,9 +245,9 @@ public partial class ModEditWindow
|
||||||
CopyToClipboardButton("Copy all current EQDP manipulations to clipboard.", iconSize,
|
CopyToClipboardButton("Copy all current EQDP manipulations to clipboard.", iconSize,
|
||||||
editor.MetaEditor.Eqdp.Select(m => (MetaManipulation)m));
|
editor.MetaEditor.Eqdp.Select(m => (MetaManipulation)m));
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
var raceCode = Names.CombinedRace(_new.Gender, _new.Race);
|
var raceCode = Names.CombinedRace(_new.Gender, _new.Race);
|
||||||
var validRaceCode = CharacterUtilityData.EqdpIdx(raceCode, false) >= 0;
|
var validRaceCode = CharacterUtilityData.EqdpIdx(raceCode, false) >= 0;
|
||||||
var canAdd = validRaceCode && editor.MetaEditor.CanAdd(_new);
|
var canAdd = validRaceCode && editor.MetaEditor.CanAdd(_new);
|
||||||
var tt = canAdd ? "Stage this edit." :
|
var tt = canAdd ? "Stage this edit." :
|
||||||
validRaceCode ? "This entry is already edited." : "This combination of race and gender can not be used.";
|
validRaceCode ? "This entry is already edited." : "This combination of race and gender can not be used.";
|
||||||
var defaultEntry = validRaceCode
|
var defaultEntry = validRaceCode
|
||||||
|
|
@ -311,7 +332,7 @@ public partial class ModEditWindow
|
||||||
var defaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(meta.Gender, meta.Race), meta.Slot.IsAccessory(),
|
var defaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(meta.Gender, meta.Race), meta.Slot.IsAccessory(),
|
||||||
meta.SetId);
|
meta.SetId);
|
||||||
var (defaultBit1, defaultBit2) = defaultEntry.ToBits(meta.Slot);
|
var (defaultBit1, defaultBit2) = defaultEntry.ToBits(meta.Slot);
|
||||||
var (bit1, bit2) = meta.Entry.ToBits(meta.Slot);
|
var (bit1, bit2) = meta.Entry.ToBits(meta.Slot);
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
if (Checkmark("Material##eqdpCheck1", string.Empty, bit1, defaultBit1, out var newBit1))
|
if (Checkmark("Material##eqdpCheck1", string.Empty, bit1, defaultBit1, out var newBit1))
|
||||||
editor.MetaEditor.Change(meta.Copy(Eqdp.FromSlotAndBits(meta.Slot, newBit1, bit2)));
|
editor.MetaEditor.Change(meta.Copy(Eqdp.FromSlotAndBits(meta.Slot, newBit1, bit2)));
|
||||||
|
|
@ -321,136 +342,7 @@ public partial class ModEditWindow
|
||||||
editor.MetaEditor.Change(meta.Copy(Eqdp.FromSlotAndBits(meta.Slot, bit1, newBit2)));
|
editor.MetaEditor.Change(meta.Copy(Eqdp.FromSlotAndBits(meta.Slot, bit1, newBit2)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ImcRow
|
|
||||||
{
|
|
||||||
private static ImcIdentifier _newIdentifier = ImcIdentifier.Default;
|
|
||||||
|
|
||||||
private static float IdWidth
|
|
||||||
=> 80 * UiHelpers.Scale;
|
|
||||||
|
|
||||||
private static float SmallIdWidth
|
|
||||||
=> 45 * UiHelpers.Scale;
|
|
||||||
|
|
||||||
public static void DrawNew(MetaFileManager metaFileManager, ModEditor editor, Vector2 iconSize)
|
|
||||||
{
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
CopyToClipboardButton("Copy all current IMC manipulations to clipboard.", iconSize,
|
|
||||||
editor.MetaEditor.Imc.Select(m => (MetaManipulation)m));
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
var (defaultEntry, fileExists, _) = metaFileManager.ImcChecker.GetDefaultEntry(_newIdentifier, true);
|
|
||||||
var manip = (MetaManipulation)new ImcManipulation(_newIdentifier, defaultEntry);
|
|
||||||
var canAdd = fileExists && editor.MetaEditor.CanAdd(manip);
|
|
||||||
var tt = canAdd ? "Stage this edit." : !fileExists ? "This IMC file does not exist." : "This entry is already edited.";
|
|
||||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), iconSize, tt, !canAdd, true))
|
|
||||||
editor.MetaEditor.Add(manip);
|
|
||||||
|
|
||||||
// Identifier
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
var change = ImcManipulationDrawer.DrawObjectType(ref _newIdentifier);
|
|
||||||
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
change |= ImcManipulationDrawer.DrawPrimaryId(ref _newIdentifier);
|
|
||||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing,
|
|
||||||
new Vector2(3 * UiHelpers.Scale, ImGui.GetStyle().ItemSpacing.Y));
|
|
||||||
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
// Equipment and accessories are slightly different imcs than other types.
|
|
||||||
if (_newIdentifier.ObjectType is ObjectType.Equipment or ObjectType.Accessory)
|
|
||||||
change |= ImcManipulationDrawer.DrawSlot(ref _newIdentifier);
|
|
||||||
else
|
|
||||||
change |= ImcManipulationDrawer.DrawSecondaryId(ref _newIdentifier);
|
|
||||||
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
change |= ImcManipulationDrawer.DrawVariant(ref _newIdentifier);
|
|
||||||
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
if (_newIdentifier.ObjectType is ObjectType.DemiHuman)
|
|
||||||
change |= ImcManipulationDrawer.DrawSlot(ref _newIdentifier, 70);
|
|
||||||
else
|
|
||||||
ImGui.Dummy(new Vector2(70 * UiHelpers.Scale, 0));
|
|
||||||
|
|
||||||
if (change)
|
|
||||||
defaultEntry = metaFileManager.ImcChecker.GetDefaultEntry(_newIdentifier, true).Entry;
|
|
||||||
// Values
|
|
||||||
using var disabled = ImRaii.Disabled();
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImcManipulationDrawer.DrawMaterialId(defaultEntry, ref defaultEntry, false);
|
|
||||||
ImGui.SameLine();
|
|
||||||
ImcManipulationDrawer.DrawMaterialAnimationId(defaultEntry, ref defaultEntry, false);
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImcManipulationDrawer.DrawDecalId(defaultEntry, ref defaultEntry, false);
|
|
||||||
ImGui.SameLine();
|
|
||||||
ImcManipulationDrawer.DrawVfxId(defaultEntry, ref defaultEntry, false);
|
|
||||||
ImGui.SameLine();
|
|
||||||
ImcManipulationDrawer.DrawSoundId(defaultEntry, ref defaultEntry, false);
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImcManipulationDrawer.DrawAttributes(defaultEntry, ref defaultEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Draw(MetaFileManager metaFileManager, ImcManipulation meta, ModEditor editor, Vector2 iconSize)
|
|
||||||
{
|
|
||||||
DrawMetaButtons(meta, editor, iconSize);
|
|
||||||
|
|
||||||
// Identifier
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + ImGui.GetStyle().FramePadding.X);
|
|
||||||
ImGui.TextUnformatted(meta.ObjectType.ToName());
|
|
||||||
ImGuiUtil.HoverTooltip(ObjectTypeTooltip);
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + ImGui.GetStyle().FramePadding.X);
|
|
||||||
ImGui.TextUnformatted(meta.PrimaryId.ToString());
|
|
||||||
ImGuiUtil.HoverTooltip(PrimaryIdTooltipShort);
|
|
||||||
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + ImGui.GetStyle().FramePadding.X);
|
|
||||||
if (meta.ObjectType is ObjectType.Equipment or ObjectType.Accessory)
|
|
||||||
{
|
|
||||||
ImGui.TextUnformatted(meta.EquipSlot.ToName());
|
|
||||||
ImGuiUtil.HoverTooltip(EquipSlotTooltip);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ImGui.TextUnformatted(meta.SecondaryId.ToString());
|
|
||||||
ImGuiUtil.HoverTooltip(SecondaryIdTooltip);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + ImGui.GetStyle().FramePadding.X);
|
|
||||||
ImGui.TextUnformatted(meta.Variant.ToString());
|
|
||||||
ImGuiUtil.HoverTooltip(VariantIdTooltip);
|
|
||||||
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + ImGui.GetStyle().FramePadding.X);
|
|
||||||
if (meta.ObjectType is ObjectType.DemiHuman)
|
|
||||||
{
|
|
||||||
ImGui.TextUnformatted(meta.EquipSlot.ToName());
|
|
||||||
ImGuiUtil.HoverTooltip(EquipSlotTooltip);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Values
|
|
||||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing,
|
|
||||||
new Vector2(3 * UiHelpers.Scale, ImGui.GetStyle().ItemSpacing.Y));
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
var defaultEntry = metaFileManager.ImcChecker.GetDefaultEntry(meta.Identifier, true).Entry;
|
|
||||||
var newEntry = meta.Entry;
|
|
||||||
var changes = ImcManipulationDrawer.DrawMaterialId(defaultEntry, ref newEntry, true);
|
|
||||||
ImGui.SameLine();
|
|
||||||
changes |= ImcManipulationDrawer.DrawMaterialAnimationId(defaultEntry, ref newEntry, true);
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
changes |= ImcManipulationDrawer.DrawDecalId(defaultEntry, ref newEntry, true);
|
|
||||||
ImGui.SameLine();
|
|
||||||
changes |= ImcManipulationDrawer.DrawVfxId(defaultEntry, ref newEntry, true);
|
|
||||||
ImGui.SameLine();
|
|
||||||
changes |= ImcManipulationDrawer.DrawSoundId(defaultEntry, ref newEntry, true);
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
changes |= ImcManipulationDrawer.DrawAttributes(defaultEntry, ref newEntry);
|
|
||||||
|
|
||||||
if (changes)
|
|
||||||
editor.MetaEditor.Change(meta.Copy(newEntry));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class EstRow
|
private static class EstRow
|
||||||
{
|
{
|
||||||
private static EstManipulation _new = new(Gender.Male, ModelRace.Midlander, EstType.Body, 1, EstEntry.Zero);
|
private static EstManipulation _new = new(Gender.Male, ModelRace.Midlander, EstType.Body, 1, EstEntry.Zero);
|
||||||
|
|
@ -464,8 +356,8 @@ public partial class ModEditWindow
|
||||||
CopyToClipboardButton("Copy all current EST manipulations to clipboard.", iconSize,
|
CopyToClipboardButton("Copy all current EST manipulations to clipboard.", iconSize,
|
||||||
editor.MetaEditor.Est.Select(m => (MetaManipulation)m));
|
editor.MetaEditor.Est.Select(m => (MetaManipulation)m));
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
var canAdd = editor.MetaEditor.CanAdd(_new);
|
var canAdd = editor.MetaEditor.CanAdd(_new);
|
||||||
var tt = canAdd ? "Stage this edit." : "This entry is already edited.";
|
var tt = canAdd ? "Stage this edit." : "This entry is already edited.";
|
||||||
var defaultEntry = EstFile.GetDefault(metaFileManager, _new.Slot, Names.CombinedRace(_new.Gender, _new.Race), _new.SetId);
|
var defaultEntry = EstFile.GetDefault(metaFileManager, _new.Slot, Names.CombinedRace(_new.Gender, _new.Race), _new.SetId);
|
||||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), iconSize, tt, !canAdd, true))
|
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), iconSize, tt, !canAdd, true))
|
||||||
editor.MetaEditor.Add(_new.Copy(defaultEntry));
|
editor.MetaEditor.Add(_new.Copy(defaultEntry));
|
||||||
|
|
@ -538,12 +430,11 @@ public partial class ModEditWindow
|
||||||
// Values
|
// Values
|
||||||
var defaultEntry = EstFile.GetDefault(metaFileManager, meta.Slot, Names.CombinedRace(meta.Gender, meta.Race), meta.SetId);
|
var defaultEntry = EstFile.GetDefault(metaFileManager, meta.Slot, Names.CombinedRace(meta.Gender, meta.Race), meta.SetId);
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
if (IntDragInput("##estSkeleton", $"Skeleton Index\nDefault Value: {defaultEntry}", IdWidth, meta.Entry.Value, defaultEntry.Value,
|
if (IntDragInput("##estSkeleton", $"Skeleton Index\nDefault Value: {defaultEntry}", IdWidth, meta.Entry.Value, defaultEntry.Value,
|
||||||
out var entry, 0, ushort.MaxValue, 0.05f))
|
out var entry, 0, ushort.MaxValue, 0.05f))
|
||||||
editor.MetaEditor.Change(meta.Copy(new EstEntry((ushort)entry)));
|
editor.MetaEditor.Change(meta.Copy(new EstEntry((ushort)entry)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class GmpRow
|
private static class GmpRow
|
||||||
{
|
{
|
||||||
private static GmpManipulation _new = new(GmpEntry.Default, 1);
|
private static GmpManipulation _new = new(GmpEntry.Default, 1);
|
||||||
|
|
@ -563,8 +454,8 @@ public partial class ModEditWindow
|
||||||
CopyToClipboardButton("Copy all current GMP manipulations to clipboard.", iconSize,
|
CopyToClipboardButton("Copy all current GMP manipulations to clipboard.", iconSize,
|
||||||
editor.MetaEditor.Gmp.Select(m => (MetaManipulation)m));
|
editor.MetaEditor.Gmp.Select(m => (MetaManipulation)m));
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
var canAdd = editor.MetaEditor.CanAdd(_new);
|
var canAdd = editor.MetaEditor.CanAdd(_new);
|
||||||
var tt = canAdd ? "Stage this edit." : "This entry is already edited.";
|
var tt = canAdd ? "Stage this edit." : "This entry is already edited.";
|
||||||
var defaultEntry = ExpandedGmpFile.GetDefault(metaFileManager, _new.SetId);
|
var defaultEntry = ExpandedGmpFile.GetDefault(metaFileManager, _new.SetId);
|
||||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), iconSize, tt, !canAdd, true))
|
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), iconSize, tt, !canAdd, true))
|
||||||
editor.MetaEditor.Add(_new.Copy(defaultEntry));
|
editor.MetaEditor.Add(_new.Copy(defaultEntry));
|
||||||
|
|
@ -643,7 +534,6 @@ public partial class ModEditWindow
|
||||||
editor.MetaEditor.Change(meta.Copy(meta.Entry with { UnknownB = (byte)unkB }));
|
editor.MetaEditor.Change(meta.Copy(meta.Entry with { UnknownB = (byte)unkB }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class RspRow
|
private static class RspRow
|
||||||
{
|
{
|
||||||
private static RspManipulation _new = new(SubRace.Midlander, RspAttribute.MaleMinSize, RspEntry.One);
|
private static RspManipulation _new = new(SubRace.Midlander, RspAttribute.MaleMinSize, RspEntry.One);
|
||||||
|
|
@ -657,8 +547,8 @@ public partial class ModEditWindow
|
||||||
CopyToClipboardButton("Copy all current RSP manipulations to clipboard.", iconSize,
|
CopyToClipboardButton("Copy all current RSP manipulations to clipboard.", iconSize,
|
||||||
editor.MetaEditor.Rsp.Select(m => (MetaManipulation)m));
|
editor.MetaEditor.Rsp.Select(m => (MetaManipulation)m));
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
var canAdd = editor.MetaEditor.CanAdd(_new);
|
var canAdd = editor.MetaEditor.CanAdd(_new);
|
||||||
var tt = canAdd ? "Stage this edit." : "This entry is already edited.";
|
var tt = canAdd ? "Stage this edit." : "This entry is already edited.";
|
||||||
var defaultEntry = CmpFile.GetDefault(metaFileManager, _new.SubRace, _new.Attribute);
|
var defaultEntry = CmpFile.GetDefault(metaFileManager, _new.SubRace, _new.Attribute);
|
||||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), iconSize, tt, !canAdd, true))
|
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), iconSize, tt, !canAdd, true))
|
||||||
editor.MetaEditor.Add(_new.Copy(defaultEntry));
|
editor.MetaEditor.Add(_new.Copy(defaultEntry));
|
||||||
|
|
@ -700,7 +590,7 @@ public partial class ModEditWindow
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
|
|
||||||
// Values
|
// Values
|
||||||
var def = CmpFile.GetDefault(metaFileManager, meta.SubRace, meta.Attribute).Value;
|
var def = CmpFile.GetDefault(metaFileManager, meta.SubRace, meta.Attribute).Value;
|
||||||
var value = meta.Entry.Value;
|
var value = meta.Entry.Value;
|
||||||
ImGui.SetNextItemWidth(FloatWidth);
|
ImGui.SetNextItemWidth(FloatWidth);
|
||||||
using var color = ImRaii.PushColor(ImGuiCol.FrameBg,
|
using var color = ImRaii.PushColor(ImGuiCol.FrameBg,
|
||||||
|
|
@ -713,12 +603,11 @@ public partial class ModEditWindow
|
||||||
ImGuiUtil.HoverTooltip($"Default Value: {def:0.###}");
|
ImGuiUtil.HoverTooltip($"Default Value: {def:0.###}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class GlobalEqpRow
|
private static class GlobalEqpRow
|
||||||
{
|
{
|
||||||
private static GlobalEqpManipulation _new = new()
|
private static GlobalEqpManipulation _new = new()
|
||||||
{
|
{
|
||||||
Type = GlobalEqpType.DoNotHideEarrings,
|
Type = GlobalEqpType.DoNotHideEarrings,
|
||||||
Condition = 1,
|
Condition = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -729,7 +618,7 @@ public partial class ModEditWindow
|
||||||
editor.MetaEditor.GlobalEqp.Select(m => (MetaManipulation)m));
|
editor.MetaEditor.GlobalEqp.Select(m => (MetaManipulation)m));
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
var canAdd = editor.MetaEditor.CanAdd(_new);
|
var canAdd = editor.MetaEditor.CanAdd(_new);
|
||||||
var tt = canAdd ? "Stage this edit." : "This entry is already manipulated.";
|
var tt = canAdd ? "Stage this edit." : "This entry is already manipulated.";
|
||||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), iconSize, tt, !canAdd, true))
|
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), iconSize, tt, !canAdd, true))
|
||||||
editor.MetaEditor.Add(_new);
|
editor.MetaEditor.Add(_new);
|
||||||
|
|
||||||
|
|
@ -744,7 +633,7 @@ public partial class ModEditWindow
|
||||||
if (ImUtf8.Selectable(type.ToName(), type == _new.Type))
|
if (ImUtf8.Selectable(type.ToName(), type == _new.Type))
|
||||||
_new = new GlobalEqpManipulation
|
_new = new GlobalEqpManipulation
|
||||||
{
|
{
|
||||||
Type = type,
|
Type = type,
|
||||||
Condition = type.HasCondition() ? _new.Type.HasCondition() ? _new.Condition : 1 : 0,
|
Condition = type.HasCondition() ? _new.Type.HasCondition() ? _new.Condition : 1 : 0,
|
||||||
};
|
};
|
||||||
ImUtf8.HoverTooltip(type.ToDescription());
|
ImUtf8.HoverTooltip(type.ToDescription());
|
||||||
|
|
@ -777,6 +666,7 @@ public partial class ModEditWindow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// A number input for ids with a optional max id of given width.
|
// A number input for ids with a optional max id of given width.
|
||||||
// Returns true if newId changed against currentId.
|
// Returns true if newId changed against currentId.
|
||||||
|
|
@ -824,7 +714,7 @@ public partial class ModEditWindow
|
||||||
return newValue != currentValue;
|
return newValue != currentValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CopyToClipboardButton(string tooltip, Vector2 iconSize, IEnumerable<MetaManipulation> manipulations)
|
private static void CopyToClipboardButton(string tooltip, Vector2 iconSize, MetaDictionary manipulations)
|
||||||
{
|
{
|
||||||
if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Clipboard.ToIconString(), iconSize, tooltip, false, true))
|
if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Clipboard.ToIconString(), iconSize, tooltip, false, true))
|
||||||
return;
|
return;
|
||||||
|
|
@ -840,10 +730,9 @@ public partial class ModEditWindow
|
||||||
{
|
{
|
||||||
var clipboard = ImGuiUtil.GetClipboardText();
|
var clipboard = ImGuiUtil.GetClipboardText();
|
||||||
|
|
||||||
var version = Functions.FromCompressedBase64<MetaManipulation[]>(clipboard, out var manips);
|
var version = Functions.FromCompressedBase64<MetaDictionary>(clipboard, out var manips);
|
||||||
if (version == MetaManipulation.CurrentVersion && manips != null)
|
if (version == MetaManipulation.CurrentVersion && manips != null)
|
||||||
foreach (var manip in manips.Where(m => m.ManipulationType != MetaManipulation.Type.Unknown))
|
_editor.MetaEditor.UpdateTo(manips);
|
||||||
_editor.MetaEditor.Set(manip);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGuiUtil.HoverTooltip(
|
ImGuiUtil.HoverTooltip(
|
||||||
|
|
@ -855,13 +744,9 @@ public partial class ModEditWindow
|
||||||
if (ImGui.Button("Set from Clipboard"))
|
if (ImGui.Button("Set from Clipboard"))
|
||||||
{
|
{
|
||||||
var clipboard = ImGuiUtil.GetClipboardText();
|
var clipboard = ImGuiUtil.GetClipboardText();
|
||||||
var version = Functions.FromCompressedBase64<MetaManipulation[]>(clipboard, out var manips);
|
var version = Functions.FromCompressedBase64<MetaDictionary>(clipboard, out var manips);
|
||||||
if (version == MetaManipulation.CurrentVersion && manips != null)
|
if (version == MetaManipulation.CurrentVersion && manips != null)
|
||||||
{
|
_editor.MetaEditor.SetTo(manips);
|
||||||
_editor.MetaEditor.Clear();
|
|
||||||
foreach (var manip in manips.Where(m => m.ManipulationType != MetaManipulation.Type.Unknown))
|
|
||||||
_editor.MetaEditor.Set(manip);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGuiUtil.HoverTooltip(
|
ImGuiUtil.HoverTooltip(
|
||||||
|
|
@ -870,11 +755,184 @@ public partial class ModEditWindow
|
||||||
|
|
||||||
private static void DrawMetaButtons(MetaManipulation meta, ModEditor editor, Vector2 iconSize)
|
private static void DrawMetaButtons(MetaManipulation meta, ModEditor editor, Vector2 iconSize)
|
||||||
{
|
{
|
||||||
ImGui.TableNextColumn();
|
//ImGui.TableNextColumn();
|
||||||
CopyToClipboardButton("Copy this manipulation to clipboard.", iconSize, Array.Empty<MetaManipulation>().Append(meta));
|
//CopyToClipboardButton("Copy this manipulation to clipboard.", iconSize, Array.Empty<MetaManipulation>().Append(meta));
|
||||||
|
//
|
||||||
ImGui.TableNextColumn();
|
//ImGui.TableNextColumn();
|
||||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), iconSize, "Delete this meta manipulation.", false, true))
|
//if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), iconSize, "Delete this meta manipulation.", false, true))
|
||||||
editor.MetaEditor.Delete(meta);
|
// editor.MetaEditor.Delete(meta);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public interface IMetaDrawer
|
||||||
|
{
|
||||||
|
public void Draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class MetaDrawer<TIdentifier, TEntry>(ModEditor editor, MetaFileManager metaFiles) : IMetaDrawer
|
||||||
|
where TIdentifier : unmanaged, IMetaIdentifier
|
||||||
|
where TEntry : unmanaged
|
||||||
|
{
|
||||||
|
protected readonly ModEditor Editor = editor;
|
||||||
|
protected readonly MetaFileManager MetaFiles = metaFiles;
|
||||||
|
protected TIdentifier Identifier;
|
||||||
|
protected TEntry Entry;
|
||||||
|
private bool _initialized;
|
||||||
|
|
||||||
|
public void Draw()
|
||||||
|
{
|
||||||
|
if (!_initialized)
|
||||||
|
{
|
||||||
|
Initialize();
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawNew();
|
||||||
|
foreach (var ((identifier, entry), idx) in Enumerate().WithIndex())
|
||||||
|
{
|
||||||
|
using var id = ImUtf8.PushId(idx);
|
||||||
|
DrawEntry(identifier, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void DrawNew();
|
||||||
|
protected abstract void Initialize();
|
||||||
|
protected abstract void DrawEntry(TIdentifier identifier, TEntry entry);
|
||||||
|
|
||||||
|
protected abstract IEnumerable<(TIdentifier, TEntry)> Enumerate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if false
|
||||||
|
public sealed class GmpMetaDrawer(ModEditor editor) : MetaDrawer<GmpIdentifier, GmpEntry>, IService
|
||||||
|
{
|
||||||
|
protected override void Initialize()
|
||||||
|
{
|
||||||
|
Identifier = new GmpIdentifier(1, EquipSlot.Body);
|
||||||
|
UpdateEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateEntry()
|
||||||
|
=> Entry = ExpandedEqpFile.GetDefault(metaManager, Identifier.SetId);
|
||||||
|
|
||||||
|
protected override void DrawNew()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
protected override void DrawEntry(GmpIdentifier identifier, GmpEntry entry)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
protected override IEnumerable<(GmpIdentifier, GmpEntry)> Enumerate()
|
||||||
|
=> editor.MetaEditor.Eqp.Select(kvp => (kvp.Key, kvp.Value.ToEntry(kvp.Key.Slot)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class EstMetaDrawer(ModEditor editor) : MetaDrawer<EstIdentifier, EstEntry>, IService
|
||||||
|
{
|
||||||
|
protected override void Initialize()
|
||||||
|
{
|
||||||
|
Identifier = new EqpIdentifier(1, EquipSlot.Body);
|
||||||
|
UpdateEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateEntry()
|
||||||
|
=> Entry = ExpandedEqpFile.GetDefault(metaManager, Identifier.SetId);
|
||||||
|
|
||||||
|
protected override void DrawNew()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
protected override void DrawEntry(EstIdentifier identifier, EstEntry entry)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
protected override IEnumerable<(EstIdentifier, EstEntry)> Enumerate()
|
||||||
|
=> editor.MetaEditor.Eqp.Select(kvp => (kvp.Key, kvp.Value.ToEntry(kvp.Key.Slot)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class EqdpMetaDrawer(ModEditor editor) : MetaDrawer<EqdpIdentifier, EqdpEntry>, IService
|
||||||
|
{
|
||||||
|
protected override void Initialize()
|
||||||
|
{
|
||||||
|
Identifier = new EqdpIdentifier(1, EquipSlot.Body);
|
||||||
|
UpdateEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateEntry()
|
||||||
|
=> Entry = ExpandedEqpFile.GetDefault(metaManager, Identifier.SetId);
|
||||||
|
|
||||||
|
protected override void DrawNew()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
protected override void DrawEntry(EqdpIdentifier identifier, EqdpEntry entry)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
protected override IEnumerable<(EqdpIdentifier, EqdpEntry)> Enumerate()
|
||||||
|
=> editor.MetaEditor.Eqp.Select(kvp => (kvp.Key, kvp.Value.ToEntry(kvp.Key.Slot)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class EqpMetaDrawer(ModEditor editor, MetaFileManager metaManager) : MetaDrawer<EqpIdentifier, EqpEntry>, IService
|
||||||
|
{
|
||||||
|
protected override void Initialize()
|
||||||
|
{
|
||||||
|
Identifier = new EqpIdentifier(1, EquipSlot.Body);
|
||||||
|
UpdateEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateEntry()
|
||||||
|
=> Entry = ExpandedEqpFile.GetDefault(metaManager, Identifier.SetId);
|
||||||
|
|
||||||
|
protected override void DrawNew()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
protected override void DrawEntry(EqpIdentifier identifier, EqpEntry entry)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
protected override IEnumerable<(EqpIdentifier, EqpEntry)> Enumerate()
|
||||||
|
=> editor.MetaEditor.Eqp.Select(kvp => (kvp.Key, kvp.Value.ToEntry(kvp.Key.Slot)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class RspMetaDrawer(ModEditor editor) : MetaDrawer<RspIdentifier, RspEntry>, IService
|
||||||
|
{
|
||||||
|
protected override void Initialize()
|
||||||
|
{
|
||||||
|
Identifier = new RspIdentifier(1, EquipSlot.Body);
|
||||||
|
UpdateEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateEntry()
|
||||||
|
=> Entry = ExpandedEqpFile.GetDefault(metaManager, Identifier.SetId);
|
||||||
|
|
||||||
|
protected override void DrawNew()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
protected override void DrawEntry(RspIdentifier identifier, RspEntry entry)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
protected override IEnumerable<(RspIdentifier, RspEntry)> Enumerate()
|
||||||
|
=> editor.MetaEditor.Eqp.Select(kvp => (kvp.Key, kvp.Value.ToEntry(kvp.Key.Slot)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public sealed class GlobalEqpMetaDrawer(ModEditor editor) : MetaDrawer<GlobalEqpManipulation, byte>, IService
|
||||||
|
{
|
||||||
|
protected override void Initialize()
|
||||||
|
{
|
||||||
|
Identifier = new EqpIdentifier(1, EquipSlot.Body);
|
||||||
|
UpdateEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateEntry()
|
||||||
|
=> Entry = ExpandedEqpFile.GetDefault(metaManager, Identifier.SetId);
|
||||||
|
|
||||||
|
protected override void DrawNew()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
protected override void DrawEntry(GlobalEqpManipulation identifier, byte _)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
protected override IEnumerable<(GlobalEqpManipulation, byte)> Enumerate()
|
||||||
|
=> editor.MetaEditor.Eqp.Select(kvp => (kvp.Key, kvp.Value.ToEntry(kvp.Key.Slot)));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ using Penumbra.Meta.Manipulations;
|
||||||
using Penumbra.Mods;
|
using Penumbra.Mods;
|
||||||
using Penumbra.Mods.Manager;
|
using Penumbra.Mods.Manager;
|
||||||
using Penumbra.Mods.Manager.OptionEditor;
|
using Penumbra.Mods.Manager.OptionEditor;
|
||||||
|
using Penumbra.UI.AdvancedWindow.Meta;
|
||||||
using Penumbra.UI.Classes;
|
using Penumbra.UI.Classes;
|
||||||
|
|
||||||
namespace Penumbra.UI.ModsTab.Groups;
|
namespace Penumbra.UI.ModsTab.Groups;
|
||||||
|
|
@ -79,29 +80,29 @@ public class AddGroupDrawer : IUiService
|
||||||
|
|
||||||
private void DrawImcInput(float width)
|
private void DrawImcInput(float width)
|
||||||
{
|
{
|
||||||
var change = ImcManipulationDrawer.DrawObjectType(ref _imcIdentifier, width);
|
var change = ImcMetaDrawer.DrawObjectType(ref _imcIdentifier, width);
|
||||||
ImUtf8.SameLineInner();
|
ImUtf8.SameLineInner();
|
||||||
change |= ImcManipulationDrawer.DrawPrimaryId(ref _imcIdentifier, width);
|
change |= ImcMetaDrawer.DrawPrimaryId(ref _imcIdentifier, width);
|
||||||
if (_imcIdentifier.ObjectType is ObjectType.Weapon or ObjectType.Monster)
|
if (_imcIdentifier.ObjectType is ObjectType.Weapon or ObjectType.Monster)
|
||||||
{
|
{
|
||||||
change |= ImcManipulationDrawer.DrawSecondaryId(ref _imcIdentifier, width);
|
change |= ImcMetaDrawer.DrawSecondaryId(ref _imcIdentifier, width);
|
||||||
ImUtf8.SameLineInner();
|
ImUtf8.SameLineInner();
|
||||||
change |= ImcManipulationDrawer.DrawVariant(ref _imcIdentifier, width);
|
change |= ImcMetaDrawer.DrawVariant(ref _imcIdentifier, width);
|
||||||
}
|
}
|
||||||
else if (_imcIdentifier.ObjectType is ObjectType.DemiHuman)
|
else if (_imcIdentifier.ObjectType is ObjectType.DemiHuman)
|
||||||
{
|
{
|
||||||
var quarterWidth = (width - ImUtf8.ItemInnerSpacing.X / ImUtf8.GlobalScale) / 2;
|
var quarterWidth = (width - ImUtf8.ItemInnerSpacing.X / ImUtf8.GlobalScale) / 2;
|
||||||
change |= ImcManipulationDrawer.DrawSecondaryId(ref _imcIdentifier, width);
|
change |= ImcMetaDrawer.DrawSecondaryId(ref _imcIdentifier, width);
|
||||||
ImUtf8.SameLineInner();
|
ImUtf8.SameLineInner();
|
||||||
change |= ImcManipulationDrawer.DrawSlot(ref _imcIdentifier, quarterWidth);
|
change |= ImcMetaDrawer.DrawSlot(ref _imcIdentifier, quarterWidth);
|
||||||
ImUtf8.SameLineInner();
|
ImUtf8.SameLineInner();
|
||||||
change |= ImcManipulationDrawer.DrawVariant(ref _imcIdentifier, quarterWidth);
|
change |= ImcMetaDrawer.DrawVariant(ref _imcIdentifier, quarterWidth);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
change |= ImcManipulationDrawer.DrawSlot(ref _imcIdentifier, width);
|
change |= ImcMetaDrawer.DrawSlot(ref _imcIdentifier, width);
|
||||||
ImUtf8.SameLineInner();
|
ImUtf8.SameLineInner();
|
||||||
change |= ImcManipulationDrawer.DrawVariant(ref _imcIdentifier, width);
|
change |= ImcMetaDrawer.DrawVariant(ref _imcIdentifier, width);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (change)
|
if (change)
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ using Penumbra.GameData.Structs;
|
||||||
using Penumbra.Mods.Groups;
|
using Penumbra.Mods.Groups;
|
||||||
using Penumbra.Mods.Manager.OptionEditor;
|
using Penumbra.Mods.Manager.OptionEditor;
|
||||||
using Penumbra.Mods.SubMods;
|
using Penumbra.Mods.SubMods;
|
||||||
|
using Penumbra.UI.AdvancedWindow.Meta;
|
||||||
|
|
||||||
namespace Penumbra.UI.ModsTab.Groups;
|
namespace Penumbra.UI.ModsTab.Groups;
|
||||||
|
|
||||||
|
|
@ -37,9 +38,9 @@ public readonly struct ImcModGroupEditDrawer(ModGroupEditDrawer editor, ImcModGr
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
using (ImUtf8.Group())
|
using (ImUtf8.Group())
|
||||||
{
|
{
|
||||||
changes |= ImcManipulationDrawer.DrawMaterialId(defaultEntry, ref entry, true);
|
changes |= ImcMetaDrawer.DrawMaterialId(defaultEntry, ref entry, true);
|
||||||
changes |= ImcManipulationDrawer.DrawVfxId(defaultEntry, ref entry, true);
|
changes |= ImcMetaDrawer.DrawVfxId(defaultEntry, ref entry, true);
|
||||||
changes |= ImcManipulationDrawer.DrawDecalId(defaultEntry, ref entry, true);
|
changes |= ImcMetaDrawer.DrawDecalId(defaultEntry, ref entry, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.SameLine(0, editor.PriorityWidth);
|
ImGui.SameLine(0, editor.PriorityWidth);
|
||||||
|
|
@ -54,8 +55,8 @@ public readonly struct ImcModGroupEditDrawer(ModGroupEditDrawer editor, ImcModGr
|
||||||
|
|
||||||
using (ImUtf8.Group())
|
using (ImUtf8.Group())
|
||||||
{
|
{
|
||||||
changes |= ImcManipulationDrawer.DrawMaterialAnimationId(defaultEntry, ref entry, true);
|
changes |= ImcMetaDrawer.DrawMaterialAnimationId(defaultEntry, ref entry, true);
|
||||||
changes |= ImcManipulationDrawer.DrawSoundId(defaultEntry, ref entry, true);
|
changes |= ImcMetaDrawer.DrawSoundId(defaultEntry, ref entry, true);
|
||||||
var canBeDisabled = group.CanBeDisabled;
|
var canBeDisabled = group.CanBeDisabled;
|
||||||
if (ImUtf8.Checkbox("##disabled"u8, ref canBeDisabled))
|
if (ImUtf8.Checkbox("##disabled"u8, ref canBeDisabled))
|
||||||
editor.ModManager.OptionEditor.ImcEditor.ChangeCanBeDisabled(group, canBeDisabled);
|
editor.ModManager.OptionEditor.ImcEditor.ChangeCanBeDisabled(group, canBeDisabled);
|
||||||
|
|
|
||||||
|
|
@ -10,210 +10,5 @@ namespace Penumbra.UI.ModsTab;
|
||||||
|
|
||||||
public static class ImcManipulationDrawer
|
public static class ImcManipulationDrawer
|
||||||
{
|
{
|
||||||
public static bool DrawObjectType(ref ImcIdentifier identifier, float width = 110)
|
|
||||||
{
|
|
||||||
var ret = Combos.ImcType("##imcType", identifier.ObjectType, out var type, width);
|
|
||||||
ImUtf8.HoverTooltip("Object Type"u8);
|
|
||||||
|
|
||||||
if (ret)
|
|
||||||
{
|
|
||||||
var equipSlot = type switch
|
|
||||||
{
|
|
||||||
ObjectType.Equipment => identifier.EquipSlot.IsEquipment() ? identifier.EquipSlot : EquipSlot.Head,
|
|
||||||
ObjectType.DemiHuman => identifier.EquipSlot.IsEquipment() ? identifier.EquipSlot : EquipSlot.Head,
|
|
||||||
ObjectType.Accessory => identifier.EquipSlot.IsAccessory() ? identifier.EquipSlot : EquipSlot.Ears,
|
|
||||||
_ => EquipSlot.Unknown,
|
|
||||||
};
|
|
||||||
identifier = identifier with
|
|
||||||
{
|
|
||||||
ObjectType = type,
|
|
||||||
EquipSlot = equipSlot,
|
|
||||||
SecondaryId = identifier.SecondaryId == 0 ? 1 : identifier.SecondaryId,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool DrawPrimaryId(ref ImcIdentifier identifier, float unscaledWidth = 80)
|
|
||||||
{
|
|
||||||
var ret = IdInput("##imcPrimaryId"u8, unscaledWidth, identifier.PrimaryId.Id, out var newId, 0, ushort.MaxValue,
|
|
||||||
identifier.PrimaryId.Id <= 1);
|
|
||||||
ImUtf8.HoverTooltip("Primary ID - You can usually find this as the 'x####' part of an item path.\n"u8
|
|
||||||
+ "This should generally not be left <= 1 unless you explicitly want that."u8);
|
|
||||||
if (ret)
|
|
||||||
identifier = identifier with { PrimaryId = newId };
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool DrawSecondaryId(ref ImcIdentifier identifier, float unscaledWidth = 100)
|
|
||||||
{
|
|
||||||
var ret = IdInput("##imcSecondaryId"u8, unscaledWidth, identifier.SecondaryId.Id, out var newId, 0, ushort.MaxValue, false);
|
|
||||||
ImUtf8.HoverTooltip("Secondary ID"u8);
|
|
||||||
if (ret)
|
|
||||||
identifier = identifier with { SecondaryId = newId };
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool DrawVariant(ref ImcIdentifier identifier, float unscaledWidth = 45)
|
|
||||||
{
|
|
||||||
var ret = IdInput("##imcVariant"u8, unscaledWidth, identifier.Variant.Id, out var newId, 0, byte.MaxValue, false);
|
|
||||||
ImUtf8.HoverTooltip("Variant ID"u8);
|
|
||||||
if (ret)
|
|
||||||
identifier = identifier with { Variant = (byte)newId };
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool DrawSlot(ref ImcIdentifier identifier, float unscaledWidth = 100)
|
|
||||||
{
|
|
||||||
bool ret;
|
|
||||||
EquipSlot slot;
|
|
||||||
switch (identifier.ObjectType)
|
|
||||||
{
|
|
||||||
case ObjectType.Equipment:
|
|
||||||
case ObjectType.DemiHuman:
|
|
||||||
ret = Combos.EqpEquipSlot("##slot", identifier.EquipSlot, out slot, unscaledWidth);
|
|
||||||
break;
|
|
||||||
case ObjectType.Accessory:
|
|
||||||
ret = Combos.AccessorySlot("##slot", identifier.EquipSlot, out slot, unscaledWidth);
|
|
||||||
break;
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImUtf8.HoverTooltip("Equip Slot"u8);
|
|
||||||
if (ret)
|
|
||||||
identifier = identifier with { EquipSlot = slot };
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool DrawMaterialId(ImcEntry defaultEntry, ref ImcEntry entry, bool addDefault, float unscaledWidth = 45)
|
|
||||||
{
|
|
||||||
if (!DragInput("##materialId"u8, "Material ID"u8, unscaledWidth * ImUtf8.GlobalScale, entry.MaterialId, defaultEntry.MaterialId,
|
|
||||||
out var newValue, (byte)1, byte.MaxValue, 0.01f, addDefault))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
entry = entry with { MaterialId = newValue };
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool DrawMaterialAnimationId(ImcEntry defaultEntry, ref ImcEntry entry, bool addDefault, float unscaledWidth = 45)
|
|
||||||
{
|
|
||||||
if (!DragInput("##mAnimId"u8, "Material Animation ID"u8, unscaledWidth * ImUtf8.GlobalScale, entry.MaterialAnimationId,
|
|
||||||
defaultEntry.MaterialAnimationId, out var newValue, (byte)0, byte.MaxValue, 0.01f, addDefault))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
entry = entry with { MaterialAnimationId = newValue };
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool DrawDecalId(ImcEntry defaultEntry, ref ImcEntry entry, bool addDefault, float unscaledWidth = 45)
|
|
||||||
{
|
|
||||||
if (!DragInput("##decalId"u8, "Decal ID"u8, unscaledWidth * ImUtf8.GlobalScale, entry.DecalId, defaultEntry.DecalId, out var newValue,
|
|
||||||
(byte)0, byte.MaxValue, 0.01f, addDefault))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
entry = entry with { DecalId = newValue };
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool DrawVfxId(ImcEntry defaultEntry, ref ImcEntry entry, bool addDefault, float unscaledWidth = 45)
|
|
||||||
{
|
|
||||||
if (!DragInput("##vfxId"u8, "VFX ID"u8, unscaledWidth * ImUtf8.GlobalScale, entry.VfxId, defaultEntry.VfxId, out var newValue, (byte)0,
|
|
||||||
byte.MaxValue, 0.01f, addDefault))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
entry = entry with { VfxId = newValue };
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool DrawSoundId(ImcEntry defaultEntry, ref ImcEntry entry, bool addDefault, float unscaledWidth = 45)
|
|
||||||
{
|
|
||||||
if (!DragInput("##soundId"u8, "Sound ID"u8, unscaledWidth * ImUtf8.GlobalScale, entry.SoundId, defaultEntry.SoundId, out var newValue,
|
|
||||||
(byte)0, byte.MaxValue, 0.01f, addDefault))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
entry = entry with { SoundId = newValue };
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool DrawAttributes(ImcEntry defaultEntry, ref ImcEntry entry)
|
|
||||||
{
|
|
||||||
var changes = false;
|
|
||||||
for (var i = 0; i < ImcEntry.NumAttributes; ++i)
|
|
||||||
{
|
|
||||||
using var id = ImRaii.PushId(i);
|
|
||||||
var flag = 1 << i;
|
|
||||||
var value = (entry.AttributeMask & flag) != 0;
|
|
||||||
var def = (defaultEntry.AttributeMask & flag) != 0;
|
|
||||||
if (Checkmark("##attribute"u8, "ABCDEFGHIJ"u8.Slice(i, 1), value, def, out var newValue))
|
|
||||||
{
|
|
||||||
var newMask = (ushort)(newValue ? entry.AttributeMask | flag : entry.AttributeMask & ~flag);
|
|
||||||
entry = entry with { AttributeMask = newMask };
|
|
||||||
changes = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i < ImcEntry.NumAttributes - 1)
|
|
||||||
ImGui.SameLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
return changes;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A number input for ids with an optional max id of given width.
|
|
||||||
/// Returns true if newId changed against currentId.
|
|
||||||
/// </summary>
|
|
||||||
private static bool IdInput(ReadOnlySpan<byte> label, float unscaledWidth, ushort currentId, out ushort newId, int minId, int maxId,
|
|
||||||
bool border)
|
|
||||||
{
|
|
||||||
int tmp = currentId;
|
|
||||||
ImGui.SetNextItemWidth(unscaledWidth * ImUtf8.GlobalScale);
|
|
||||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, UiHelpers.Scale, border);
|
|
||||||
using var color = ImRaii.PushColor(ImGuiCol.Border, Colors.RegexWarningBorder, border);
|
|
||||||
if (ImUtf8.InputScalar(label, ref tmp))
|
|
||||||
tmp = Math.Clamp(tmp, minId, maxId);
|
|
||||||
|
|
||||||
newId = (ushort)tmp;
|
|
||||||
return newId != currentId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A dragging int input of given width that compares against a default value, shows a tooltip and clamps against min and max.
|
|
||||||
/// Returns true if newValue changed against currentValue.
|
|
||||||
/// </summary>
|
|
||||||
private static bool DragInput<T>(ReadOnlySpan<byte> label, ReadOnlySpan<byte> tooltip, float width, T currentValue, T defaultValue,
|
|
||||||
out T newValue, T minValue, T maxValue, float speed, bool addDefault) where T : unmanaged, INumber<T>
|
|
||||||
{
|
|
||||||
newValue = currentValue;
|
|
||||||
using var color = ImRaii.PushColor(ImGuiCol.FrameBg,
|
|
||||||
defaultValue > currentValue ? ColorId.DecreasedMetaValue.Value() : ColorId.IncreasedMetaValue.Value(),
|
|
||||||
defaultValue != currentValue);
|
|
||||||
ImGui.SetNextItemWidth(width);
|
|
||||||
if (ImUtf8.DragScalar(label, ref newValue, minValue, maxValue, speed))
|
|
||||||
newValue = newValue <= minValue ? minValue : newValue >= maxValue ? maxValue : newValue;
|
|
||||||
|
|
||||||
if (addDefault)
|
|
||||||
ImUtf8.HoverTooltip($"{tooltip}\nDefault Value: {defaultValue}");
|
|
||||||
else
|
|
||||||
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, tooltip);
|
|
||||||
|
|
||||||
return newValue != currentValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A checkmark that compares against a default value and shows a tooltip.
|
|
||||||
/// Returns true if newValue is changed against currentValue.
|
|
||||||
/// </summary>
|
|
||||||
private static bool Checkmark(ReadOnlySpan<byte> label, ReadOnlySpan<byte> tooltip, bool currentValue, bool defaultValue,
|
|
||||||
out bool newValue)
|
|
||||||
{
|
|
||||||
using var color = ImRaii.PushColor(ImGuiCol.FrameBg,
|
|
||||||
defaultValue ? ColorId.DecreasedMetaValue.Value() : ColorId.IncreasedMetaValue.Value(),
|
|
||||||
defaultValue != currentValue);
|
|
||||||
newValue = currentValue;
|
|
||||||
ImUtf8.Checkbox(label, ref newValue);
|
|
||||||
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, tooltip);
|
|
||||||
return newValue != currentValue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,18 @@ public static class DictionaryExtensions
|
||||||
lhs.Add(key, value);
|
lhs.Add(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Set all entries in the right-hand dictionary to the same values in the left-hand dictionary, ensuring capacity beforehand. </summary>
|
||||||
|
public static void UpdateTo<TKey, TValue>(this Dictionary<TKey, TValue> lhs, IReadOnlyDictionary<TKey, TValue> rhs)
|
||||||
|
where TKey : notnull
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(lhs, rhs))
|
||||||
|
return;
|
||||||
|
|
||||||
|
lhs.EnsureCapacity(rhs.Count);
|
||||||
|
foreach (var (key, value) in rhs)
|
||||||
|
lhs[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Set one set to the other, deleting previous entries and ensuring capacity beforehand. </summary>
|
/// <summary> Set one set to the other, deleting previous entries and ensuring capacity beforehand. </summary>
|
||||||
public static void SetTo<T>(this HashSet<T> lhs, IReadOnlySet<T> rhs)
|
public static void SetTo<T>(this HashSet<T> lhs, IReadOnlySet<T> rhs)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue