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;
|
||||
|
||||
[JsonConverter(typeof(Converter))]
|
||||
public sealed class MetaDictionary : IEnumerable<MetaManipulation>
|
||||
public class MetaDictionary : IEnumerable<MetaManipulation>
|
||||
{
|
||||
private readonly Dictionary<ImcIdentifier, ImcEntry> _imc = [];
|
||||
private readonly Dictionary<EqpIdentifier, EqpEntryInternal> _eqp = [];
|
||||
|
|
@ -17,8 +17,37 @@ public sealed class MetaDictionary : IEnumerable<MetaManipulation>
|
|||
private readonly Dictionary<GmpIdentifier, GmpEntry> _gmp = [];
|
||||
private readonly HashSet<GlobalEqpManipulation> _globalEqp = [];
|
||||
|
||||
public IReadOnlyDictionary<ImcIdentifier, ImcEntry> Imc
|
||||
=> _imc;
|
||||
|
||||
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()
|
||||
{
|
||||
_imc.Clear();
|
||||
|
|
@ -123,6 +152,68 @@ public sealed class MetaDictionary : IEnumerable<MetaManipulation>
|
|||
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)
|
||||
{
|
||||
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>
|
||||
public bool MergeForced(MetaDictionary manips, out IMetaIdentifier failedIdentifier)
|
||||
public bool MergeForced(MetaDictionary manips, out IMetaIdentifier? failedIdentifier)
|
||||
{
|
||||
foreach (var (identifier, entry) in manips._imc)
|
||||
{
|
||||
if (!TryAdd(identifier, entry))
|
||||
foreach (var (identifier, _) in manips._imc.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
||||
{
|
||||
failedIdentifier = identifier;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (identifier, entry) in manips._eqp)
|
||||
{
|
||||
if (!TryAdd(identifier, entry))
|
||||
foreach (var (identifier, _) in manips._eqp.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
||||
{
|
||||
failedIdentifier = identifier;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (identifier, entry) in manips._eqdp)
|
||||
{
|
||||
if (!TryAdd(identifier, entry))
|
||||
foreach (var (identifier, _) in manips._eqdp.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
||||
{
|
||||
failedIdentifier = identifier;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (identifier, entry) in manips._gmp)
|
||||
{
|
||||
if (!TryAdd(identifier, entry))
|
||||
foreach (var (identifier, _) in manips._gmp.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
||||
{
|
||||
failedIdentifier = identifier;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (identifier, entry) in manips._rsp)
|
||||
{
|
||||
if (!TryAdd(identifier, entry))
|
||||
foreach (var (identifier, _) in manips._rsp.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
||||
{
|
||||
failedIdentifier = identifier;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (identifier, entry) in manips._est)
|
||||
{
|
||||
if (!TryAdd(identifier, entry))
|
||||
foreach (var (identifier, _) in manips._est.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
||||
{
|
||||
failedIdentifier = identifier;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var identifier in manips._globalEqp)
|
||||
{
|
||||
if (!TryAdd(identifier))
|
||||
foreach (var identifier in manips._globalEqp.Where(identifier => !TryAdd(identifier)))
|
||||
{
|
||||
failedIdentifier = identifier;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
failedIdentifier = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
var ret = new MetaDictionary();
|
||||
|
|
@ -251,6 +336,31 @@ public sealed class MetaDictionary : IEnumerable<MetaManipulation>
|
|||
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>
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, MetaDictionary? value, JsonSerializer serializer)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,149 @@
|
|||
using Dalamud.Interface;
|
||||
using ImGuiNET;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using OtterGui;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Mods.Editor;
|
||||
using Penumbra.String.Functions;
|
||||
using Penumbra.UI;
|
||||
using Penumbra.UI.ModsTab;
|
||||
|
||||
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 MetaIndex FileIndex();
|
||||
|
|
@ -315,3 +454,4 @@ public readonly struct MetaManipulation : IEquatable<MetaManipulation>, ICompara
|
|||
public static bool operator >=(MetaManipulation left, MetaManipulation right)
|
||||
=> left.CompareTo(right) >= 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -162,12 +162,9 @@ public class ModMerger : IDisposable
|
|||
|
||||
foreach (var originalOption in mergeOptions)
|
||||
{
|
||||
foreach (var manip in originalOption.Manipulations)
|
||||
{
|
||||
if (!manips.Add(manip))
|
||||
if (!manips.MergeForced(originalOption.Manipulations, out var failed))
|
||||
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.");
|
||||
}
|
||||
$"Could not add meta manipulation {failed} 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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,24 +1,24 @@
|
|||
using System.Collections.Frozen;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
using Penumbra.Mods.Manager;
|
||||
using Penumbra.Mods.SubMods;
|
||||
|
||||
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 int TotalCount;
|
||||
|
||||
public void Add(string name, int count)
|
||||
{
|
||||
if (count > 0)
|
||||
Add(name);
|
||||
TotalCount += count;
|
||||
}
|
||||
|
||||
public new void Clear()
|
||||
{
|
||||
TotalCount = 0;
|
||||
|
|
@ -31,91 +31,9 @@ public class ModMetaEditor(ModManager modManager)
|
|||
|
||||
public bool Changes { get; private set; }
|
||||
|
||||
public IReadOnlySet<ImcManipulation> Imc
|
||||
=> _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)
|
||||
public new void Clear()
|
||||
{
|
||||
return m.ManipulationType switch
|
||||
{
|
||||
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();
|
||||
base.Clear();
|
||||
Changes = true;
|
||||
}
|
||||
|
||||
|
|
@ -129,15 +47,19 @@ public class ModMetaEditor(ModManager modManager)
|
|||
if (option == currentOption)
|
||||
continue;
|
||||
|
||||
foreach (var manip in option.Manipulations)
|
||||
{
|
||||
var data = OtherData[manip.ManipulationType];
|
||||
++data.TotalCount;
|
||||
data.Add(option.GetFullName());
|
||||
}
|
||||
var name = option.GetFullName();
|
||||
OtherData[MetaManipulation.Type.Imc].Add(name, option.Manipulations.GetCount(MetaManipulation.Type.Imc));
|
||||
OtherData[MetaManipulation.Type.Eqp].Add(name, option.Manipulations.GetCount(MetaManipulation.Type.Eqp));
|
||||
OtherData[MetaManipulation.Type.Eqdp].Add(name, option.Manipulations.GetCount(MetaManipulation.Type.Eqdp));
|
||||
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)
|
||||
|
|
@ -145,50 +67,7 @@ public class ModMetaEditor(ModManager modManager)
|
|||
if (!Changes)
|
||||
return;
|
||||
|
||||
modManager.OptionEditor.SetManipulations(container, [..Recombine()]);
|
||||
modManager.OptionEditor.SetManipulations(container, this);
|
||||
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,9 +95,8 @@ public class ImcModGroup(Mod mod) : IModGroup
|
|||
public IModGroupEditDrawer EditDrawer(ModGroupEditDrawer editDrawer)
|
||||
=> new ImcModGroupEditDrawer(editDrawer, this);
|
||||
|
||||
public ImcManipulation GetManip(ushort mask, Variant variant)
|
||||
=> new(Identifier.ObjectType, Identifier.BodySlot, Identifier.PrimaryId, Identifier.SecondaryId.Id, variant.Id,
|
||||
Identifier.EquipSlot, DefaultEntry with { AttributeMask = mask });
|
||||
public ImcEntry GetEntry(ushort mask)
|
||||
=> DefaultEntry with { AttributeMask = mask };
|
||||
|
||||
public void AddData(Setting setting, Dictionary<Utf8GamePath, FullPath> redirections, MetaDictionary manipulations)
|
||||
{
|
||||
|
|
@ -105,18 +104,19 @@ public class ImcModGroup(Mod mod) : IModGroup
|
|||
return;
|
||||
|
||||
var mask = GetCurrentMask(setting);
|
||||
var entry = GetEntry(mask);
|
||||
if (AllVariants)
|
||||
{
|
||||
var count = ImcChecker.GetVariantCount(Identifier);
|
||||
if (count == 0)
|
||||
manipulations.Add(GetManip(mask, Identifier.Variant));
|
||||
manipulations.TryAdd(Identifier, entry);
|
||||
else
|
||||
for (var i = 0; i <= count; ++i)
|
||||
manipulations.Add(GetManip(mask, (Variant)i));
|
||||
manipulations.TryAdd(Identifier with { Variant = (Variant)i }, entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
manipulations.Add(GetManip(mask, Identifier.Variant));
|
||||
manipulations.TryAdd(Identifier, entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ public class ItemSwapContainer
|
|||
|
||||
private MetaDictionary MetaResolver(ModCollection? collection)
|
||||
=> collection?.MetaCache?.Manipulations is { } cache
|
||||
? [.. cache]
|
||||
? [] // [.. cache] TODO
|
||||
: _appliedModData.Manipulations;
|
||||
|
||||
public EquipItem[] LoadEquipment(EquipItem from, EquipItem to, ModCollection? collection = null, bool useRightRing = true,
|
||||
|
|
|
|||
|
|
@ -198,7 +198,8 @@ public partial class ModCreator(
|
|||
Penumbra.Log.Verbose(
|
||||
$"Incorporating {file} as Metadata file of {meta.MetaManipulations.Count} manipulations {deleteString}");
|
||||
deleteList.Add(file.FullName);
|
||||
option.Manipulations.UnionWith([.. meta.MetaManipulations]);
|
||||
// TODO
|
||||
option.Manipulations.UnionWith([]);//[.. meta.MetaManipulations]);
|
||||
}
|
||||
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}");
|
||||
deleteList.Add(file.FullName);
|
||||
|
||||
option.Manipulations.UnionWith([.. rgsp.MetaManipulations]);
|
||||
// TODO
|
||||
option.Manipulations.UnionWith([]);//[.. rgsp.MetaManipulations]);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public static class SubMod
|
|||
{
|
||||
to.Files = new Dictionary<Utf8GamePath, FullPath>(from.Files);
|
||||
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>
|
||||
|
|
|
|||
|
|
@ -93,7 +93,8 @@ public class TemporaryMod : IMod
|
|||
}
|
||||
}
|
||||
|
||||
MetaDictionary manips = [.. collection.MetaCache?.Manipulations ?? []];
|
||||
// TODO
|
||||
MetaDictionary manips = []; // [.. collection.MetaCache?.Manipulations ?? []];
|
||||
defaultMod.Manipulations.UnionWith(manips);
|
||||
|
||||
saveService.ImmediateSave(new ModSaveGroup(dir, defaultMod, config.ReplaceNonAsciiOnImport));
|
||||
|
|
|
|||
|
|
@ -188,7 +188,6 @@ public static class StaticServiceManager
|
|||
.AddSingleton<DuplicateManager>()
|
||||
.AddSingleton<MdlMaterialEditor>()
|
||||
.AddSingleton<ModFileEditor>()
|
||||
.AddSingleton<ModMetaEditor>()
|
||||
.AddSingleton<ModSwapEditor>()
|
||||
.AddSingleton<ModNormalizer>()
|
||||
.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 ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using OtterGui.Text.EndObjects;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Meta;
|
||||
using Penumbra.Meta.Files;
|
||||
|
|
@ -20,17 +21,7 @@ public partial class ModEditWindow
|
|||
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.";
|
||||
|
||||
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()
|
||||
{
|
||||
|
|
@ -56,7 +47,7 @@ public partial class ModEditWindow
|
|||
ImGui.SameLine();
|
||||
SetFromClipboardButton();
|
||||
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();
|
||||
if (ImGui.Button("Write as TexTools Files"))
|
||||
_metaFileManager.WriteAllTexToolsMeta(Mod!);
|
||||
|
|
@ -65,35 +56,85 @@ public partial class ModEditWindow
|
|||
if (!child)
|
||||
return;
|
||||
|
||||
DrawEditHeader(_editor.MetaEditor.Eqp, "Equipment Parameter Edits (EQP)###EQP", 5, EqpRow.Draw, EqpRow.DrawNew,
|
||||
_editor.MetaEditor.OtherData[MetaManipulation.Type.Eqp]);
|
||||
DrawEditHeader(_editor.MetaEditor.Eqdp, "Racial Model Edits (EQDP)###EQDP", 7, EqdpRow.Draw, EqdpRow.DrawNew,
|
||||
_editor.MetaEditor.OtherData[MetaManipulation.Type.Eqdp]);
|
||||
DrawEditHeader(_editor.MetaEditor.Imc, "Variant Edits (IMC)###IMC", 10, ImcRow.Draw, ImcRow.DrawNew,
|
||||
_editor.MetaEditor.OtherData[MetaManipulation.Type.Imc]);
|
||||
DrawEditHeader(_editor.MetaEditor.Est, "Extra Skeleton Parameters (EST)###EST", 7, EstRow.Draw, EstRow.DrawNew,
|
||||
_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]);
|
||||
DrawEditHeader(MetaManipulation.Type.Eqp);
|
||||
DrawEditHeader(MetaManipulation.Type.Eqdp);
|
||||
DrawEditHeader(MetaManipulation.Type.Imc);
|
||||
DrawEditHeader(MetaManipulation.Type.Est);
|
||||
DrawEditHeader(MetaManipulation.Type.Gmp);
|
||||
DrawEditHeader(MetaManipulation.Type.Rsp);
|
||||
DrawEditHeader(MetaManipulation.Type.GlobalEqp);
|
||||
}
|
||||
|
||||
private static ReadOnlySpan<byte> Label(MetaManipulation.Type type)
|
||||
=> type switch
|
||||
{
|
||||
MetaManipulation.Type.Imc => "Variant Edits (IMC)###IMC"u8,
|
||||
MetaManipulation.Type.Eqdp => "Racial Model Edits (EQDP)###EQDP"u8,
|
||||
MetaManipulation.Type.Eqp => "Equipment Parameter Edits (EQP)###EQP"u8,
|
||||
MetaManipulation.Type.Est => "Extra Skeleton Parameters (EST)###EST"u8,
|
||||
MetaManipulation.Type.Gmp => "Visor/Gimmick Edits (GMP)###GMP"u8,
|
||||
MetaManipulation.Type.Rsp => "Racial Scaling Edits (RSP)###RSP"u8,
|
||||
MetaManipulation.Type.GlobalEqp => "Global Equipment Parameter Edits (Global EQP)###GEQP"u8,
|
||||
_ => "\0"u8,
|
||||
};
|
||||
|
||||
/// <summary> The headers for the different meta changes all have basically the same structure for different types.</summary>
|
||||
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)
|
||||
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)
|
||||
return;
|
||||
|
||||
DrawTable(type);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
var oldPos = ImGui.GetCursorPosY();
|
||||
var header = ImGui.CollapsingHeader($"{items.Count} {label}");
|
||||
var newPos = ImGui.GetCursorPos();
|
||||
if (otherOptionData.TotalCount > 0)
|
||||
if (Drawer(type) is not { } drawer)
|
||||
return;
|
||||
|
||||
drawer.Draw();
|
||||
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));
|
||||
|
|
@ -108,28 +149,10 @@ public partial class ModEditWindow
|
|||
ImGui.SetCursorPos(newPos);
|
||||
}
|
||||
|
||||
if (!header)
|
||||
return;
|
||||
|
||||
using (var table = ImRaii.Table(label, numColumns, flags))
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.NewLine();
|
||||
}
|
||||
|
||||
#if false
|
||||
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
|
||||
=> 100 * UiHelpers.Scale;
|
||||
|
|
@ -209,8 +232,6 @@ public partial class ModEditWindow
|
|||
ImGui.NewLine();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class EqdpRow
|
||||
{
|
||||
private static EqdpManipulation _new = new(EqdpEntry.Invalid, EquipSlot.Head, Gender.Male, ModelRace.Midlander, 1);
|
||||
|
|
@ -322,135 +343,6 @@ public partial class ModEditWindow
|
|||
}
|
||||
}
|
||||
|
||||
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 EstManipulation _new = new(Gender.Male, ModelRace.Midlander, EstType.Body, 1, EstEntry.Zero);
|
||||
|
|
@ -543,7 +435,6 @@ public partial class ModEditWindow
|
|||
editor.MetaEditor.Change(meta.Copy(new EstEntry((ushort)entry)));
|
||||
}
|
||||
}
|
||||
|
||||
private static class GmpRow
|
||||
{
|
||||
private static GmpManipulation _new = new(GmpEntry.Default, 1);
|
||||
|
|
@ -643,7 +534,6 @@ public partial class ModEditWindow
|
|||
editor.MetaEditor.Change(meta.Copy(meta.Entry with { UnknownB = (byte)unkB }));
|
||||
}
|
||||
}
|
||||
|
||||
private static class RspRow
|
||||
{
|
||||
private static RspManipulation _new = new(SubRace.Midlander, RspAttribute.MaleMinSize, RspEntry.One);
|
||||
|
|
@ -713,7 +603,6 @@ public partial class ModEditWindow
|
|||
ImGuiUtil.HoverTooltip($"Default Value: {def:0.###}");
|
||||
}
|
||||
}
|
||||
|
||||
private static class GlobalEqpRow
|
||||
{
|
||||
private static GlobalEqpManipulation _new = new()
|
||||
|
|
@ -777,6 +666,7 @@ public partial class ModEditWindow
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// A number input for ids with a optional max id of given width.
|
||||
// Returns true if newId changed against currentId.
|
||||
|
|
@ -824,7 +714,7 @@ public partial class ModEditWindow
|
|||
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))
|
||||
return;
|
||||
|
|
@ -840,10 +730,9 @@ public partial class ModEditWindow
|
|||
{
|
||||
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)
|
||||
foreach (var manip in manips.Where(m => m.ManipulationType != MetaManipulation.Type.Unknown))
|
||||
_editor.MetaEditor.Set(manip);
|
||||
_editor.MetaEditor.UpdateTo(manips);
|
||||
}
|
||||
|
||||
ImGuiUtil.HoverTooltip(
|
||||
|
|
@ -855,13 +744,9 @@ public partial class ModEditWindow
|
|||
if (ImGui.Button("Set from Clipboard"))
|
||||
{
|
||||
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)
|
||||
{
|
||||
_editor.MetaEditor.Clear();
|
||||
foreach (var manip in manips.Where(m => m.ManipulationType != MetaManipulation.Type.Unknown))
|
||||
_editor.MetaEditor.Set(manip);
|
||||
}
|
||||
_editor.MetaEditor.SetTo(manips);
|
||||
}
|
||||
|
||||
ImGuiUtil.HoverTooltip(
|
||||
|
|
@ -870,11 +755,184 @@ public partial class ModEditWindow
|
|||
|
||||
private static void DrawMetaButtons(MetaManipulation meta, ModEditor editor, Vector2 iconSize)
|
||||
{
|
||||
ImGui.TableNextColumn();
|
||||
CopyToClipboardButton("Copy this manipulation to clipboard.", iconSize, Array.Empty<MetaManipulation>().Append(meta));
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), iconSize, "Delete this meta manipulation.", false, true))
|
||||
editor.MetaEditor.Delete(meta);
|
||||
//ImGui.TableNextColumn();
|
||||
//CopyToClipboardButton("Copy this manipulation to clipboard.", iconSize, Array.Empty<MetaManipulation>().Append(meta));
|
||||
//
|
||||
//ImGui.TableNextColumn();
|
||||
//if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), iconSize, "Delete this meta manipulation.", false, true))
|
||||
// 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.Manager;
|
||||
using Penumbra.Mods.Manager.OptionEditor;
|
||||
using Penumbra.UI.AdvancedWindow.Meta;
|
||||
using Penumbra.UI.Classes;
|
||||
|
||||
namespace Penumbra.UI.ModsTab.Groups;
|
||||
|
|
@ -79,29 +80,29 @@ public class AddGroupDrawer : IUiService
|
|||
|
||||
private void DrawImcInput(float width)
|
||||
{
|
||||
var change = ImcManipulationDrawer.DrawObjectType(ref _imcIdentifier, width);
|
||||
var change = ImcMetaDrawer.DrawObjectType(ref _imcIdentifier, width);
|
||||
ImUtf8.SameLineInner();
|
||||
change |= ImcManipulationDrawer.DrawPrimaryId(ref _imcIdentifier, width);
|
||||
change |= ImcMetaDrawer.DrawPrimaryId(ref _imcIdentifier, width);
|
||||
if (_imcIdentifier.ObjectType is ObjectType.Weapon or ObjectType.Monster)
|
||||
{
|
||||
change |= ImcManipulationDrawer.DrawSecondaryId(ref _imcIdentifier, width);
|
||||
change |= ImcMetaDrawer.DrawSecondaryId(ref _imcIdentifier, width);
|
||||
ImUtf8.SameLineInner();
|
||||
change |= ImcManipulationDrawer.DrawVariant(ref _imcIdentifier, width);
|
||||
change |= ImcMetaDrawer.DrawVariant(ref _imcIdentifier, width);
|
||||
}
|
||||
else if (_imcIdentifier.ObjectType is ObjectType.DemiHuman)
|
||||
{
|
||||
var quarterWidth = (width - ImUtf8.ItemInnerSpacing.X / ImUtf8.GlobalScale) / 2;
|
||||
change |= ImcManipulationDrawer.DrawSecondaryId(ref _imcIdentifier, width);
|
||||
change |= ImcMetaDrawer.DrawSecondaryId(ref _imcIdentifier, width);
|
||||
ImUtf8.SameLineInner();
|
||||
change |= ImcManipulationDrawer.DrawSlot(ref _imcIdentifier, quarterWidth);
|
||||
change |= ImcMetaDrawer.DrawSlot(ref _imcIdentifier, quarterWidth);
|
||||
ImUtf8.SameLineInner();
|
||||
change |= ImcManipulationDrawer.DrawVariant(ref _imcIdentifier, quarterWidth);
|
||||
change |= ImcMetaDrawer.DrawVariant(ref _imcIdentifier, quarterWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
change |= ImcManipulationDrawer.DrawSlot(ref _imcIdentifier, width);
|
||||
change |= ImcMetaDrawer.DrawSlot(ref _imcIdentifier, width);
|
||||
ImUtf8.SameLineInner();
|
||||
change |= ImcManipulationDrawer.DrawVariant(ref _imcIdentifier, width);
|
||||
change |= ImcMetaDrawer.DrawVariant(ref _imcIdentifier, width);
|
||||
}
|
||||
|
||||
if (change)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using Penumbra.GameData.Structs;
|
|||
using Penumbra.Mods.Groups;
|
||||
using Penumbra.Mods.Manager.OptionEditor;
|
||||
using Penumbra.Mods.SubMods;
|
||||
using Penumbra.UI.AdvancedWindow.Meta;
|
||||
|
||||
namespace Penumbra.UI.ModsTab.Groups;
|
||||
|
||||
|
|
@ -37,9 +38,9 @@ public readonly struct ImcModGroupEditDrawer(ModGroupEditDrawer editor, ImcModGr
|
|||
ImGui.SameLine();
|
||||
using (ImUtf8.Group())
|
||||
{
|
||||
changes |= ImcManipulationDrawer.DrawMaterialId(defaultEntry, ref entry, true);
|
||||
changes |= ImcManipulationDrawer.DrawVfxId(defaultEntry, ref entry, true);
|
||||
changes |= ImcManipulationDrawer.DrawDecalId(defaultEntry, ref entry, true);
|
||||
changes |= ImcMetaDrawer.DrawMaterialId(defaultEntry, ref entry, true);
|
||||
changes |= ImcMetaDrawer.DrawVfxId(defaultEntry, ref entry, true);
|
||||
changes |= ImcMetaDrawer.DrawDecalId(defaultEntry, ref entry, true);
|
||||
}
|
||||
|
||||
ImGui.SameLine(0, editor.PriorityWidth);
|
||||
|
|
@ -54,8 +55,8 @@ public readonly struct ImcModGroupEditDrawer(ModGroupEditDrawer editor, ImcModGr
|
|||
|
||||
using (ImUtf8.Group())
|
||||
{
|
||||
changes |= ImcManipulationDrawer.DrawMaterialAnimationId(defaultEntry, ref entry, true);
|
||||
changes |= ImcManipulationDrawer.DrawSoundId(defaultEntry, ref entry, true);
|
||||
changes |= ImcMetaDrawer.DrawMaterialAnimationId(defaultEntry, ref entry, true);
|
||||
changes |= ImcMetaDrawer.DrawSoundId(defaultEntry, ref entry, true);
|
||||
var canBeDisabled = group.CanBeDisabled;
|
||||
if (ImUtf8.Checkbox("##disabled"u8, ref canBeDisabled))
|
||||
editor.ModManager.OptionEditor.ImcEditor.ChangeCanBeDisabled(group, canBeDisabled);
|
||||
|
|
|
|||
|
|
@ -10,210 +10,5 @@ namespace Penumbra.UI.ModsTab;
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
/// <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>
|
||||
public static void SetTo<T>(this HashSet<T> lhs, IReadOnlySet<T> rhs)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue