Added more detailed information about metadata changes on click on value, as well as option to edit them or add new ones.

This commit is contained in:
Ottermandias 2021-07-17 23:17:41 +02:00
parent 068b1e074b
commit 83cad76b62
9 changed files with 950 additions and 166 deletions

View file

@ -32,7 +32,7 @@ namespace Penumbra.Game
LegsHideBootsM = 0x08ul << 16,
_20 = 0x10ul << 16,
LegsShowFoot = 0x20ul << 16,
_22 = 0x40ul << 16,
LegsShowTail = 0x40ul << 16,
_23 = 0x80ul << 16,
LegsMask = 0xFFul << 16,

View file

@ -21,13 +21,35 @@ namespace Penumbra.Meta.Files
public static ulong ToInteger( this ImcFile.ImageChangeData imc )
{
ulong ret = imc.MaterialId;
ret |= ( ulong )imc.DecalId << 8;
ret |= ( ulong )imc.AttributeMask << 16;
ret |= ( ulong )imc.SoundId << 16;
ret |= ( ulong )imc.VfxId << 32;
ret |= ( ulong )imc.DecalId << 8;
ret |= ( ulong )imc.AttributeMask << 16;
ret |= ( ulong )imc.SoundId << 16;
ret |= ( ulong )imc.VfxId << 32;
ret |= ( ulong )imc.ActualMaterialAnimationId() << 40;
return ret;
}
public static byte ActualMaterialAnimationId( this ImcFile.ImageChangeData imc )
{
var tmp = imc.GetType().GetField( "_MaterialAnimationIdMask",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance );
ret |= ( ulong )( byte )tmp!.GetValue( imc ) << 40;
return ( byte )( tmp?.GetValue( imc ) ?? 0 );
}
public static ImcFile.ImageChangeData FromValues( byte materialId, byte decalId, ushort attributeMask, byte soundId, byte vfxId,
byte materialAnimationId )
{
var ret = new ImcFile.ImageChangeData()
{
DecalId = decalId,
MaterialId = materialId,
VfxId = vfxId,
};
ret.GetType().GetField( "_AttributeAndSound",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance )!
.SetValue( ret, ( ushort )( ( attributeMask & 0x3FF ) | ( soundId << 10 ) ) );
ret.GetType().GetField( "_AttributeAndSound",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance )!.SetValue( ret, materialAnimationId );
return ret;
}
@ -45,7 +67,7 @@ namespace Penumbra.Meta.Files
bw.Write( variant.DecalId );
bw.Write( ( ushort )( variant.AttributeMask | variant.SoundId ) );
bw.Write( variant.VfxId );
bw.Write( variant.MaterialAnimationId );
bw.Write( variant.ActualMaterialAnimationId() );
}
public static byte[] WriteBytes( this ImcFile file )

View file

@ -145,6 +145,24 @@ namespace Penumbra.Meta.Files
};
}
public object? GetDefaultValue( MetaManipulation m )
{
return m.Type switch
{
MetaType.Imc => GetDefaultImcFile( m.ImcIdentifier.ObjectType, m.ImcIdentifier.PrimaryId, m.ImcIdentifier.SecondaryId )
?.GetValue( m ),
MetaType.Gmp => GetDefaultGmpFile()?.GetEntry( m.GmpIdentifier.SetId ),
MetaType.Eqp => GetDefaultEqpFile()?.GetEntry( m.EqpIdentifier.SetId )
.Reduce( m.EqpIdentifier.Slot ),
MetaType.Eqdp => GetDefaultEqdpFile( m.EqdpIdentifier.Slot, m.EqdpIdentifier.GenderRace )?.GetEntry( m.EqdpIdentifier.SetId )
.Reduce( m.EqdpIdentifier.Slot ),
MetaType.Est => GetDefaultEstFile( m.EstIdentifier.ObjectType, m.EstIdentifier.EquipSlot, m.EstIdentifier.BodySlot )
?.GetEntry( m.EstIdentifier.GenderRace, m.EstIdentifier.PrimaryId ),
MetaType.Rsp => GetDefaultCmpFile()?[ m.RspIdentifier.SubRace ][ m.RspIdentifier.Attribute ],
_ => throw new NotImplementedException(),
};
}
// Create a deep copy of a default file as a new file.
public object? CreateNewFile( MetaManipulation m )
{

View file

@ -50,7 +50,7 @@ namespace Penumbra.Mods
}
}
internal void UpdateCollections( ModData mod, bool metaChanges, ResourceChange fileChanges, bool nameChange, bool recomputeMeta )
internal void UpdateCollections( ModData mod, bool metaChanges, ResourceChange fileChanges, bool nameChange, bool reloadMeta )
{
foreach( var collection in Collections.Values )
{
@ -70,13 +70,13 @@ namespace Penumbra.Mods
collection.Cache?.CalculateEffectiveFileList();
}
if( recomputeMeta )
if( reloadMeta )
{
collection.Cache?.UpdateMetaManipulations();
}
}
if( recomputeMeta )
if( reloadMeta && ActiveCollection.Settings.TryGetValue( mod.BasePath.Name, out var config ) && config.Enabled )
{
Service< GameResourceManagement >.Get().ReloadPlayerResources();
}

View file

@ -152,7 +152,7 @@ namespace Penumbra.Mods
return true;
}
public bool UpdateMod( ModData mod, bool recomputeMeta = false )
public bool UpdateMod( ModData mod, bool reloadMeta = false, bool recomputeMeta = false )
{
var oldName = mod.Meta.Name;
var metaChanges = mod.Meta.RefreshFromFile( mod.MetaFile );
@ -177,7 +177,7 @@ namespace Penumbra.Mods
mod.Resources.MetaManipulations.SaveToFile( MetaCollection.FileName( mod.BasePath ) );
}
Collections.UpdateCollections( mod, metaChanges, fileChanges, nameChange, recomputeMeta );
Collections.UpdateCollections( mod, metaChanges, fileChanges, nameChange, reloadMeta );
return true;
}

View file

@ -54,10 +54,13 @@ namespace Penumbra.UI
private const float OptionSelectionWidth = 140f;
private const float CheckMarkSize = 50f;
private const uint ColorDarkGreen = 0xFF00A000;
private const uint ColorGreen = 0xFF00C800;
private const uint ColorYellow = 0xFF00C8C8;
private const uint ColorDarkRed = 0xFF0000A0;
private const uint ColorRed = 0xFF0000C8;
private bool _editMode;
private int _selectedGroupIndex;
private OptionGroup? _selectedGroup;
@ -649,149 +652,6 @@ namespace Penumbra.UI
}
}
private static void DrawManipulationRow( MetaManipulation manip )
{
ImGui.TableNextColumn();
ImGui.Text( manip.Type.ToString() );
ImGui.TableNextColumn();
switch( manip.Type )
{
case MetaType.Eqp:
{
ImGui.Text( manip.EqpIdentifier.Slot.IsAccessory()
? ObjectType.Accessory.ToString()
: ObjectType.Equipment.ToString() );
ImGui.TableNextColumn();
ImGui.Text( manip.EqpIdentifier.SetId.ToString() );
ImGui.TableNextColumn();
ImGui.Text( manip.EqpIdentifier.Slot.ToString() );
break;
}
case MetaType.Gmp:
{
ImGui.Text( ObjectType.Equipment.ToString() );
ImGui.TableNextColumn();
ImGui.Text( manip.GmpIdentifier.SetId.ToString() );
ImGui.TableNextColumn();
ImGui.Text( EquipSlot.Head.ToString() );
break;
}
case MetaType.Eqdp:
{
ImGui.Text( manip.EqpIdentifier.Slot.IsAccessory()
? ObjectType.Accessory.ToString()
: ObjectType.Equipment.ToString() );
ImGui.TableNextColumn();
ImGui.Text( manip.EqdpIdentifier.SetId.ToString() );
ImGui.TableNextColumn();
ImGui.Text( manip.EqpIdentifier.Slot.ToString() );
ImGui.TableNextColumn();
var (gender, race) = manip.EqdpIdentifier.GenderRace.Split();
ImGui.Text( race.ToString() );
ImGui.TableNextColumn();
ImGui.Text( gender.ToString() );
break;
}
case MetaType.Est:
{
ImGui.Text( manip.EstIdentifier.ObjectType.ToString() );
ImGui.TableNextColumn();
ImGui.Text( manip.EstIdentifier.PrimaryId.ToString() );
ImGui.TableNextColumn();
ImGui.Text( manip.EstIdentifier.ObjectType == ObjectType.Equipment
? manip.EstIdentifier.EquipSlot.ToString()
: manip.EstIdentifier.BodySlot.ToString() );
ImGui.TableNextColumn();
var (gender, race) = manip.EstIdentifier.GenderRace.Split();
ImGui.Text( race.ToString() );
ImGui.TableNextColumn();
ImGui.Text( gender.ToString() );
break;
}
case MetaType.Imc:
{
ImGui.Text( manip.ImcIdentifier.ObjectType.ToString() );
ImGui.TableNextColumn();
ImGui.Text( manip.ImcIdentifier.PrimaryId.ToString() );
ImGui.TableNextColumn();
if( manip.ImcIdentifier.ObjectType == ObjectType.Accessory
|| manip.ImcIdentifier.ObjectType == ObjectType.Equipment )
{
ImGui.Text( manip.ImcIdentifier.ObjectType == ObjectType.Equipment
|| manip.ImcIdentifier.ObjectType == ObjectType.Accessory
? manip.ImcIdentifier.EquipSlot.ToString()
: manip.ImcIdentifier.BodySlot.ToString() );
}
ImGui.TableNextColumn();
ImGui.TableNextColumn();
ImGui.TableNextColumn();
if( manip.ImcIdentifier.ObjectType != ObjectType.Equipment
&& manip.ImcIdentifier.ObjectType != ObjectType.Accessory )
{
ImGui.Text( manip.ImcIdentifier.SecondaryId.ToString() );
}
ImGui.TableNextColumn();
ImGui.Text( manip.ImcIdentifier.Variant.ToString() );
break;
}
case MetaType.Rsp:
{
ImGui.Text( manip.RspIdentifier.Attribute.ToUngenderedString() );
ImGui.TableNextColumn();
ImGui.TableNextColumn();
ImGui.TableNextColumn();
ImGui.Text( manip.RspIdentifier.SubRace.ToString() );
ImGui.TableNextColumn();
ImGui.Text( manip.RspIdentifier.Attribute.ToGender().ToString() );
break;
}
}
ImGui.TableSetColumnIndex( 9 );
ImGui.Text( manip.Type == MetaType.Rsp ? manip.RspValue.ToString( CultureInfo.InvariantCulture ) : manip.Value.ToString() );
ImGui.TableNextRow();
}
private static void DrawMetaManipulationsTable( string label, List< MetaManipulation > list )
{
if( list.Count == 0
|| !ImGui.BeginTable( label, 10,
ImGuiTableFlags.BordersInner | ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit ) )
{
return;
}
ImGui.TableNextColumn();
ImGui.TableHeader( $"Type##{label}" );
ImGui.TableNextColumn();
ImGui.TableHeader( $"Object Type##{label}" );
ImGui.TableNextColumn();
ImGui.TableHeader( $"Set##{label}" );
ImGui.TableNextColumn();
ImGui.TableHeader( $"Slot##{label}" );
ImGui.TableNextColumn();
ImGui.TableHeader( $"Race##{label}" );
ImGui.TableNextColumn();
ImGui.TableHeader( $"Gender##{label}" );
ImGui.TableNextColumn();
ImGui.TableHeader( $"Secondary ID##{label}" );
ImGui.TableNextColumn();
ImGui.TableHeader( $"Variant##{label}" );
ImGui.TableNextColumn();
ImGui.TableNextColumn();
ImGui.TableHeader( $"Value##{label}" );
ImGui.TableNextRow();
foreach( var manip in list )
{
DrawManipulationRow( manip );
}
ImGui.EndTable();
}
private void DrawMetaManipulationsTab()
{
if( Mod.Data.Resources.MetaManipulations.Count == 0 )
@ -806,26 +666,33 @@ namespace Penumbra.UI
if( ImGui.BeginListBox( "##MetaManipulations", AutoFillSize ) )
{
var manips = Mod.Data.Resources.MetaManipulations;
if( manips.DefaultData.Count > 0 )
var manips = Mod.Data.Resources.MetaManipulations;
var changes = false;
if( _editMode || manips.DefaultData.Count > 0 )
{
if( ImGui.CollapsingHeader( "Default" ) )
{
DrawMetaManipulationsTable( "##DefaultManips", manips.DefaultData );
changes = DrawMetaManipulationsTable( "##DefaultManips", manips.DefaultData );
}
}
foreach( var group in manips.GroupData )
{
foreach( var option in @group.Value )
foreach( var option in group.Value )
{
if( ImGui.CollapsingHeader( $"{@group.Key} - {option.Key}" ) )
if( ImGui.CollapsingHeader( $"{group.Key} - {option.Key}" ) )
{
DrawMetaManipulationsTable( $"##{@group.Key}{option.Key}manips", option.Value );
changes |= DrawMetaManipulationsTable( $"##{group.Key}{option.Key}manips", option.Value );
}
}
}
if( changes )
{
Mod.Data.Resources.MetaManipulations.SaveToFile( MetaCollection.FileName( Mod.Data.BasePath ) );
_selector.ReloadCurrentMod( true, false );
}
ImGui.EndListBox();
}

View file

@ -0,0 +1,877 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Numerics;
using Dalamud.Interface;
using ImGuiNET;
using Lumina.Data.Files;
using Penumbra.Game;
using Penumbra.Game.Enums;
using Penumbra.Meta;
using Penumbra.Meta.Files;
using Penumbra.Util;
using ObjectType = Penumbra.Game.Enums.ObjectType;
namespace Penumbra.UI
{
public partial class SettingsInterface
{
private partial class PluginDetails
{
private int _newManipTypeIdx = 0;
private ushort _newManipSetId = 0;
private ushort _newManipSecondaryId = 0;
private int _newManipSubrace = 0;
private int _newManipRace = 0;
private int _newManipAttribute = 0;
private int _newManipEquipSlot = 0;
private int _newManipObjectType = 0;
private int _newManipGender = 0;
private int _newManipBodySlot = 0;
private ushort _newManipVariant = 0;
private static readonly (string, EqpEntry)[] EqpAttributesBody =
{
( "Enabled", EqpEntry.BodyEnabled ),
( "Hide Waist", EqpEntry.BodyHideWaist ),
( "Hide Small Gloves", EqpEntry.BodyHideGlovesS ),
( "Hide Medium Gloves", EqpEntry.BodyHideGlovesM ),
( "Hide Large Gloves", EqpEntry.BodyHideGlovesL ),
( "Hide Gorget", EqpEntry.BodyHideGorget ),
( "Show Legs", EqpEntry.BodyShowLeg ),
( "Show Hands", EqpEntry.BodyShowHand ),
( "Show Head", EqpEntry.BodyShowHead ),
( "Show Necklace", EqpEntry.BodyShowNecklace ),
( "Show Bracelet", EqpEntry.BodyShowBracelet ),
( "Show Tail", EqpEntry.BodyShowTail ),
( "Unknown 2", EqpEntry._2 ),
( "Unknown 4", EqpEntry._4 ),
( "Unknown 14", EqpEntry._14 ),
( "Unknown 15", EqpEntry._15 ),
};
private static readonly (string, EqpEntry)[] EqpAttributesLegs =
{
( "Enabled", EqpEntry.LegsEnabled ),
( "Hide Kneepads", EqpEntry.LegsHideKneePads ),
( "Hide Small Boots", EqpEntry.LegsHideBootsS ),
( "Hide Medium Boots", EqpEntry.LegsHideBootsM ),
( "Hide Show Foot", EqpEntry.LegsShowFoot ),
( "Hide Show Tail", EqpEntry.LegsShowTail ),
( "Unknown 20", EqpEntry._20 ),
( "Unknown 23", EqpEntry._23 ),
};
private static readonly (string, EqpEntry)[] EqpAttributesHands =
{
( "Enabled", EqpEntry.HandsEnabled ),
( "Hide Elbow", EqpEntry.HandsHideElbow ),
( "Hide Forearm", EqpEntry.HandsHideForearm ),
( "Show Bracelet", EqpEntry.HandShowBracelet ),
( "Show Left Ring", EqpEntry.HandShowRingL ),
( "Show Right Ring", EqpEntry.HandShowRingR ),
( "Unknown 27", EqpEntry._27 ),
( "Unknown 31", EqpEntry._31 ),
};
private static readonly (string, EqpEntry)[] EqpAttributesFeet =
{
( "Enabled", EqpEntry.FeetEnabled ),
( "Hide Knees", EqpEntry.FeetHideKnee ),
( "Hide Calfs", EqpEntry.FeetHideCalf ),
( "Hide Ankles", EqpEntry.FeetHideAnkle ),
( "Unknown 36", EqpEntry._36 ),
( "Unknown 37", EqpEntry._37 ),
( "Unknown 38", EqpEntry._38 ),
( "Unknown 39", EqpEntry._39 ),
};
private static readonly (string, EqpEntry)[] EqpAttributesHead =
{
( "Enabled", EqpEntry.HeadEnabled ),
( "Hide Scalp", EqpEntry.HeadHideScalp ),
( "Hide Hair", EqpEntry.HeadHideHair ),
( "Show Hair Override", EqpEntry.HeadShowHairOverride ),
( "Hide Neck", EqpEntry.HeadHideNeck ),
( "Show Necklace", EqpEntry.HeadShowNecklace ),
( "Show Earrings", EqpEntry.HeadShowEarrings ),
( "Show Earrings (Human)", EqpEntry.HeadShowEarringsHuman ),
( "Show Earrings (Au Ra)", EqpEntry.HeadShowEarringsAura ),
( "Show Ears (Human)", EqpEntry.HeadShowEarHuman ),
( "Show Ears (Miqo'te)", EqpEntry.HeadShowEarMiqote ),
( "Show Ears (Au Ra)", EqpEntry.HeadShowEarAuRa ),
( "Show Ears (Viera)", EqpEntry.HeadShowEarViera ),
( "Show on Hrothgar", EqpEntry.HeadShowHrothgarHat ),
( "Show on Viera", EqpEntry.HeadShowVieraHat ),
( "Unknown 46", EqpEntry._46 ),
( "Unknown 54", EqpEntry._54 ),
( "Unknown 55", EqpEntry._55 ),
( "Unknown 58", EqpEntry._58 ),
( "Unknown 59", EqpEntry._59 ),
( "Unknown 60", EqpEntry._60 ),
( "Unknown 61", EqpEntry._61 ),
( "Unknown 62", EqpEntry._62 ),
( "Unknown 63", EqpEntry._63 ),
};
private static readonly (string, EquipSlot)[] EqpEquipSlots = new[]
{
( "Head", EquipSlot.Head ),
( "Body", EquipSlot.Body ),
( "Hands", EquipSlot.Hands ),
( "Legs", EquipSlot.Legs ),
( "Feet", EquipSlot.Feet ),
};
private static readonly (string, EquipSlot)[] EqdpEquipSlots = new[]
{
EqpEquipSlots[ 0 ],
EqpEquipSlots[ 1 ],
EqpEquipSlots[ 2 ],
EqpEquipSlots[ 3 ],
EqpEquipSlots[ 4 ],
( "Ears", EquipSlot.Ears ),
( "Neck", EquipSlot.Neck ),
( "Wrist", EquipSlot.Wrists ),
( "Left Finger", EquipSlot.RingL ),
( "Right Finger", EquipSlot.RingR ),
};
private static readonly (string, Race)[] Races = new[]
{
( "Midlander", Race.Midlander ),
( "Highlander", Race.Highlander ),
( "Elezen", Race.Elezen ),
( "Miqo'te", Race.Miqote ),
( "Roegadyn", Race.Roegadyn ),
( "Lalafell", Race.Lalafell ),
( "Au Ra", Race.AuRa ),
( "Viera", Race.Viera ),
( "Hrothgar", Race.Hrothgar ),
};
private static readonly (string, Gender)[] Genders = new[]
{
( "Male", Gender.Male ),
( "Female", Gender.Female ),
( "Male (NPC)", Gender.MaleNpc ),
( "Female (NPC)", Gender.FemaleNpc ),
};
private static readonly (string, ObjectType)[] ObjectTypes = new[]
{
( "Equipment", ObjectType.Equipment ),
( "Customization", ObjectType.Character ),
};
private static readonly (string, EquipSlot)[] EstEquipSlots = new[]
{
EqpEquipSlots[ 0 ],
EqpEquipSlots[ 1 ],
};
private static readonly (string, BodySlot)[] EstBodySlots = new[]
{
( "Hair", BodySlot.Hair ),
( "Face", BodySlot.Face ),
};
private static readonly (string, SubRace)[] Subraces = new[]
{
( "Midlander", SubRace.Midlander ),
( "Highlander", SubRace.Highlander ),
( "Wildwood", SubRace.Wildwood ),
( "Duskwright", SubRace.Duskwright ),
( "Seeker Of The Sun", SubRace.SeekerOfTheSun ),
( "Keeper Of The Moon", SubRace.KeeperOfTheMoon ),
( "Seawolf", SubRace.Seawolf ),
( "Hellsguard", SubRace.Hellsguard ),
( "Plainsfolk", SubRace.Plainsfolk ),
( "Dunesfolk", SubRace.Dunesfolk ),
( "Raen", SubRace.Raen ),
( "Xaela", SubRace.Xaela ),
( "Rava", SubRace.Rava ),
( "Veena", SubRace.Veena ),
( "Hellion", SubRace.Hellion ),
( "Lost", SubRace.Lost ),
};
private static readonly (string, RspAttribute)[] RspAttributes = new[]
{
( "Male Minimum Size", RspAttribute.MaleMinSize ),
( "Male Maximum Size", RspAttribute.MaleMaxSize ),
( "Female Minimum Size", RspAttribute.FemaleMinSize ),
( "Female Maximum Size", RspAttribute.FemaleMaxSize ),
( "Bust Minimum X-Axis", RspAttribute.BustMinX ),
( "Bust Maximum X-Axis", RspAttribute.BustMaxX ),
( "Bust Minimum Y-Axis", RspAttribute.BustMinY ),
( "Bust Maximum Y-Axis", RspAttribute.BustMaxY ),
( "Bust Minimum Z-Axis", RspAttribute.BustMinZ ),
( "Bust Maximum Z-Axis", RspAttribute.BustMaxZ ),
( "Male Minimum Tail Length", RspAttribute.MaleMinTail ),
( "Male Maximum Tail Length", RspAttribute.MaleMaxTail ),
( "Female Minimum Tail Length", RspAttribute.FemaleMinTail ),
( "Female Maximum Tail Length", RspAttribute.FemaleMaxTail ),
};
private static readonly (string, ObjectType)[] ImcObjectType = new[]
{
ObjectTypes[ 0 ],
( "Weapon", ObjectType.Weapon ),
( "Demihuman", ObjectType.DemiHuman ),
( "Monster", ObjectType.Monster ),
};
private static readonly (string, BodySlot)[] ImcBodySlots = new[]
{
EstBodySlots[ 0 ],
EstBodySlots[ 1 ],
( "Body", BodySlot.Body ),
( "Tail", BodySlot.Tail ),
( "Ears", BodySlot.Zear ),
};
private static bool PrintCheckBox( string name, ref bool value, bool def )
{
var color = value == def ? 0 : value ? ColorDarkGreen : ColorDarkRed;
if( color == 0 )
{
return ImGui.Checkbox( name, ref value );
}
ImGui.PushStyleColor( ImGuiCol.Text, color );
var ret = ImGui.Checkbox( name, ref value );
ImGui.PopStyleColor();
return ret;
}
private bool RestrictedInputInt( string name, ref ushort value, ushort min, ushort max )
{
int tmp = value;
if( ImGui.InputInt( name, ref tmp, 0, 0, _editMode ? ImGuiInputTextFlags.EnterReturnsTrue : ImGuiInputTextFlags.ReadOnly )
&& tmp != value
&& tmp >= min
&& tmp <= max )
{
value = ( ushort )tmp;
return true;
}
return false;
}
private static bool DefaultButton< T >( string name, ref T value, T defaultValue ) where T : IComparable< T >
{
var compare = defaultValue.CompareTo( value );
var color = compare < 0 ? ColorDarkGreen :
compare > 0 ? ColorDarkRed : ImGui.ColorConvertFloat4ToU32( ImGui.GetStyle().Colors[ ( int )ImGuiCol.Button ] );
ImGui.PushStyleColor( ImGuiCol.Button, color );
var ret = ImGui.Button( name, Vector2.UnitX * 120 ) && compare != 0;
ImGui.SameLine();
ImGui.PopStyleColor();
return ret;
}
private bool DrawInputWithDefault( string name, ref ushort value, ushort defaultValue, ushort max )
=> DefaultButton( $"{( _editMode ? "Set to " : "" )}Default: {defaultValue}##imc{name}", ref value, defaultValue )
|| RestrictedInputInt( name, ref value, 0, max );
private static bool CustomCombo< T >( string label, IList< (string, T) > namesAndValues, out T value, ref int idx )
{
value = idx < namesAndValues.Count ? namesAndValues[ idx ].Item2 : default!;
if( !ImGui.BeginCombo( label, idx < namesAndValues.Count ? namesAndValues[ idx ].Item1 : string.Empty ) )
{
return false;
}
for( var i = 0; i < namesAndValues.Count; ++i )
{
if( ImGui.Selectable( $"{namesAndValues[ i ].Item1}##{label}{i}", idx == i ) && idx != i )
{
idx = i;
value = namesAndValues[ i ].Item2;
ImGui.EndCombo();
return true;
}
}
ImGui.EndCombo();
return false;
}
private bool DrawEqpRow( int manipIdx, IList< MetaManipulation > list )
{
var ret = false;
var id = list[ manipIdx ].EqpIdentifier;
var val = list[ manipIdx ].EqpValue;
if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) )
{
var defaults = ( EqpEntry )Service< MetaDefaults >.Get().GetDefaultValue( list[ manipIdx ] )!;
var attributes = id.Slot switch
{
EquipSlot.Head => EqpAttributesHead,
EquipSlot.Body => EqpAttributesBody,
EquipSlot.Hands => EqpAttributesHands,
EquipSlot.Legs => EqpAttributesLegs,
EquipSlot.Feet => EqpAttributesFeet,
_ => Array.Empty< (string, EqpEntry) >(),
};
foreach( var (name, flag) in attributes )
{
var tmp = val.HasFlag( flag );
if( PrintCheckBox( $"{name}##manip", ref tmp, defaults.HasFlag( flag ) ) && _editMode && tmp != val.HasFlag( flag ) )
{
list[ manipIdx ] = MetaManipulation.Eqp( id.Slot, id.SetId, tmp ? val | flag : val & ~flag );
ret = true;
}
}
ImGui.EndPopup();
}
ImGui.Text( ObjectType.Equipment.ToString() );
ImGui.TableNextColumn();
ImGui.Text( id.SetId.ToString() );
ImGui.TableNextColumn();
ImGui.Text( id.Slot.ToString() );
return ret;
}
private bool DrawGmpRow( int manipIdx, IList< MetaManipulation > list )
{
var defaults = ( GmpEntry )Service< MetaDefaults >.Get().GetDefaultValue( list[ manipIdx ] )!;
var ret = false;
var id = list[ manipIdx ].GmpIdentifier;
var val = list[ manipIdx ].GmpValue;
if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) )
{
var enabled = val.Enabled;
var animated = val.Animated;
var rotationA = val.RotationA;
var rotationB = val.RotationB;
var rotationC = val.RotationC;
ushort unk = val.UnknownTotal;
ret |= PrintCheckBox( "Visor Enabled##manip", ref enabled, defaults.Enabled ) && enabled != val.Enabled;
ret |= PrintCheckBox( "Visor Animated##manip", ref animated, defaults.Animated );
ret |= DrawInputWithDefault( "Rotation A##manip", ref rotationA, defaults.RotationA, 0x3FF );
ret |= DrawInputWithDefault( "Rotation B##manip", ref rotationB, defaults.RotationB, 0x3FF );
ret |= DrawInputWithDefault( "Rotation C##manip", ref rotationC, defaults.RotationC, 0x3FF );
ret |= DrawInputWithDefault( "Unknown Byte##manip", ref unk, defaults.UnknownTotal, 0xFF );
if( ret && _editMode )
{
list[ manipIdx ] = MetaManipulation.Gmp( id.SetId,
new GmpEntry
{
Animated = animated, Enabled = enabled, UnknownTotal = ( byte )unk,
RotationA = rotationA, RotationB = rotationB, RotationC = rotationC,
} );
}
ImGui.EndPopup();
}
ImGui.Text( ObjectType.Equipment.ToString() );
ImGui.TableNextColumn();
ImGui.Text( id.SetId.ToString() );
ImGui.TableNextColumn();
ImGui.Text( EquipSlot.Head.ToString() );
return ret;
}
private static (bool, bool) GetEqdpBits( EquipSlot slot, EqdpEntry entry )
{
return slot switch
{
EquipSlot.Head => ( entry.HasFlag( EqdpEntry.Head1 ), entry.HasFlag( EqdpEntry.Head2 ) ),
EquipSlot.Body => ( entry.HasFlag( EqdpEntry.Body1 ), entry.HasFlag( EqdpEntry.Body2 ) ),
EquipSlot.Hands => ( entry.HasFlag( EqdpEntry.Hands1 ), entry.HasFlag( EqdpEntry.Hands2 ) ),
EquipSlot.Legs => ( entry.HasFlag( EqdpEntry.Legs1 ), entry.HasFlag( EqdpEntry.Legs2 ) ),
EquipSlot.Feet => ( entry.HasFlag( EqdpEntry.Feet1 ), entry.HasFlag( EqdpEntry.Feet2 ) ),
EquipSlot.Neck => ( entry.HasFlag( EqdpEntry.Neck1 ), entry.HasFlag( EqdpEntry.Neck2 ) ),
EquipSlot.Ears => ( entry.HasFlag( EqdpEntry.Ears1 ), entry.HasFlag( EqdpEntry.Ears2 ) ),
EquipSlot.Wrists => ( entry.HasFlag( EqdpEntry.Wrists1 ), entry.HasFlag( EqdpEntry.Wrists2 ) ),
EquipSlot.RingR => ( entry.HasFlag( EqdpEntry.RingR1 ), entry.HasFlag( EqdpEntry.RingR2 ) ),
EquipSlot.RingL => ( entry.HasFlag( EqdpEntry.RingL1 ), entry.HasFlag( EqdpEntry.RingL2 ) ),
_ => ( false, false ),
};
}
private static EqdpEntry SetEqdpBits( EquipSlot slot, EqdpEntry value, bool bit1, bool bit2 )
{
switch( slot )
{
case EquipSlot.Head:
value = bit1 ? value | EqdpEntry.Head1 : value & ~EqdpEntry.Head1;
value = bit2 ? value | EqdpEntry.Head2 : value & ~EqdpEntry.Head2;
return value;
case EquipSlot.Body:
value = bit1 ? value | EqdpEntry.Body1 : value & ~EqdpEntry.Body1;
value = bit2 ? value | EqdpEntry.Body2 : value & ~EqdpEntry.Body2;
return value;
case EquipSlot.Hands:
value = bit1 ? value | EqdpEntry.Hands1 : value & ~EqdpEntry.Hands1;
value = bit2 ? value | EqdpEntry.Hands2 : value & ~EqdpEntry.Hands2;
return value;
case EquipSlot.Legs:
value = bit1 ? value | EqdpEntry.Legs1 : value & ~EqdpEntry.Legs1;
value = bit2 ? value | EqdpEntry.Legs2 : value & ~EqdpEntry.Legs2;
return value;
case EquipSlot.Feet:
value = bit1 ? value | EqdpEntry.Feet1 : value & ~EqdpEntry.Feet1;
value = bit2 ? value | EqdpEntry.Feet2 : value & ~EqdpEntry.Feet2;
return value;
case EquipSlot.Neck:
value = bit1 ? value | EqdpEntry.Neck1 : value & ~EqdpEntry.Neck1;
value = bit2 ? value | EqdpEntry.Neck2 : value & ~EqdpEntry.Neck2;
return value;
case EquipSlot.Ears:
value = bit1 ? value | EqdpEntry.Ears1 : value & ~EqdpEntry.Ears1;
value = bit2 ? value | EqdpEntry.Ears2 : value & ~EqdpEntry.Ears2;
return value;
case EquipSlot.Wrists:
value = bit1 ? value | EqdpEntry.Wrists1 : value & ~EqdpEntry.Wrists1;
value = bit2 ? value | EqdpEntry.Wrists2 : value & ~EqdpEntry.Wrists2;
return value;
case EquipSlot.RingR:
value = bit1 ? value | EqdpEntry.RingR1 : value & ~EqdpEntry.RingR1;
value = bit2 ? value | EqdpEntry.RingR2 : value & ~EqdpEntry.RingR2;
return value;
case EquipSlot.RingL:
value = bit1 ? value | EqdpEntry.RingL1 : value & ~EqdpEntry.RingL1;
value = bit2 ? value | EqdpEntry.RingL2 : value & ~EqdpEntry.RingL2;
return value;
}
return value;
}
private bool DrawEqdpRow( int manipIdx, IList< MetaManipulation > list )
{
var defaults = ( EqdpEntry )Service< MetaDefaults >.Get().GetDefaultValue( list[ manipIdx ] )!;
var ret = false;
var id = list[ manipIdx ].EqdpIdentifier;
var val = list[ manipIdx ].EqdpValue;
if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) )
{
var (bit1, bit2) = GetEqdpBits( id.Slot, val );
var (defBit1, defBit2) = GetEqdpBits( id.Slot, defaults );
ret |= PrintCheckBox( "Bit 1##manip", ref bit1, defBit1 );
ret |= PrintCheckBox( "Bit 2##manip", ref bit2, defBit2 );
if( ret && _editMode )
{
list[ manipIdx ] = MetaManipulation.Eqdp( id.Slot, id.GenderRace, id.SetId, SetEqdpBits( id.Slot, val, bit1, bit2 ) );
}
ImGui.EndPopup();
}
ImGui.Text( id.Slot.IsAccessory()
? ObjectType.Accessory.ToString()
: ObjectType.Equipment.ToString() );
ImGui.TableNextColumn();
ImGui.Text( id.SetId.ToString() );
ImGui.TableNextColumn();
ImGui.Text( id.Slot.ToString() );
ImGui.TableNextColumn();
var (gender, race) = id.GenderRace.Split();
ImGui.Text( race.ToString() );
ImGui.TableNextColumn();
ImGui.Text( gender.ToString() );
return ret;
}
private bool DrawEstRow( int manipIdx, IList< MetaManipulation > list )
{
var defaults = ( ushort )Service< MetaDefaults >.Get().GetDefaultValue( list[ manipIdx ] )!;
var ret = false;
var id = list[ manipIdx ].EstIdentifier;
var val = list[ manipIdx ].EstValue;
if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) )
{
if( DrawInputWithDefault( "No Idea what this does!##manip", ref val, defaults, ushort.MaxValue ) && _editMode )
{
list[ manipIdx ] = new MetaManipulation( id.Value, val );
ret = true;
}
ImGui.EndPopup();
}
ImGui.Text( id.ObjectType.ToString() );
ImGui.TableNextColumn();
ImGui.Text( id.PrimaryId.ToString() );
ImGui.TableNextColumn();
ImGui.Text( id.ObjectType == ObjectType.Equipment
? id.EquipSlot.ToString()
: id.BodySlot.ToString() );
ImGui.TableNextColumn();
var (gender, race) = id.GenderRace.Split();
ImGui.Text( race.ToString() );
ImGui.TableNextColumn();
ImGui.Text( gender.ToString() );
return ret;
}
private bool DrawImcRow( int manipIdx, IList< MetaManipulation > list )
{
var defaults = ( ImcFile.ImageChangeData )Service< MetaDefaults >.Get().GetDefaultValue( list[ manipIdx ] )!;
var ret = false;
var id = list[ manipIdx ].ImcIdentifier;
var val = list[ manipIdx ].ImcValue;
if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) )
{
ushort materialId = val.MaterialId;
ushort vfxId = val.VfxId;
ushort decalId = val.DecalId;
var soundId = ( ushort )( val.SoundId >> 10 );
var attributeMask = val.AttributeMask;
var materialAnimationId = ( ushort )( val.MaterialAnimationId >> 12 );
ret |= DrawInputWithDefault( "Material Id", ref materialId, defaults.MaterialId, byte.MaxValue );
ret |= DrawInputWithDefault( "Vfx Id", ref vfxId, defaults.VfxId, byte.MaxValue );
ret |= DrawInputWithDefault( "Decal Id", ref decalId, defaults.DecalId, byte.MaxValue );
ret |= DrawInputWithDefault( "Sound Id", ref soundId, defaults.SoundId, 0x3F );
ret |= DrawInputWithDefault( "Attribute Mask", ref attributeMask, defaults.AttributeMask, 0x3FF );
ret |= DrawInputWithDefault( "Material Animation Id", ref materialAnimationId, defaults.MaterialAnimationId,
byte.MaxValue );
if( ret && _editMode )
{
var value = ImcExtensions.FromValues( ( byte )materialId, ( byte )decalId, attributeMask, ( byte )soundId,
( byte )vfxId, ( byte )materialAnimationId );
list[ manipIdx ] = new MetaManipulation( id.Value, value.ToInteger() );
}
ImGui.EndPopup();
}
ImGui.Text( id.ObjectType.ToString() );
ImGui.TableNextColumn();
ImGui.Text( id.PrimaryId.ToString() );
ImGui.TableNextColumn();
if( id.ObjectType == ObjectType.Accessory
|| id.ObjectType == ObjectType.Equipment )
{
ImGui.Text( id.ObjectType == ObjectType.Equipment
|| id.ObjectType == ObjectType.Accessory
? id.EquipSlot.ToString()
: id.BodySlot.ToString() );
}
ImGui.TableNextColumn();
ImGui.TableNextColumn();
ImGui.TableNextColumn();
if( id.ObjectType != ObjectType.Equipment
&& id.ObjectType != ObjectType.Accessory )
{
ImGui.Text( id.SecondaryId.ToString() );
}
ImGui.TableNextColumn();
ImGui.Text( id.Variant.ToString() );
return ret;
}
private bool DrawRspRow( int manipIdx, IList< MetaManipulation > list )
{
var defaults = ( float )Service< MetaDefaults >.Get().GetDefaultValue( list[ manipIdx ] )!;
var ret = false;
var id = list[ manipIdx ].RspIdentifier;
var val = list[ manipIdx ].RspValue;
if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) )
{
var color = defaults < val ? ColorDarkGreen :
defaults > val ? ColorDarkRed : ImGui.ColorConvertFloat4ToU32( ImGui.GetStyle().Colors[ ( int )ImGuiCol.Button ] );
if( DefaultButton(
$"{( _editMode ? "Set to " : "" )}Default: {defaults:F3}##scaleManip", ref val, defaults )
&& _editMode )
{
list[ manipIdx ] = MetaManipulation.Rsp( id.SubRace, id.Attribute, defaults );
ret = true;
}
ImGui.SetNextItemWidth( 50 );
if( ImGui.InputFloat( "Scale###manip", ref val, 0, 0, "%.3f",
_editMode ? ImGuiInputTextFlags.EnterReturnsTrue : ImGuiInputTextFlags.ReadOnly )
&& val >= 0
&& val <= 5
&& _editMode )
{
list[ manipIdx ] = MetaManipulation.Rsp( id.SubRace, id.Attribute, val );
ret = true;
}
ImGui.EndPopup();
}
ImGui.Text( id.Attribute.ToUngenderedString() );
ImGui.TableNextColumn();
ImGui.TableNextColumn();
ImGui.TableNextColumn();
ImGui.Text( id.SubRace.ToString() );
ImGui.TableNextColumn();
ImGui.Text( id.Attribute.ToGender().ToString() );
return ret;
}
private bool DrawManipulationRow( ref int manipIdx, IList< MetaManipulation > list )
{
var type = list[ manipIdx ].Type;
if( _editMode )
{
ImGui.TableNextColumn();
ImGui.PushFont( UiBuilder.IconFont );
if( ImGui.Button( $"{FontAwesomeIcon.Trash.ToIconString()}##manipDelete{manipIdx}" ) )
{
list.RemoveAt( manipIdx );
ImGui.PopFont();
ImGui.TableNextRow();
--manipIdx;
return true;
}
ImGui.PopFont();
}
ImGui.TableNextColumn();
ImGui.Text( type.ToString() );
ImGui.TableNextColumn();
var changes = false;
switch( type )
{
case MetaType.Eqp:
changes = DrawEqpRow( manipIdx, list );
break;
case MetaType.Gmp:
changes = DrawGmpRow( manipIdx, list );
break;
case MetaType.Eqdp:
changes = DrawEqdpRow( manipIdx, list );
break;
case MetaType.Est:
changes = DrawEstRow( manipIdx, list );
break;
case MetaType.Imc:
changes = DrawImcRow( manipIdx, list );
break;
case MetaType.Rsp:
changes = DrawRspRow( manipIdx, list );
break;
}
ImGui.TableSetColumnIndex( 9 );
if( ImGui.Selectable( $"{list[ manipIdx ].Value}##{manipIdx}" ) )
{
ImGui.OpenPopup( $"##MetaPopup{manipIdx}" );
}
ImGui.TableNextRow();
return changes;
}
private MetaType DrawNewTypeSelection()
{
ImGui.RadioButton( "IMC##newManipType", ref _newManipTypeIdx, 1 );
ImGui.SameLine();
ImGui.RadioButton( "EQDP##newManipType", ref _newManipTypeIdx, 2 );
ImGui.SameLine();
ImGui.RadioButton( "EQP##newManipType", ref _newManipTypeIdx, 3 );
ImGui.SameLine();
ImGui.RadioButton( "EST##newManipType", ref _newManipTypeIdx, 4 );
ImGui.SameLine();
ImGui.RadioButton( "GMP##newManipType", ref _newManipTypeIdx, 5 );
ImGui.SameLine();
ImGui.RadioButton( "RSP##newManipType", ref _newManipTypeIdx, 6 );
return ( MetaType )_newManipTypeIdx;
}
private bool DrawNewManipulationPopup( string popupName, IList< MetaManipulation > list )
{
var change = false;
if( ImGui.BeginPopup( popupName ) )
{
var manipType = DrawNewTypeSelection();
MetaManipulation? newManip = null;
switch( manipType )
{
case MetaType.Imc:
{
RestrictedInputInt( "Set Id##newManipImc", ref _newManipSetId, 0, ushort.MaxValue );
RestrictedInputInt( "Variant##newManipImc", ref _newManipVariant, 0, byte.MaxValue );
CustomCombo( "Object Type", ImcObjectType, out var objectType, ref _newManipObjectType );
EquipSlot equipSlot = default;
switch( objectType )
{
case ObjectType.Equipment:
CustomCombo( "Equipment Slot", EqdpEquipSlots, out equipSlot, ref _newManipEquipSlot );
newManip = MetaManipulation.Imc( equipSlot, _newManipSetId, _newManipVariant,
new ImcFile.ImageChangeData() );
break;
case ObjectType.DemiHuman:
case ObjectType.Weapon:
case ObjectType.Monster:
RestrictedInputInt( "Secondary Id##newManipImc", ref _newManipSecondaryId, 0, ushort.MaxValue );
CustomCombo( "Body Slot", ImcBodySlots, out var bodySlot, ref _newManipBodySlot );
newManip = MetaManipulation.Imc( objectType, bodySlot, _newManipSetId, _newManipSecondaryId,
_newManipVariant, new ImcFile.ImageChangeData() );
break;
}
break;
}
case MetaType.Eqdp:
{
RestrictedInputInt( "Set Id##newManipEqdp", ref _newManipSetId, 0, ushort.MaxValue );
CustomCombo( "Equipment Slot", EqdpEquipSlots, out var equipSlot, ref _newManipEquipSlot );
CustomCombo( "Race", Races, out var race, ref _newManipRace );
CustomCombo( "Gender", Genders, out var gender, ref _newManipGender );
newManip = MetaManipulation.Eqdp( equipSlot, GameData.CombinedRace( gender, race ), ( ushort )_newManipSetId,
new EqdpEntry() );
break;
}
case MetaType.Eqp:
{
RestrictedInputInt( "Set Id##newManipEqp", ref _newManipSetId, 0, ushort.MaxValue );
CustomCombo( "Equipment Slot", EqpEquipSlots, out var equipSlot, ref _newManipEquipSlot );
newManip = MetaManipulation.Eqp( equipSlot, ( ushort )_newManipSetId, 0 );
break;
}
case MetaType.Est:
{
RestrictedInputInt( "Set Id##newManipEst", ref _newManipSetId, 0, ushort.MaxValue );
CustomCombo( "Object Type", ObjectTypes, out var objectType, ref _newManipObjectType );
EquipSlot equipSlot = default;
BodySlot bodySlot = default;
switch( ( ObjectType )_newManipObjectType )
{
case ObjectType.Equipment:
CustomCombo( "Equipment Slot", EstEquipSlots, out equipSlot, ref _newManipEquipSlot );
break;
case ObjectType.Character:
CustomCombo( "Body Slot", EstBodySlots, out bodySlot, ref _newManipBodySlot );
break;
}
CustomCombo( "Race", Races, out var race, ref _newManipRace );
CustomCombo( "Gender", Genders, out var gender, ref _newManipGender );
newManip = MetaManipulation.Est( objectType, equipSlot, GameData.CombinedRace( gender, race ), bodySlot,
( ushort )_newManipSetId, 0 );
break;
}
case MetaType.Gmp:
RestrictedInputInt( "Set Id##newManipGmp", ref _newManipSetId, 0, ushort.MaxValue );
newManip = MetaManipulation.Gmp( ( ushort )_newManipSetId, new GmpEntry() );
break;
case MetaType.Rsp:
CustomCombo( "Subrace", Subraces, out var subRace, ref _newManipSubrace );
CustomCombo( "Attribute", RspAttributes, out var rspAttribute, ref _newManipAttribute );
newManip = MetaManipulation.Rsp( subRace, rspAttribute, 1f );
break;
}
if( ImGui.Button( "Create Manipulation##newManip", Vector2.UnitX * -1 )
&& newManip != null
&& list.All( m => m.Identifier != newManip.Value.Identifier ) )
{
var def = Service< MetaDefaults >.Get().GetDefaultValue( newManip.Value );
if( def != null )
{
var manip = newManip.Value.Type switch
{
MetaType.Est => new MetaManipulation( newManip.Value.Identifier, ( ulong )def ),
MetaType.Eqp => new MetaManipulation( newManip.Value.Identifier, ( ulong )def ),
MetaType.Eqdp => new MetaManipulation( newManip.Value.Identifier, ( ulong )def ),
MetaType.Gmp => new MetaManipulation( newManip.Value.Identifier, ( ulong )def ),
MetaType.Imc => new MetaManipulation( newManip.Value.Identifier,
( ( ImcFile.ImageChangeData )def ).ToInteger() ),
MetaType.Rsp => MetaManipulation.Rsp( newManip.Value.RspIdentifier.SubRace,
newManip.Value.RspIdentifier.Attribute, ( float )def ),
_ => throw new InvalidEnumArgumentException(),
};
list.Add( manip );
change = true;
}
}
ImGui.EndPopup();
}
return change;
}
private bool DrawMetaManipulationsTable( string label, IList< MetaManipulation > list )
{
var numRows = _editMode ? 11 : 10;
var changes = false;
if( list.Count > 0
&& ImGui.BeginTable( label, numRows,
ImGuiTableFlags.BordersInner | ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit ) )
{
if( _editMode )
{
ImGui.TableNextColumn();
}
ImGui.TableNextColumn();
ImGui.TableHeader( $"Type##{label}" );
ImGui.TableNextColumn();
ImGui.TableHeader( $"Object Type##{label}" );
ImGui.TableNextColumn();
ImGui.TableHeader( $"Set##{label}" );
ImGui.TableNextColumn();
ImGui.TableHeader( $"Slot##{label}" );
ImGui.TableNextColumn();
ImGui.TableHeader( $"Race##{label}" );
ImGui.TableNextColumn();
ImGui.TableHeader( $"Gender##{label}" );
ImGui.TableNextColumn();
ImGui.TableHeader( $"Secondary ID##{label}" );
ImGui.TableNextColumn();
ImGui.TableHeader( $"Variant##{label}" );
ImGui.TableNextColumn();
ImGui.TableNextColumn();
ImGui.TableHeader( $"Value##{label}" );
ImGui.TableNextRow();
for( var i = 0; i < list.Count; ++i )
{
changes |= DrawManipulationRow( ref i, list );
}
ImGui.EndTable();
}
var popupName = $"##newManip{label}";
if( _editMode )
{
changes |= DrawNewManipulationPopup( $"##newManip{label}", list );
if( ImGui.Button( $"Add New Manipulation##{label}", Vector2.UnitX * -1 ) )
{
ImGui.OpenPopup( popupName );
}
return changes;
}
return false;
}
}
}
}

View file

@ -430,7 +430,7 @@ namespace Penumbra.UI
{
if( ImGui.Button( ButtonReloadJson ) )
{
_selector.ReloadCurrentMod();
_selector.ReloadCurrentMod( true, false );
}
if( ImGui.IsItemHovered() )
@ -443,13 +443,13 @@ namespace Penumbra.UI
{
if( ImGui.Button( "Recompute Metadata" ) )
{
_selector.ReloadCurrentMod( true );
_selector.ReloadCurrentMod( true, true );
}
if( ImGui.IsItemHovered() )
{
ImGui.SetTooltip(
"Force a recomputation of the metadata_manipulations.json file from all .meta files in the folder.\nAlso reloads the mod." );
"Force a recomputation of the metadata_manipulations.json file from all .meta files in the folder.\nAlso reloads the mod.\nBe aware that this removes all manually added metadata changes." );
}
}

View file

@ -544,14 +544,14 @@ namespace Penumbra.UI
SetSelection( idx );
}
public void ReloadCurrentMod( bool recomputeMeta = false )
public void ReloadCurrentMod( bool reloadMeta = false, bool recomputeMeta = false )
{
if( Mod == null )
{
return;
}
if( _index >= 0 && _modManager.UpdateMod( Mod.Data, recomputeMeta ) )
if( _index >= 0 && _modManager.UpdateMod( Mod.Data, reloadMeta, recomputeMeta ) )
{
ResetModNamesLower();
SelectModByDir( Mod.Data.BasePath.Name );