Add Byte String stuff, remove Services, cleanup and refactor interop stuff, disable path resolver for the moment

This commit is contained in:
Ottermandias 2022-03-06 00:40:42 +01:00
parent 0e8f839471
commit c3454f1d16
65 changed files with 4707 additions and 3371 deletions

View file

@ -1,61 +0,0 @@
using ImGuiNET;
using Penumbra.UI.Custom;
namespace Penumbra.UI
{
public partial class SettingsInterface
{
private class MenuBar
{
private const string MenuLabel = "Penumbra";
private const string MenuItemToggle = "Toggle UI";
private const string SlashCommand = "/penumbra";
private const string MenuItemRediscover = "Rediscover Mods";
private const string MenuItemHide = "Hide Menu Bar";
#if DEBUG
private bool _showDebugBar = true;
#else
private const bool _showDebugBar = false;
#endif
private readonly SettingsInterface _base;
public MenuBar( SettingsInterface ui )
=> _base = ui;
public void Draw()
{
if( !_showDebugBar || !ImGui.BeginMainMenuBar() )
{
return;
}
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndMainMenuBar );
if( !ImGui.BeginMenu( MenuLabel ) )
{
return;
}
raii.Push( ImGui.EndMenu );
if( ImGui.MenuItem( MenuItemToggle, SlashCommand, _base._menu.Visible ) )
{
_base.FlipVisibility();
}
if( ImGui.MenuItem( MenuItemRediscover ) )
{
_base.ReloadMods();
}
#if DEBUG
if( ImGui.MenuItem( MenuItemHide ) )
{
_showDebugBar = false;
}
#endif
}
}
}
}

View file

@ -1,70 +1,65 @@
using System.Collections.Generic;
using System.Linq;
using ImGuiNET;
using Penumbra.Mods;
using Penumbra.UI.Custom;
using Penumbra.Util;
namespace Penumbra.UI
namespace Penumbra.UI;
public partial class SettingsInterface
{
public partial class SettingsInterface
private class TabChangedItems
{
private class TabChangedItems
private const string LabelTab = "Changed Items";
private readonly SettingsInterface _base;
private string _filter = string.Empty;
private string _filterLower = string.Empty;
public TabChangedItems( SettingsInterface ui )
=> _base = ui;
public void Draw()
{
private const string LabelTab = "Changed Items";
private readonly ModManager _modManager;
private readonly SettingsInterface _base;
private string _filter = string.Empty;
private string _filterLower = string.Empty;
public TabChangedItems( SettingsInterface ui )
if( !ImGui.BeginTabItem( LabelTab ) )
{
_base = ui;
_modManager = Service< ModManager >.Get();
return;
}
public void Draw()
var modManager = Penumbra.ModManager;
var items = modManager.Collections.ActiveCollection.Cache?.ChangedItems ?? new Dictionary< string, object? >();
var forced = modManager.Collections.ForcedCollection.Cache?.ChangedItems ?? new Dictionary< string, object? >();
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
ImGui.SetNextItemWidth( -1 );
if( ImGui.InputTextWithHint( "##ChangedItemsFilter", "Filter...", ref _filter, 64 ) )
{
if( !ImGui.BeginTabItem( LabelTab ) )
{
return;
}
var items = _modManager.Collections.ActiveCollection.Cache?.ChangedItems ?? new Dictionary<string, object?>();
var forced = _modManager.Collections.ForcedCollection.Cache?.ChangedItems ?? new Dictionary<string, object?>();
_filterLower = _filter.ToLowerInvariant();
}
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
if( !ImGui.BeginTable( "##ChangedItemsTable", 1, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY, AutoFillSize ) )
{
return;
}
ImGui.SetNextItemWidth( -1 );
if( ImGui.InputTextWithHint( "##ChangedItemsFilter", "Filter...", ref _filter, 64 ) )
{
_filterLower = _filter.ToLowerInvariant();
}
raii.Push( ImGui.EndTable );
if( !ImGui.BeginTable( "##ChangedItemsTable", 1, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY, AutoFillSize ) )
{
return;
}
var list = items.AsEnumerable();
if( forced.Count > 0 )
{
list = list.Concat( forced ).OrderBy( kvp => kvp.Key );
}
raii.Push( ImGui.EndTable );
if( _filter.Any() )
{
list = list.Where( kvp => kvp.Key.ToLowerInvariant().Contains( _filterLower ) );
}
var list = items.AsEnumerable();
if( forced.Count > 0 )
{
list = list.Concat( forced ).OrderBy( kvp => kvp.Key );
}
if( _filter.Any() )
{
list = list.Where( kvp => kvp.Key.ToLowerInvariant().Contains( _filterLower ) );
}
foreach( var (name, data) in list )
{
ImGui.TableNextRow();
ImGui.TableNextColumn();
_base.DrawChangedItem( name, data, ImGui.GetStyle().ScrollbarSize );
}
foreach( var (name, data) in list )
{
ImGui.TableNextRow();
ImGui.TableNextColumn();
_base.DrawChangedItem( name, data, ImGui.GetStyle().ScrollbarSize );
}
}
}

View file

@ -19,7 +19,6 @@ public partial class SettingsInterface
{
private const string CharacterCollectionHelpPopup = "Character Collection Information";
private readonly Selector _selector;
private readonly ModManager _manager;
private string _collectionNames = null!;
private string _collectionNamesWithNone = null!;
private ModCollection[] _collections = null!;
@ -32,7 +31,7 @@ public partial class SettingsInterface
private void UpdateNames()
{
_collections = _manager.Collections.Collections.Values.Prepend( ModCollection.Empty ).ToArray();
_collections = Penumbra.ModManager.Collections.Collections.Values.Prepend( ModCollection.Empty ).ToArray();
_collectionNames = string.Join( "\0", _collections.Skip( 1 ).Select( c => c.Name ) ) + '\0';
_collectionNamesWithNone = "None\0" + _collectionNames;
UpdateIndices();
@ -52,18 +51,18 @@ public partial class SettingsInterface
}
private void UpdateIndex()
=> _currentCollectionIndex = GetIndex( _manager.Collections.CurrentCollection ) - 1;
=> _currentCollectionIndex = GetIndex( Penumbra.ModManager.Collections.CurrentCollection ) - 1;
public void UpdateForcedIndex()
=> _currentForcedIndex = GetIndex( _manager.Collections.ForcedCollection );
=> _currentForcedIndex = GetIndex( Penumbra.ModManager.Collections.ForcedCollection );
public void UpdateDefaultIndex()
=> _currentDefaultIndex = GetIndex( _manager.Collections.DefaultCollection );
=> _currentDefaultIndex = GetIndex( Penumbra.ModManager.Collections.DefaultCollection );
private void UpdateCharacterIndices()
{
_currentCharacterIndices.Clear();
foreach( var kvp in _manager.Collections.CharacterCollection )
foreach( var kvp in Penumbra.ModManager.Collections.CharacterCollection )
{
_currentCharacterIndices[ kvp.Key ] = GetIndex( kvp.Value );
}
@ -80,16 +79,16 @@ public partial class SettingsInterface
public TabCollections( Selector selector )
{
_selector = selector;
_manager = Service< ModManager >.Get();
UpdateNames();
}
private void CreateNewCollection( Dictionary< string, ModSettings > settings )
{
if( _manager.Collections.AddCollection( _newCollectionName, settings ) )
var manager = Penumbra.ModManager;
if( manager.Collections.AddCollection( _newCollectionName, settings ) )
{
UpdateNames();
SetCurrentCollection( _manager.Collections.Collections[ _newCollectionName ], true );
SetCurrentCollection( manager.Collections.Collections[ _newCollectionName ], true );
}
_newCollectionName = string.Empty;
@ -99,9 +98,10 @@ public partial class SettingsInterface
{
if( ImGui.Button( "Clean Settings" ) )
{
var changes = ModFunctions.CleanUpCollection( _manager.Collections.CurrentCollection.Settings,
_manager.BasePath.EnumerateDirectories() );
_manager.Collections.CurrentCollection.UpdateSettings( changes );
var manager = Penumbra.ModManager;
var changes = ModFunctions.CleanUpCollection( manager.Collections.CurrentCollection.Settings,
manager.BasePath.EnumerateDirectories() );
manager.Collections.CurrentCollection.UpdateSettings( changes );
}
ImGuiCustom.HoverTooltip(
@ -126,9 +126,10 @@ public partial class SettingsInterface
var hover = ImGui.IsItemHovered();
ImGui.SameLine();
var manager = Penumbra.ModManager;
if( ImGui.Button( "Duplicate Current Collection" ) && _newCollectionName.Length > 0 )
{
CreateNewCollection( _manager.Collections.CurrentCollection.Settings );
CreateNewCollection( manager.Collections.CurrentCollection.Settings );
}
hover |= ImGui.IsItemHovered();
@ -139,13 +140,13 @@ public partial class SettingsInterface
ImGui.SetTooltip( "Please enter a name before creating a collection." );
}
var deleteCondition = _manager.Collections.Collections.Count > 1
&& _manager.Collections.CurrentCollection.Name != ModCollection.DefaultCollection;
var deleteCondition = manager.Collections.Collections.Count > 1
&& manager.Collections.CurrentCollection.Name != ModCollection.DefaultCollection;
ImGui.SameLine();
if( ImGuiCustom.DisableButton( "Delete Current Collection", deleteCondition ) )
{
_manager.Collections.RemoveCollection( _manager.Collections.CurrentCollection.Name );
SetCurrentCollection( _manager.Collections.CurrentCollection, true );
manager.Collections.RemoveCollection( manager.Collections.CurrentCollection.Name );
SetCurrentCollection( manager.Collections.CurrentCollection, true );
UpdateNames();
}
@ -168,7 +169,7 @@ public partial class SettingsInterface
return;
}
_manager.Collections.SetCurrentCollection( _collections[ idx + 1 ] );
Penumbra.ModManager.Collections.SetCurrentCollection( _collections[ idx + 1 ] );
_currentCollectionIndex = idx;
_selector.Cache.TriggerListReset();
if( _selector.Mod != null )
@ -207,7 +208,7 @@ public partial class SettingsInterface
ImGui.SetNextItemWidth( SettingsMenu.InputTextWidth );
if( ImGui.Combo( "##Default Collection", ref index, _collectionNamesWithNone ) && index != _currentDefaultIndex )
{
_manager.Collections.SetDefaultCollection( _collections[ index ] );
Penumbra.ModManager.Collections.SetDefaultCollection( _collections[ index ] );
_currentDefaultIndex = index;
}
@ -224,17 +225,18 @@ public partial class SettingsInterface
{
var index = _currentForcedIndex;
ImGui.SetNextItemWidth( SettingsMenu.InputTextWidth );
using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.Alpha, 0.5f, _manager.Collections.CharacterCollection.Count == 0 );
var manager = Penumbra.ModManager;
using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.Alpha, 0.5f, manager.Collections.CharacterCollection.Count == 0 );
if( ImGui.Combo( "##Forced Collection", ref index, _collectionNamesWithNone )
&& index != _currentForcedIndex
&& _manager.Collections.CharacterCollection.Count > 0 )
&& index != _currentForcedIndex
&& manager.Collections.CharacterCollection.Count > 0 )
{
_manager.Collections.SetForcedCollection( _collections[ index ] );
manager.Collections.SetForcedCollection( _collections[ index ] );
_currentForcedIndex = index;
}
style.Pop();
if( _manager.Collections.CharacterCollection.Count == 0 && ImGui.IsItemHovered() )
if( manager.Collections.CharacterCollection.Count == 0 && ImGui.IsItemHovered() )
{
ImGui.SetTooltip(
"Forced Collections only provide value if you have at least one Character Collection. There is no need to set one until then." );
@ -260,7 +262,7 @@ public partial class SettingsInterface
if( ImGuiCustom.DisableButton( "Create New Character Collection",
_newCharacterName.Length > 0 && Penumbra.Config.HasReadCharacterCollectionDesc ) )
{
_manager.Collections.CreateCharacterCollection( _newCharacterName );
Penumbra.ModManager.Collections.CreateCharacterCollection( _newCharacterName );
_currentCharacterIndices[ _newCharacterName ] = 0;
_newCharacterName = string.Empty;
}
@ -342,14 +344,15 @@ public partial class SettingsInterface
DrawDefaultCollectionSelector();
DrawForcedCollectionSelector();
foreach( var name in _manager.Collections.CharacterCollection.Keys.ToArray() )
var manager = Penumbra.ModManager;
foreach( var name in manager.Collections.CharacterCollection.Keys.ToArray() )
{
var idx = _currentCharacterIndices[ name ];
var tmp = idx;
ImGui.SetNextItemWidth( SettingsMenu.InputTextWidth );
if( ImGui.Combo( $"##{name}collection", ref tmp, _collectionNamesWithNone ) && idx != tmp )
{
_manager.Collections.SetCharacterCollection( name, _collections[ tmp ] );
manager.Collections.SetCharacterCollection( name, _collections[ tmp ] );
_currentCharacterIndices[ name ] = tmp;
}
@ -360,7 +363,7 @@ public partial class SettingsInterface
using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.FramePadding, Vector2.One * ImGuiHelpers.GlobalScale * 1.5f );
if( ImGui.Button( $"{FontAwesomeIcon.Trash.ToIconString()}##{name}" ) )
{
_manager.Collections.RemoveCharacterCollection( name );
manager.Collections.RemoveCharacterCollection( name );
}
style.Pop();

View file

@ -0,0 +1,131 @@
using System.Runtime.InteropServices;
using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using FFXIVClientStructs.FFXIV.Client.System.Resource;
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
using ImGuiNET;
using Penumbra.UI.Custom;
namespace Penumbra.UI;
public partial class SettingsInterface
{
[StructLayout( LayoutKind.Explicit )]
private unsafe struct RenderModel
{
[FieldOffset( 0x18 )]
public RenderModel* PreviousModel;
[FieldOffset( 0x20 )]
public RenderModel* NextModel;
[FieldOffset( 0x30 )]
public ResourceHandle* ResourceHandle;
[FieldOffset( 0x40 )]
public Skeleton* Skeleton;
[FieldOffset( 0x58 )]
public void** BoneList;
[FieldOffset( 0x60 )]
public int BoneListCount;
[FieldOffset( 0x68 )]
private void* UnkDXBuffer1;
[FieldOffset( 0x70 )]
private void* UnkDXBuffer2;
[FieldOffset( 0x78 )]
private void* UnkDXBuffer3;
[FieldOffset( 0x90 )]
public void** Materials;
[FieldOffset( 0x98 )]
public int MaterialCount;
}
[StructLayout( LayoutKind.Explicit )]
private unsafe struct Material
{
[FieldOffset( 0x10 )]
public ResourceHandle* ResourceHandle;
[FieldOffset( 0x28 )]
public void* MaterialData;
[FieldOffset( 0x48 )]
public Texture* Tex1;
[FieldOffset( 0x60 )]
public Texture* Tex2;
[FieldOffset( 0x78 )]
public Texture* Tex3;
}
private static unsafe void DrawPlayerModelInfo()
{
var player = Dalamud.ClientState.LocalPlayer;
var name = player?.Name.ToString() ?? "NULL";
if( !ImGui.CollapsingHeader( $"Player Model Info: {name}##Draw" ) || player == null )
{
return;
}
var model = ( CharacterBase* )( ( Character* )player.Address )->GameObject.GetDrawObject();
if( model == null )
{
return;
}
if( !ImGui.BeginTable( $"##{name}DrawTable", 5, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit ) )
{
return;
}
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTable );
ImGui.TableNextColumn();
ImGui.TableHeader( "Slot" );
ImGui.TableNextColumn();
ImGui.TableHeader( "Imc Ptr" );
ImGui.TableNextColumn();
ImGui.TableHeader( "Imc File" );
ImGui.TableNextColumn();
ImGui.TableHeader( "Model Ptr" );
ImGui.TableNextColumn();
ImGui.TableHeader( "Model File" );
for( var i = 0; i < model->SlotCount; ++i )
{
var imc = ( ResourceHandle* )model->IMCArray[ i ];
ImGui.TableNextRow();
ImGui.TableNextColumn();
ImGui.Text( $"Slot {i}" );
ImGui.TableNextColumn();
ImGui.Text( imc == null ? "NULL" : $"0x{( ulong )imc:X}" );
ImGui.TableNextColumn();
if( imc != null )
{
ImGui.Text( imc->FileName.ToString() );
}
var mdl = ( RenderModel* )model->ModelArray[ i ];
ImGui.TableNextColumn();
ImGui.Text( mdl == null ? "NULL" : $"0x{( ulong )mdl:X}" );
if( mdl == null || mdl->ResourceHandle == null || mdl->ResourceHandle->Category != ResourceCategory.Chara )
{
continue;
}
ImGui.TableNextColumn();
if( mdl != null )
{
ImGui.Text( mdl->ResourceHandle->FileName.ToString() );
}
}
}
}

View file

@ -1,13 +1,17 @@
using System;
using System.Collections.Generic;
using System.Drawing.Text;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Reflection;
using System.Runtime.InteropServices;
using Dalamud.Game.ClientState.Objects.Types;
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
using FFXIVClientStructs.FFXIV.Client.System.String;
using ImGuiNET;
using Penumbra.Api;
using Penumbra.GameData.ByteString;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
using Penumbra.GameData.Util;
@ -16,6 +20,8 @@ using Penumbra.Meta;
using Penumbra.Mods;
using Penumbra.UI.Custom;
using Penumbra.Util;
using ResourceHandle = Penumbra.Interop.Structs.ResourceHandle;
using Utf8String = Penumbra.GameData.ByteString.Utf8String;
namespace Penumbra.UI;
@ -143,7 +149,7 @@ public partial class SettingsInterface
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTable );
var manager = Service< ModManager >.Get();
var manager = Penumbra.ModManager;
PrintValue( "Active Collection", manager.Collections.ActiveCollection.Name );
PrintValue( " has Cache", ( manager.Collections.ActiveCollection.Cache != null ).ToString() );
PrintValue( "Current Collection", manager.Collections.CurrentCollection.Name );
@ -164,7 +170,7 @@ public partial class SettingsInterface
PrintValue( "Mod Manager Temp Path Exists",
manager.TempPath != null ? Directory.Exists( manager.TempPath.FullName ).ToString() : false.ToString() );
PrintValue( "Mod Manager Temp Path IsWritable", manager.TempWritable.ToString() );
PrintValue( "Resource Loader Enabled", _penumbra.ResourceLoader.IsEnabled.ToString() );
//PrintValue( "Resource Loader Enabled", _penumbra.ResourceLoader.IsEnabled.ToString() );
}
private void DrawDebugTabRedraw()
@ -281,7 +287,7 @@ public partial class SettingsInterface
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTable );
foreach( var collection in Service< ModManager >.Get().Collections.Collections.Values.Where( c => c.Cache != null ) )
foreach( var collection in Penumbra.ModManager.Collections.Collections.Values.Where( c => c.Cache != null ) )
{
var manip = collection.Cache!.MetaManipulations;
var files = ( Dictionary< GamePath, MetaManager.FileInformation >? )manip.GetType()
@ -363,8 +369,7 @@ public partial class SettingsInterface
return;
}
var manager = Service< ModManager >.Get();
var cache = manager.Collections.CurrentCollection.Cache;
var cache = Penumbra.ModManager.Collections.CurrentCollection.Cache;
if( cache == null || !ImGui.BeginTable( "##MissingFilesDebugList", 1, ImGuiTableFlags.RowBg, -Vector2.UnitX ) )
{
return;
@ -385,6 +390,86 @@ public partial class SettingsInterface
}
}
private unsafe void DrawDebugTabReplacedResources()
{
if( !ImGui.CollapsingHeader( "Replaced Resources##Debug" ) )
{
return;
}
_penumbra.ResourceLoader.UpdateDebugInfo();
if( _penumbra.ResourceLoader.DebugList.Count == 0
|| !ImGui.BeginTable( "##ReplacedResourcesDebugList", 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit, -Vector2.UnitX ) )
{
return;
}
using var end = ImGuiRaii.DeferredEnd( ImGui.EndTable );
foreach( var data in _penumbra.ResourceLoader.DebugList.Values.ToArray() )
{
var refCountManip = data.ManipulatedResource == null ? 0 : data.ManipulatedResource->RefCount;
var refCountOrig = data.OriginalResource == null ? 0 : data.OriginalResource->RefCount;
ImGui.TableNextColumn();
ImGui.Text( data.ManipulatedPath.ToString() );
ImGui.TableNextColumn();
ImGui.Text( ( ( ulong )data.ManipulatedResource ).ToString( "X" ) );
ImGui.TableNextColumn();
ImGui.Text( refCountManip.ToString() );
ImGui.TableNextColumn();
ImGui.Text( data.OriginalPath.ToString() );
ImGui.TableNextColumn();
ImGui.Text( ( ( ulong )data.OriginalResource ).ToString( "X" ) );
ImGui.TableNextColumn();
ImGui.Text( refCountOrig.ToString() );
}
}
private unsafe void DrawPathResolverDebug()
{
if( !ImGui.CollapsingHeader( "Path Resolver##Debug" ) )
{
return;
}
//if( ImGui.TreeNodeEx( "Draw Object to Object" ) )
//{
// using var end = ImGuiRaii.DeferredEnd( ImGui.TreePop );
// if( ImGui.BeginTable( "###DrawObjectResolverTable", 4, ImGuiTableFlags.SizingFixedFit ) )
// {
// end.Push( ImGui.EndTable );
// foreach( var (ptr, idx) in _penumbra.PathResolver._drawObjectToObject )
// {
// ImGui.TableNextColumn();
// ImGui.Text( ptr.ToString( "X" ) );
// ImGui.TableNextColumn();
// ImGui.Text( idx.ToString() );
// ImGui.TableNextColumn();
// ImGui.Text( Dalamud.Objects[ idx ]?.Address.ToString() ?? "NULL" );
// ImGui.TableNextColumn();
// ImGui.Text( Dalamud.Objects[ idx ]?.Name.ToString() ?? "NULL" );
// }
// }
//}
//
//if( ImGui.TreeNodeEx( "Path Collections" ) )
//{
// using var end = ImGuiRaii.DeferredEnd( ImGui.TreePop );
// if( ImGui.BeginTable( "###PathCollectionResolverTable", 2, ImGuiTableFlags.SizingFixedFit ) )
// {
// end.Push( ImGui.EndTable );
// foreach( var (path, collection) in _penumbra.PathResolver._pathCollections )
// {
// ImGui.TableNextColumn();
// ImGuiNative.igTextUnformatted( path.Path, path.Path + path.Length );
// ImGui.TableNextColumn();
// ImGui.Text( collection.Name );
// }
// }
//}
}
private void DrawDebugTab()
{
if( !ImGui.BeginTabItem( "Debug Tab" ) )
@ -396,8 +481,16 @@ public partial class SettingsInterface
DrawDebugTabGeneral();
ImGui.NewLine();
DrawDebugTabReplacedResources();
ImGui.NewLine();
DrawResourceProblems();
ImGui.NewLine();
DrawDebugTabMissingFiles();
ImGui.NewLine();
DrawPlayerModelInfo();
ImGui.NewLine();
DrawPathResolverDebug();
ImGui.NewLine();
DrawDebugTabRedraw();
ImGui.NewLine();
DrawDebugTabPlayers();

View file

@ -1,148 +0,0 @@
using System;
using System.Runtime.InteropServices;
using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using FFXIVClientStructs.FFXIV.Client.System.Resource;
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
using ImGuiNET;
using Lumina.Models.Models;
using Penumbra.UI.Custom;
using DalamudCharacter = Dalamud.Game.ClientState.Objects.Types.Character;
namespace Penumbra.UI
{
public partial class SettingsInterface
{
[StructLayout( LayoutKind.Explicit )]
private unsafe struct RenderModel
{
[FieldOffset(0x18)]
public RenderModel* PreviousModel;
[FieldOffset( 0x20 )]
public RenderModel* NextModel;
[FieldOffset( 0x30 )]
public ResourceHandle* ResourceHandle;
[FieldOffset( 0x40 )]
public Skeleton* Skeleton;
[FieldOffset( 0x58 )]
public void** BoneList;
[FieldOffset( 0x60 )]
public int BoneListCount;
[FieldOffset( 0x68 )]
private void* UnkDXBuffer1;
[FieldOffset( 0x70 )]
private void* UnkDXBuffer2;
[FieldOffset( 0x78 )]
private void* UnkDXBuffer3;
[FieldOffset( 0x90 )]
public void** Materials;
[FieldOffset( 0x98 )]
public int MaterialCount;
}
[StructLayout( LayoutKind.Explicit )]
private unsafe struct Material
{
[FieldOffset(0x10)]
public ResourceHandle* ResourceHandle;
[FieldOffset(0x28)]
public void* MaterialData;
[FieldOffset( 0x48 )]
public Texture* Tex1;
[FieldOffset( 0x60 )]
public Texture* Tex2;
[FieldOffset( 0x78 )]
public Texture* Tex3;
}
private static unsafe void DrawPlayerModelInfo( DalamudCharacter character )
{
var name = character.Name.ToString();
if( !ImGui.CollapsingHeader( $"{name}##Draw" ) )
{
return;
}
var model = ( CharacterBase* )( ( Character* )character.Address )->GameObject.GetDrawObject();
if( model == null )
{
return;
}
if( !ImGui.BeginTable( $"##{name}DrawTable", 5, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit ) )
{
return;
}
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTable );
ImGui.TableNextColumn();
ImGui.TableHeader( "Slot" );
ImGui.TableNextColumn();
ImGui.TableHeader( "Imc Ptr" );
ImGui.TableNextColumn();
ImGui.TableHeader( "Imc File" );
ImGui.TableNextColumn();
ImGui.TableHeader( "Model Ptr" );
ImGui.TableNextColumn();
ImGui.TableHeader( "Model File" );
for( var i = 0; i < model->SlotCount; ++i )
{
var imc = ( ResourceHandle* )model->IMCArray[ i ];
ImGui.TableNextRow();
ImGui.TableNextColumn();
ImGui.Text( $"Slot {i}" );
ImGui.TableNextColumn();
ImGui.Text( imc == null ? "NULL" : $"0x{( ulong )imc:X}" );
ImGui.TableNextColumn();
if( imc != null )
{
ImGui.Text( imc->FileName.ToString() );
}
var mdl = ( RenderModel* )model->ModelArray[ i ];
ImGui.TableNextColumn();
ImGui.Text( mdl == null ? "NULL" : $"0x{( ulong )mdl:X}" );
if( mdl == null || mdl->ResourceHandle == null || mdl->ResourceHandle->Category != ResourceCategory.Chara )
{
continue;
}
ImGui.TableNextColumn();
if( mdl != null )
{
ImGui.Text( mdl->ResourceHandle->FileName.ToString() );
}
}
}
private void DrawPlayerModelTab()
{
if( !ImGui.BeginTabItem( "Model Debug" ) )
{
return;
}
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
var player = Dalamud.ClientState.LocalPlayer;
if( player == null )
{
return;
}
DrawPlayerModelInfo( player );
}
}
}

View file

@ -3,215 +3,210 @@ using System.IO;
using System.Linq;
using Dalamud.Interface;
using ImGuiNET;
using Penumbra.GameData.ByteString;
using Penumbra.GameData.Util;
using Penumbra.Mods;
using Penumbra.UI.Custom;
using Penumbra.Util;
namespace Penumbra.UI
namespace Penumbra.UI;
public partial class SettingsInterface
{
public partial class SettingsInterface
private class TabEffective
{
private class TabEffective
private const string LabelTab = "Effective Changes";
private string _gamePathFilter = string.Empty;
private string _gamePathFilterLower = string.Empty;
private string _filePathFilter = string.Empty;
private string _filePathFilterLower = string.Empty;
private readonly float _leftTextLength =
ImGui.CalcTextSize( "chara/human/c0000/obj/body/b0000/material/v0000/mt_c0000b0000_b.mtrl" ).X / ImGuiHelpers.GlobalScale + 40;
private float _arrowLength = 0;
private static void DrawLine( string path, string name )
{
private const string LabelTab = "Effective Changes";
private readonly ModManager _modManager;
ImGui.TableNextColumn();
ImGuiCustom.CopyOnClickSelectable( path );
private string _gamePathFilter = string.Empty;
private string _gamePathFilterLower = string.Empty;
private string _filePathFilter = string.Empty;
private string _filePathFilterLower = string.Empty;
ImGui.TableNextColumn();
ImGuiCustom.PrintIcon( FontAwesomeIcon.LongArrowAltLeft );
ImGui.SameLine();
ImGuiCustom.CopyOnClickSelectable( name );
}
private readonly float _leftTextLength =
ImGui.CalcTextSize( "chara/human/c0000/obj/body/b0000/material/v0000/mt_c0000b0000_b.mtrl" ).X / ImGuiHelpers.GlobalScale + 40;
private float _arrowLength = 0;
public TabEffective()
=> _modManager = Service< ModManager >.Get();
private static void DrawLine( string path, string name )
private void DrawFilters()
{
if( _arrowLength == 0 )
{
ImGui.TableNextColumn();
ImGuiCustom.CopyOnClickSelectable( path );
ImGui.TableNextColumn();
ImGuiCustom.PrintIcon( FontAwesomeIcon.LongArrowAltLeft );
ImGui.SameLine();
ImGuiCustom.CopyOnClickSelectable( name );
using var font = ImGuiRaii.PushFont( UiBuilder.IconFont );
_arrowLength = ImGui.CalcTextSize( FontAwesomeIcon.LongArrowAltLeft.ToIconString() ).X / ImGuiHelpers.GlobalScale;
}
private void DrawFilters()
ImGui.SetNextItemWidth( _leftTextLength * ImGuiHelpers.GlobalScale );
if( ImGui.InputTextWithHint( "##effective_changes_gfilter", "Filter game path...", ref _gamePathFilter, 256 ) )
{
if( _arrowLength == 0 )
_gamePathFilterLower = _gamePathFilter.ToLowerInvariant();
}
ImGui.SameLine( ( _leftTextLength + _arrowLength ) * ImGuiHelpers.GlobalScale + 3 * ImGui.GetStyle().ItemSpacing.X );
ImGui.SetNextItemWidth( -1 );
if( ImGui.InputTextWithHint( "##effective_changes_ffilter", "Filter file path...", ref _filePathFilter, 256 ) )
{
_filePathFilterLower = _filePathFilter.ToLowerInvariant();
}
}
private bool CheckFilters( KeyValuePair< GamePath, FullPath > kvp )
{
if( _gamePathFilter.Any() && !kvp.Key.ToString().Contains( _gamePathFilterLower ) )
{
return false;
}
return !_filePathFilter.Any() || kvp.Value.FullName.ToLowerInvariant().Contains( _filePathFilterLower );
}
private bool CheckFilters( KeyValuePair< GamePath, GamePath > kvp )
{
if( _gamePathFilter.Any() && !kvp.Key.ToString().Contains( _gamePathFilterLower ) )
{
return false;
}
return !_filePathFilter.Any() || kvp.Value.ToString().Contains( _filePathFilterLower );
}
private bool CheckFilters( (string, string, string) kvp )
{
if( _gamePathFilter.Any() && !kvp.Item1.ToLowerInvariant().Contains( _gamePathFilterLower ) )
{
return false;
}
return !_filePathFilter.Any() || kvp.Item3.Contains( _filePathFilterLower );
}
private void DrawFilteredRows( ModCollectionCache? active, ModCollectionCache? forced )
{
void DrawFileLines( ModCollectionCache cache )
{
foreach( var (gp, fp) in cache.ResolvedFiles.Where( CheckFilters ) )
{
using var font = ImGuiRaii.PushFont( UiBuilder.IconFont );
_arrowLength = ImGui.CalcTextSize( FontAwesomeIcon.LongArrowAltLeft.ToIconString() ).X / ImGuiHelpers.GlobalScale;
DrawLine( gp, fp.FullName );
}
ImGui.SetNextItemWidth( _leftTextLength * ImGuiHelpers.GlobalScale );
if( ImGui.InputTextWithHint( "##effective_changes_gfilter", "Filter game path...", ref _gamePathFilter, 256 ) )
foreach( var (gp, fp) in cache.SwappedFiles.Where( CheckFilters ) )
{
_gamePathFilterLower = _gamePathFilter.ToLowerInvariant();
DrawLine( gp, fp );
}
ImGui.SameLine( ( _leftTextLength + _arrowLength ) * ImGuiHelpers.GlobalScale + 3 * ImGui.GetStyle().ItemSpacing.X );
ImGui.SetNextItemWidth( -1 );
if( ImGui.InputTextWithHint( "##effective_changes_ffilter", "Filter file path...", ref _filePathFilter, 256 ) )
foreach( var (mp, mod, _) in cache.MetaManipulations.Manipulations
.Select( p => ( p.Item1.IdentifierString(), p.Item2.Data.Meta.Name, p.Item2.Data.Meta.LowerName ) )
.Where( CheckFilters ) )
{
_filePathFilterLower = _filePathFilter.ToLowerInvariant();
DrawLine( mp, mod );
}
}
private bool CheckFilters( KeyValuePair< GamePath, FullPath > kvp )
if( active != null )
{
if( _gamePathFilter.Any() && !kvp.Key.ToString().Contains( _gamePathFilterLower ) )
{
return false;
}
return !_filePathFilter.Any() || kvp.Value.FullName.ToLowerInvariant().Contains( _filePathFilterLower );
DrawFileLines( active );
}
private bool CheckFilters( KeyValuePair< GamePath, GamePath > kvp )
if( forced != null )
{
if( _gamePathFilter.Any() && !kvp.Key.ToString().Contains( _gamePathFilterLower ) )
{
return false;
}
DrawFileLines( forced );
}
}
return !_filePathFilter.Any() || kvp.Value.ToString().Contains( _filePathFilterLower );
public void Draw()
{
if( !ImGui.BeginTabItem( LabelTab ) )
{
return;
}
private bool CheckFilters( (string, string, string) kvp )
{
if( _gamePathFilter.Any() && !kvp.Item1.ToLowerInvariant().Contains( _gamePathFilterLower ) )
{
return false;
}
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
return !_filePathFilter.Any() || kvp.Item3.Contains( _filePathFilterLower );
DrawFilters();
const ImGuiTableFlags flags = ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollX;
var modManager = Penumbra.ModManager;
var activeCollection = modManager.Collections.ActiveCollection.Cache;
var forcedCollection = modManager.Collections.ForcedCollection.Cache;
var (activeResolved, activeSwap, activeMeta) = activeCollection != null
? ( activeCollection.ResolvedFiles.Count, activeCollection.SwappedFiles.Count, activeCollection.MetaManipulations.Count )
: ( 0, 0, 0 );
var (forcedResolved, forcedSwap, forcedMeta) = forcedCollection != null
? ( forcedCollection.ResolvedFiles.Count, forcedCollection.SwappedFiles.Count, forcedCollection.MetaManipulations.Count )
: ( 0, 0, 0 );
var totalLines = activeResolved + forcedResolved + activeSwap + forcedSwap + activeMeta + forcedMeta;
if( totalLines == 0 )
{
return;
}
private void DrawFilteredRows( ModCollectionCache? active, ModCollectionCache? forced )
if( ImGui.BeginTable( "##effective_changes", 2, flags, AutoFillSize ) )
{
void DrawFileLines( ModCollectionCache cache )
raii.Push( ImGui.EndTable );
ImGui.TableSetupColumn( "##tableGamePathCol", ImGuiTableColumnFlags.None, _leftTextLength * ImGuiHelpers.GlobalScale );
if( _filePathFilter.Any() || _gamePathFilter.Any() )
{
foreach( var (gp, fp) in cache.ResolvedFiles.Where( CheckFilters ) )
DrawFilteredRows( activeCollection, forcedCollection );
}
else
{
ImGuiListClipperPtr clipper;
unsafe
{
DrawLine( gp, fp.FullName );
clipper = new ImGuiListClipperPtr( ImGuiNative.ImGuiListClipper_ImGuiListClipper() );
}
foreach( var (gp, fp) in cache.SwappedFiles.Where( CheckFilters ) )
clipper.Begin( totalLines );
while( clipper.Step() )
{
DrawLine( gp, fp );
}
foreach( var (mp, mod, _) in cache.MetaManipulations.Manipulations
.Select( p => ( p.Item1.IdentifierString(), p.Item2.Data.Meta.Name, p.Item2.Data.Meta.LowerName ) )
.Where( CheckFilters ) )
{
DrawLine( mp, mod );
}
}
if( active != null )
{
DrawFileLines( active );
}
if( forced != null )
{
DrawFileLines( forced );
}
}
public void Draw()
{
if( !ImGui.BeginTabItem( LabelTab ) )
{
return;
}
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
DrawFilters();
const ImGuiTableFlags flags = ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollX;
var activeCollection = _modManager.Collections.ActiveCollection.Cache;
var forcedCollection = _modManager.Collections.ForcedCollection.Cache;
var (activeResolved, activeSwap, activeMeta) = activeCollection != null
? ( activeCollection.ResolvedFiles.Count, activeCollection.SwappedFiles.Count, activeCollection.MetaManipulations.Count )
: ( 0, 0, 0 );
var (forcedResolved, forcedSwap, forcedMeta) = forcedCollection != null
? ( forcedCollection.ResolvedFiles.Count, forcedCollection.SwappedFiles.Count, forcedCollection.MetaManipulations.Count )
: ( 0, 0, 0 );
var totalLines = activeResolved + forcedResolved + activeSwap + forcedSwap + activeMeta + forcedMeta;
if( totalLines == 0 )
{
return;
}
if( ImGui.BeginTable( "##effective_changes", 2, flags, AutoFillSize ) )
{
raii.Push( ImGui.EndTable );
ImGui.TableSetupColumn( "##tableGamePathCol", ImGuiTableColumnFlags.None, _leftTextLength * ImGuiHelpers.GlobalScale );
if( _filePathFilter.Any() || _gamePathFilter.Any() )
{
DrawFilteredRows( activeCollection, forcedCollection );
}
else
{
ImGuiListClipperPtr clipper;
unsafe
for( var actualRow = clipper.DisplayStart; actualRow < clipper.DisplayEnd; actualRow++ )
{
clipper = new ImGuiListClipperPtr( ImGuiNative.ImGuiListClipper_ImGuiListClipper() );
}
clipper.Begin( totalLines );
while( clipper.Step() )
{
for( var actualRow = clipper.DisplayStart; actualRow < clipper.DisplayEnd; actualRow++ )
var row = actualRow;
ImGui.TableNextRow();
if( row < activeResolved )
{
var row = actualRow;
ImGui.TableNextRow();
if( row < activeResolved )
{
var (gamePath, file) = activeCollection!.ResolvedFiles.ElementAt( row );
DrawLine( gamePath, file.FullName );
}
else if( ( row -= activeResolved ) < activeSwap )
{
var (gamePath, swap) = activeCollection!.SwappedFiles.ElementAt( row );
DrawLine( gamePath, swap );
}
else if( ( row -= activeSwap ) < activeMeta )
{
var (manip, mod) = activeCollection!.MetaManipulations.Manipulations.ElementAt( row );
DrawLine( manip.IdentifierString(), mod.Data.Meta.Name );
}
else if( ( row -= activeMeta ) < forcedResolved )
{
var (gamePath, file) = forcedCollection!.ResolvedFiles.ElementAt( row );
DrawLine( gamePath, file.FullName );
}
else if( ( row -= forcedResolved ) < forcedSwap )
{
var (gamePath, swap) = forcedCollection!.SwappedFiles.ElementAt( row );
DrawLine( gamePath, swap );
}
else
{
row -= forcedSwap;
var (manip, mod) = forcedCollection!.MetaManipulations.Manipulations.ElementAt( row );
DrawLine( manip.IdentifierString(), mod.Data.Meta.Name );
}
var (gamePath, file) = activeCollection!.ResolvedFiles.ElementAt( row );
DrawLine( gamePath, file.FullName );
}
else if( ( row -= activeResolved ) < activeSwap )
{
var (gamePath, swap) = activeCollection!.SwappedFiles.ElementAt( row );
DrawLine( gamePath, swap );
}
else if( ( row -= activeSwap ) < activeMeta )
{
var (manip, mod) = activeCollection!.MetaManipulations.Manipulations.ElementAt( row );
DrawLine( manip.IdentifierString(), mod.Data.Meta.Name );
}
else if( ( row -= activeMeta ) < forcedResolved )
{
var (gamePath, file) = forcedCollection!.ResolvedFiles.ElementAt( row );
DrawLine( gamePath, file.FullName );
}
else if( ( row -= forcedResolved ) < forcedSwap )
{
var (gamePath, swap) = forcedCollection!.SwappedFiles.ElementAt( row );
DrawLine( gamePath, swap );
}
else
{
row -= forcedSwap;
var (manip, mod) = forcedCollection!.MetaManipulations.Manipulations.ElementAt( row );
DrawLine( manip.IdentifierString(), mod.Data.Meta.Name );
}
}
}
@ -219,5 +214,4 @@ namespace Penumbra.UI
}
}
}
}
}

View file

@ -8,188 +8,182 @@ using System.Windows.Forms;
using Dalamud.Logging;
using ImGuiNET;
using Penumbra.Importer;
using Penumbra.Mods;
using Penumbra.UI.Custom;
using Penumbra.Util;
namespace Penumbra.UI
namespace Penumbra.UI;
public partial class SettingsInterface
{
public partial class SettingsInterface
private class TabImport
{
private class TabImport
private const string LabelTab = "Import Mods";
private const string LabelImportButton = "Import TexTools Modpacks";
private const string LabelFileDialog = "Pick one or more modpacks.";
private const string LabelFileImportRunning = "Import in progress...";
private const string FileTypeFilter = "TexTools TTMP Modpack (*.ttmp2)|*.ttmp*|All files (*.*)|*.*";
private const string TooltipModpack1 = "Writing modpack to disk before extracting...";
private const uint ColorRed = 0xFF0000C8;
private const uint ColorYellow = 0xFF00C8C8;
private static readonly Vector2 ImportBarSize = new(-1, 0);
private bool _isImportRunning;
private string _errorMessage = string.Empty;
private TexToolsImport? _texToolsImport;
private readonly SettingsInterface _base;
public readonly HashSet< string > NewMods = new();
public TabImport( SettingsInterface ui )
=> _base = ui;
public bool IsImporting()
=> _isImportRunning;
private void RunImportTask()
{
private const string LabelTab = "Import Mods";
private const string LabelImportButton = "Import TexTools Modpacks";
private const string LabelFileDialog = "Pick one or more modpacks.";
private const string LabelFileImportRunning = "Import in progress...";
private const string FileTypeFilter = "TexTools TTMP Modpack (*.ttmp2)|*.ttmp*|All files (*.*)|*.*";
private const string TooltipModpack1 = "Writing modpack to disk before extracting...";
private const uint ColorRed = 0xFF0000C8;
private const uint ColorYellow = 0xFF00C8C8;
private static readonly Vector2 ImportBarSize = new( -1, 0 );
private bool _isImportRunning;
private string _errorMessage = string.Empty;
private TexToolsImport? _texToolsImport;
private readonly SettingsInterface _base;
private readonly ModManager _manager;
public readonly HashSet< string > NewMods = new();
public TabImport( SettingsInterface ui )
_isImportRunning = true;
Task.Run( async () =>
{
_base = ui;
_manager = Service< ModManager >.Get();
}
public bool IsImporting()
=> _isImportRunning;
private void RunImportTask()
{
_isImportRunning = true;
Task.Run( async () =>
try
{
try
var picker = new OpenFileDialog
{
var picker = new OpenFileDialog
Multiselect = true,
Filter = FileTypeFilter,
CheckFileExists = true,
Title = LabelFileDialog,
};
var result = await picker.ShowDialogAsync();
if( result == DialogResult.OK )
{
_errorMessage = string.Empty;
foreach( var fileName in picker.FileNames )
{
Multiselect = true,
Filter = FileTypeFilter,
CheckFileExists = true,
Title = LabelFileDialog,
};
PluginLog.Information( $"-> {fileName} START" );
var result = await picker.ShowDialogAsync();
if( result == DialogResult.OK )
{
_errorMessage = string.Empty;
foreach( var fileName in picker.FileNames )
try
{
PluginLog.Information( $"-> {fileName} START" );
try
_texToolsImport = new TexToolsImport( Penumbra.ModManager.BasePath );
var dir = _texToolsImport.ImportModPack( new FileInfo( fileName ) );
if( dir.Name.Any() )
{
_texToolsImport = new TexToolsImport( _manager.BasePath );
var dir = _texToolsImport.ImportModPack( new FileInfo( fileName ) );
if( dir.Name.Any() )
{
NewMods.Add( dir.Name );
}
NewMods.Add( dir.Name );
}
PluginLog.Information( $"-> {fileName} OK!" );
}
catch( Exception ex )
{
PluginLog.LogError( ex, "Failed to import modpack at {0}", fileName );
_errorMessage = ex.Message;
}
PluginLog.Information( $"-> {fileName} OK!" );
}
var directory = _texToolsImport?.ExtractedDirectory;
_texToolsImport = null;
_base.ReloadMods();
if( directory != null )
catch( Exception ex )
{
_base._menu.InstalledTab.Selector.SelectModOnUpdate( directory.Name );
PluginLog.LogError( ex, "Failed to import modpack at {0}", fileName );
_errorMessage = ex.Message;
}
}
var directory = _texToolsImport?.ExtractedDirectory;
_texToolsImport = null;
_base.ReloadMods();
if( directory != null )
{
_base._menu.InstalledTab.Selector.SelectModOnUpdate( directory.Name );
}
}
catch( Exception e )
{
PluginLog.Error( $"Error opening file picker dialogue:\n{e}" );
}
}
catch( Exception e )
{
PluginLog.Error( $"Error opening file picker dialogue:\n{e}" );
}
_isImportRunning = false;
} );
}
_isImportRunning = false;
} );
}
private void DrawImportButton()
private void DrawImportButton()
{
if( !Penumbra.ModManager.Valid )
{
if( !_manager.Valid )
{
using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.Alpha, 0.5f );
ImGui.Button( LabelImportButton );
style.Pop();
using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.Alpha, 0.5f );
ImGui.Button( LabelImportButton );
style.Pop();
using var color = ImGuiRaii.PushColor( ImGuiCol.Text, ColorRed );
ImGui.Text( "Can not import since the mod directory path is not valid." );
ImGui.Dummy( Vector2.UnitY * ImGui.GetTextLineHeightWithSpacing() );
color.Pop();
ImGui.Text( "Please set the mod directory in the settings tab." );
ImGui.Text( "This folder should preferably be close to the root directory of your (preferably SSD) drive, for example" );
color.Push( ImGuiCol.Text, ColorYellow );
ImGui.Text( " D:\\ffxivmods" );
color.Pop();
ImGui.Text( "You can return to this tab once you've done that." );
}
else if( ImGui.Button( LabelImportButton ) )
{
RunImportTask();
}
}
private void DrawImportProgress()
{
ImGui.Button( LabelFileImportRunning );
if( _texToolsImport == null )
{
return;
}
switch( _texToolsImport.State )
{
case ImporterState.None: break;
case ImporterState.WritingPackToDisk:
ImGui.Text( TooltipModpack1 );
break;
case ImporterState.ExtractingModFiles:
{
var str =
$"{_texToolsImport.CurrentModPack} - {_texToolsImport.CurrentProgress} of {_texToolsImport.TotalProgress} files";
ImGui.ProgressBar( _texToolsImport.Progress, ImportBarSize, str );
break;
}
case ImporterState.Done: break;
default: throw new ArgumentOutOfRangeException();
}
}
private void DrawFailedImportMessage()
{
using var color = ImGuiRaii.PushColor( ImGuiCol.Text, ColorRed );
ImGui.Text( $"One or more of your modpacks failed to import:\n\t\t{_errorMessage}" );
ImGui.Text( "Can not import since the mod directory path is not valid." );
ImGui.Dummy( Vector2.UnitY * ImGui.GetTextLineHeightWithSpacing() );
color.Pop();
ImGui.Text( "Please set the mod directory in the settings tab." );
ImGui.Text( "This folder should preferably be close to the root directory of your (preferably SSD) drive, for example" );
color.Push( ImGuiCol.Text, ColorYellow );
ImGui.Text( " D:\\ffxivmods" );
color.Pop();
ImGui.Text( "You can return to this tab once you've done that." );
}
else if( ImGui.Button( LabelImportButton ) )
{
RunImportTask();
}
}
private void DrawImportProgress()
{
ImGui.Button( LabelFileImportRunning );
if( _texToolsImport == null )
{
return;
}
public void Draw()
switch( _texToolsImport.State )
{
if( !ImGui.BeginTabItem( LabelTab ) )
case ImporterState.None: break;
case ImporterState.WritingPackToDisk:
ImGui.Text( TooltipModpack1 );
break;
case ImporterState.ExtractingModFiles:
{
return;
}
var str =
$"{_texToolsImport.CurrentModPack} - {_texToolsImport.CurrentProgress} of {_texToolsImport.TotalProgress} files";
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
ImGui.ProgressBar( _texToolsImport.Progress, ImportBarSize, str );
break;
}
case ImporterState.Done: break;
default: throw new ArgumentOutOfRangeException();
}
}
if( !_isImportRunning )
{
DrawImportButton();
}
else
{
DrawImportProgress();
}
private void DrawFailedImportMessage()
{
using var color = ImGuiRaii.PushColor( ImGuiCol.Text, ColorRed );
ImGui.Text( $"One or more of your modpacks failed to import:\n\t\t{_errorMessage}" );
}
if( _errorMessage.Any() )
{
DrawFailedImportMessage();
}
public void Draw()
{
if( !ImGui.BeginTabItem( LabelTab ) )
{
return;
}
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
if( !_isImportRunning )
{
DrawImportButton();
}
else
{
DrawImportProgress();
}
if( _errorMessage.Any() )
{
DrawFailedImportMessage();
}
}
}

View file

@ -1,42 +1,37 @@
using System.Collections.Generic;
using ImGuiNET;
using Penumbra.Mods;
using Penumbra.UI.Custom;
using Penumbra.Util;
namespace Penumbra.UI
namespace Penumbra.UI;
public partial class SettingsInterface
{
public partial class SettingsInterface
private class TabInstalled
{
private class TabInstalled
private const string LabelTab = "Installed Mods";
public readonly Selector Selector;
public readonly ModPanel ModPanel;
public TabInstalled( SettingsInterface ui, HashSet< string > newMods )
{
private const string LabelTab = "Installed Mods";
Selector = new Selector( ui, newMods );
ModPanel = new ModPanel( ui, Selector, newMods );
}
private readonly ModManager _modManager;
public readonly Selector Selector;
public readonly ModPanel ModPanel;
public TabInstalled( SettingsInterface ui, HashSet< string > newMods )
public void Draw()
{
var ret = ImGui.BeginTabItem( LabelTab );
if( !ret )
{
Selector = new Selector( ui, newMods );
ModPanel = new ModPanel( ui, Selector, newMods );
_modManager = Service< ModManager >.Get();
return;
}
public void Draw()
{
var ret = ImGui.BeginTabItem( LabelTab );
if( !ret )
{
return;
}
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
Selector.Draw();
ImGui.SameLine();
ModPanel.Draw();
}
Selector.Draw();
ImGui.SameLine();
ModPanel.Draw();
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -112,7 +112,7 @@ namespace Penumbra.UI
var groupName = group.GroupName;
if( ImGuiCustom.BeginFramedGroupEdit( ref groupName ) )
{
if( _modManager.ChangeModGroup( group.GroupName, groupName, Mod.Data ) && Mod.Data.Meta.RefreshHasGroupsWithConfig() )
if( Penumbra.ModManager.ChangeModGroup( group.GroupName, groupName, Mod.Data ) && Mod.Data.Meta.RefreshHasGroupsWithConfig() )
{
_selector.Cache.TriggerFilterReset();
}
@ -165,7 +165,7 @@ namespace Penumbra.UI
{
if( newName.Length == 0 )
{
_modManager.RemoveModOption( i, group, Mod.Data );
Penumbra.ModManager.RemoveModOption( i, group, Mod.Data );
}
else if( newName != opt.OptionName )
{
@ -189,7 +189,7 @@ namespace Penumbra.UI
var groupName = group.GroupName;
if( ImGui.InputText( $"##{groupName}_add", ref groupName, 64, ImGuiInputTextFlags.EnterReturnsTrue ) )
{
if( _modManager.ChangeModGroup( group.GroupName, groupName, Mod.Data ) && Mod.Data.Meta.RefreshHasGroupsWithConfig() )
if( Penumbra.ModManager.ChangeModGroup( group.GroupName, groupName, Mod.Data ) && Mod.Data.Meta.RefreshHasGroupsWithConfig() )
{
_selector.Cache.TriggerFilterReset();
}
@ -221,7 +221,7 @@ namespace Penumbra.UI
{
if( newName.Length == 0 )
{
_modManager.RemoveModOption( code, group, Mod.Data );
Penumbra.ModManager.RemoveModOption( code, group, Mod.Data );
}
else
{
@ -267,7 +267,7 @@ namespace Penumbra.UI
if( ImGui.InputTextWithHint( LabelNewSingleGroupEdit, "Add new Single Group...", ref newGroup, 64,
ImGuiInputTextFlags.EnterReturnsTrue ) )
{
_modManager.ChangeModGroup( "", newGroup, Mod.Data, SelectType.Single );
Penumbra.ModManager.ChangeModGroup( "", newGroup, Mod.Data, SelectType.Single );
// Adds empty group, so can not change filters.
}
}
@ -280,7 +280,7 @@ namespace Penumbra.UI
if( ImGui.InputTextWithHint( LabelNewMultiGroup, "Add new Multi Group...", ref newGroup, 64,
ImGuiInputTextFlags.EnterReturnsTrue ) )
{
_modManager.ChangeModGroup( "", newGroup, Mod.Data, SelectType.Multi );
Penumbra.ModManager.ChangeModGroup( "", newGroup, Mod.Data, SelectType.Multi );
// Adds empty group, so can not change filters.
}
}

View file

@ -229,7 +229,7 @@ namespace Penumbra.UI
if( ImGui.BeginPopup( $"##MetaPopup{manipIdx}" ) )
{
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndPopup );
var defaults = ( EqpEntry )Service< MetaDefaults >.Get().GetDefaultValue( list[ manipIdx ] )!;
var defaults = ( EqpEntry )Penumbra.MetaDefaults.GetDefaultValue( list[ manipIdx ] )!;
var attributes = Eqp.EqpAttributes[ id.Slot ];
foreach( var flag in attributes )
@ -254,7 +254,7 @@ namespace Penumbra.UI
private bool DrawGmpRow( int manipIdx, IList< MetaManipulation > list )
{
var defaults = ( GmpEntry )Service< MetaDefaults >.Get().GetDefaultValue( list[ manipIdx ] )!;
var defaults = ( GmpEntry )Penumbra.MetaDefaults.GetDefaultValue( list[ manipIdx ] )!;
var ret = false;
var id = list[ manipIdx ].GmpIdentifier;
var val = list[ manipIdx ].GmpValue;
@ -364,7 +364,7 @@ namespace Penumbra.UI
private bool DrawEqdpRow( int manipIdx, IList< MetaManipulation > list )
{
var defaults = ( EqdpEntry )Service< MetaDefaults >.Get().GetDefaultValue( list[ manipIdx ] )!;
var defaults = ( EqdpEntry )Penumbra.MetaDefaults.GetDefaultValue( list[ manipIdx ] )!;
var ret = false;
var id = list[ manipIdx ].EqdpIdentifier;
var val = list[ manipIdx ].EqdpValue;
@ -401,7 +401,7 @@ namespace Penumbra.UI
private bool DrawEstRow( int manipIdx, IList< MetaManipulation > list )
{
var defaults = ( ushort )Service< MetaDefaults >.Get().GetDefaultValue( list[ manipIdx ] )!;
var defaults = ( ushort )Penumbra.MetaDefaults.GetDefaultValue( list[ manipIdx ] )!;
var ret = false;
var id = list[ manipIdx ].EstIdentifier;
var val = list[ manipIdx ].EstValue;
@ -433,7 +433,7 @@ namespace Penumbra.UI
private bool DrawImcRow( int manipIdx, IList< MetaManipulation > list )
{
var defaults = ( ImcFile.ImageChangeData )Service< MetaDefaults >.Get().GetDefaultValue( list[ manipIdx ] )!;
var defaults = ( ImcFile.ImageChangeData )Penumbra.MetaDefaults.GetDefaultValue( list[ manipIdx ] )!;
var ret = false;
var id = list[ manipIdx ].ImcIdentifier;
var val = list[ manipIdx ].ImcValue;
@ -492,7 +492,7 @@ namespace Penumbra.UI
private bool DrawRspRow( int manipIdx, IList< MetaManipulation > list )
{
var defaults = ( float )Service< MetaDefaults >.Get().GetDefaultValue( list[ manipIdx ] )!;
var defaults = ( float )Penumbra.MetaDefaults.GetDefaultValue( list[ manipIdx ] )!;
var ret = false;
var id = list[ manipIdx ].RspIdentifier;
var val = list[ manipIdx ].RspValue;
@ -694,7 +694,7 @@ namespace Penumbra.UI
&& newManip != null
&& list.All( m => m.Identifier != newManip.Value.Identifier ) )
{
var def = Service< MetaDefaults >.Get().GetDefaultValue( newManip.Value );
var def = Penumbra.MetaDefaults.GetDefaultValue( newManip.Value );
if( def != null )
{
var manip = newManip.Value.Type switch

View file

@ -50,7 +50,6 @@ public partial class SettingsInterface
private readonly SettingsInterface _base;
private readonly Selector _selector;
private readonly ModManager _modManager;
private readonly HashSet< string > _newMods;
public readonly PluginDetails Details;
@ -68,7 +67,6 @@ public partial class SettingsInterface
_newMods = newMods;
Details = new PluginDetails( _base, _selector );
_currentWebsite = Meta?.Website ?? "";
_modManager = Service< ModManager >.Get();
}
private Mod.Mod? Mod
@ -79,11 +77,12 @@ public partial class SettingsInterface
private void DrawName()
{
var name = Meta!.Name;
if( ImGuiCustom.InputOrText( _editMode, LabelEditName, ref name, 64 ) && _modManager.RenameMod( name, Mod!.Data ) )
var name = Meta!.Name;
var modManager = Penumbra.ModManager;
if( ImGuiCustom.InputOrText( _editMode, LabelEditName, ref name, 64 ) && modManager.RenameMod( name, Mod!.Data ) )
{
_selector.SelectModOnUpdate( Mod.Data.BasePath.Name );
if( !_modManager.Config.ModSortOrder.ContainsKey( Mod!.Data.BasePath.Name ) )
if( !modManager.Config.ModSortOrder.ContainsKey( Mod!.Data.BasePath.Name ) )
{
Mod.Data.Rename( name );
}
@ -286,7 +285,7 @@ public partial class SettingsInterface
{
ImGui.OpenPopup( LabelOverWriteDir );
}
else if( _modManager.RenameModFolder( Mod.Data, newDir ) )
else if( Penumbra.ModManager.RenameModFolder( Mod.Data, newDir ) )
{
_selector.ReloadCurrentMod();
ImGui.CloseCurrentPopup();
@ -301,12 +300,12 @@ public partial class SettingsInterface
if( sourceUri.Equals( targetUri ) )
{
var tmpFolder = new DirectoryInfo( TempFile.TempFileName( dir.Parent! ).FullName );
if( _modManager.RenameModFolder( Mod.Data, tmpFolder ) )
if( Penumbra.ModManager.RenameModFolder( Mod.Data, tmpFolder ) )
{
if( !_modManager.RenameModFolder( Mod.Data, newDir ) )
if( !Penumbra.ModManager.RenameModFolder( Mod.Data, newDir ) )
{
PluginLog.Error( "Could not recapitalize folder after renaming, reverting rename." );
_modManager.RenameModFolder( Mod.Data, dir );
Penumbra.ModManager.RenameModFolder( Mod.Data, dir );
}
_selector.ReloadCurrentMod();
@ -364,17 +363,14 @@ public partial class SettingsInterface
ImGui.Text(
$"The mod directory {newDir} already exists.\nDo you want to merge / overwrite both mods?\nThis may corrupt the resulting mod in irrecoverable ways." );
var buttonSize = ImGuiHelpers.ScaledVector2( 120, 0 );
if( ImGui.Button( "Yes", buttonSize ) )
if( ImGui.Button( "Yes", buttonSize ) && MergeFolderInto( dir, newDir ) )
{
if( MergeFolderInto( dir, newDir ) )
{
Service< ModManager >.Get()!.RenameModFolder( Mod.Data, newDir, false );
Penumbra.ModManager.RenameModFolder( Mod.Data, newDir, false );
_selector.SelectModOnUpdate( _newName );
_selector.SelectModOnUpdate( _newName );
closeParent = true;
ImGui.CloseCurrentPopup();
}
closeParent = true;
ImGui.CloseCurrentPopup();
}
ImGui.SameLine();
@ -580,7 +576,7 @@ public partial class SettingsInterface
DrawMaterialChangeRow();
DrawSortOrder( Mod!.Data, _modManager, _selector );
DrawSortOrder( Mod!.Data, Penumbra.ModManager, _selector );
}
public void Draw()

View file

@ -101,7 +101,7 @@ public partial class SettingsInterface
ImGui.CloseCurrentPopup();
var mod = Mod;
Cache.RemoveMod( mod );
_modManager.DeleteMod( mod.Data.BasePath );
Penumbra.ModManager.DeleteMod( mod.Data.BasePath );
ModFileSystem.InvokeChange();
ClearSelection();
}
@ -166,7 +166,7 @@ public partial class SettingsInterface
var metaFile = new FileInfo( Path.Combine( newDir.FullName, "meta.json" ) );
modMeta.SaveToFile( metaFile );
_modManager.AddMod( newDir );
Penumbra.ModManager.AddMod( newDir );
ModFileSystem.InvokeChange();
SelectModOnUpdate( newDir.Name );
}
@ -464,7 +464,7 @@ public partial class SettingsInterface
return;
}
if( _index >= 0 && _modManager.UpdateMod( Mod.Data, reloadMeta, recomputeMeta, force ) )
if( _index >= 0 && Penumbra.ModManager.UpdateMod( Mod.Data, reloadMeta, recomputeMeta, force ) )
{
SelectModOnUpdate( Mod.Data.BasePath.Name );
_base._menu.InstalledTab.ModPanel.Details.ResetState();
@ -526,11 +526,11 @@ public partial class SettingsInterface
}
Cache.TriggerFilterReset();
var collection = _modManager.Collections.CurrentCollection;
var collection = Penumbra.ModManager.Collections.CurrentCollection;
if( collection.Cache != null )
{
collection.CalculateEffectiveFileList( _modManager.TempPath, metaManips,
collection == _modManager.Collections.ActiveCollection );
collection.CalculateEffectiveFileList( Penumbra.ModManager.TempPath, metaManips,
collection == Penumbra.ModManager.Collections.ActiveCollection );
}
collection.Save();
@ -597,7 +597,6 @@ public partial class SettingsInterface
private partial class Selector
{
private readonly SettingsInterface _base;
private readonly ModManager _modManager;
public readonly ModListCache Cache;
private float _selectorScalingFactor = 1;
@ -605,14 +604,13 @@ public partial class SettingsInterface
public Selector( SettingsInterface ui, IReadOnlySet< string > newMods )
{
_base = ui;
_modManager = Service< ModManager >.Get();
Cache = new ModListCache( _modManager, newMods );
Cache = new ModListCache( Penumbra.ModManager, newMods );
}
private void DrawCollectionButton( string label, string tooltipLabel, float size, ModCollection collection )
{
if( collection == ModCollection.Empty
|| collection == _modManager.Collections.CurrentCollection )
|| collection == Penumbra.ModManager.Collections.CurrentCollection )
{
using var _ = ImGuiRaii.PushStyle( ImGuiStyleVar.Alpha, 0.5f );
ImGui.Button( label, Vector2.UnitX * size );
@ -641,10 +639,10 @@ public partial class SettingsInterface
- 4 * ImGui.GetStyle().ItemSpacing.X )
/ 2, 5f );
ImGui.SameLine();
DrawCollectionButton( "Default", "default", buttonSize, _modManager.Collections.DefaultCollection );
DrawCollectionButton( "Default", "default", buttonSize, Penumbra.ModManager.Collections.DefaultCollection );
ImGui.SameLine();
DrawCollectionButton( "Forced", "forced", buttonSize, _modManager.Collections.ForcedCollection );
DrawCollectionButton( "Forced", "forced", buttonSize, Penumbra.ModManager.Collections.ForcedCollection );
ImGui.SameLine();
ImGui.SetNextItemWidth( comboSize );
@ -655,7 +653,7 @@ public partial class SettingsInterface
private void DrawFolderContent( ModFolder folder, ref int idx )
{
// Collection may be manipulated.
foreach( var item in folder.GetItems( _modManager.Config.SortFoldersFirst ).ToArray() )
foreach( var item in folder.GetItems( Penumbra.ModManager.Config.SortFoldersFirst ).ToArray() )
{
if( item is ModFolder sub )
{
@ -785,7 +783,7 @@ public partial class SettingsInterface
style.Push( ImGuiStyleVar.IndentSpacing, 12.5f );
var modIndex = 0;
DrawFolderContent( _modManager.StructuredMods, ref modIndex );
DrawFolderContent( Penumbra.ModManager.StructuredMods, ref modIndex );
style.Pop();
}

View file

@ -1,9 +1,12 @@
using System;
using System.Linq;
using System.Numerics;
using Dalamud.Interface;
using FFXIVClientStructs.FFXIV.Client.System.Resource;
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
using FFXIVClientStructs.STD;
using ImGuiNET;
using Penumbra.Interop;
using Penumbra.UI.Custom;
namespace Penumbra.UI;
@ -21,16 +24,22 @@ public partial class SettingsInterface
: $"({type:X8}) {( char )byte1}{( char )byte2}{( char )byte3}{( char )byte4} - {count}###{label}{type}Debug";
}
private unsafe void DrawResourceMap( string label, StdMap< uint, Pointer< ResourceHandle > >* typeMap )
private unsafe void DrawResourceMap( ResourceCategory category, uint ext, StdMap< uint, Pointer< ResourceHandle > >* map )
{
if( typeMap == null || !ImGui.TreeNodeEx( label ) )
if( map == null )
{
return;
}
var label = GetNodeLabel( ( uint )category, ext, map->Count );
if( !ImGui.TreeNodeEx( label ) )
{
return;
}
using var raii = ImGuiRaii.DeferredEnd( ImGui.TreePop );
if( typeMap->Count == 0 || !ImGui.BeginTable( $"##{label}_table", 4, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg ) )
if( map->Count == 0 || !ImGui.BeginTable( $"##{label}_table", 4, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg ) )
{
return;
}
@ -44,21 +53,19 @@ public partial class SettingsInterface
ImGui.TableSetupColumn( "Refs", ImGuiTableColumnFlags.WidthFixed, 30 * ImGuiHelpers.GlobalScale );
ImGui.TableHeadersRow();
var node = typeMap->SmallestValue;
while( !node->IsNil )
ResourceLoader.IterateResourceMap( map, ( hash, r ) =>
{
ImGui.TableNextRow();
ImGui.TableNextColumn();
ImGui.Text( $"0x{node->KeyValuePair.Item1:X8}" );
ImGui.Text( $"0x{hash:X8}" );
ImGui.TableNextColumn();
var address = $"0x{( ulong )node->KeyValuePair.Item2.Value:X}";
var address = $"0x{( ulong )r:X}";
ImGui.Text( address );
if( ImGui.IsItemClicked() )
{
ImGui.SetClipboardText( address );
}
ref var name = ref node->KeyValuePair.Item2.Value->FileName;
ref var name = ref r->FileName;
ImGui.TableNextColumn();
if( name.Capacity > 15 )
{
@ -72,30 +79,73 @@ public partial class SettingsInterface
}
}
//ImGui.Text( node->KeyValuePair.Item2.Value->FileName.ToString() );
if( ImGui.IsItemClicked() )
{
var data = ( ( Interop.Structs.ResourceHandle* )r )->GetData();
ImGui.SetClipboardText( string.Join( " ",
new ReadOnlySpan< byte >( ( byte* )data.Data, data.Length ).ToArray().Select( b => b.ToString( "X2" ) ) ) );
//ImGuiNative.igSetClipboardText( ( byte* )Structs.ResourceHandle.GetData( ( IntPtr )r ) );
}
ImGui.TableNextColumn();
ImGui.Text( node->KeyValuePair.Item2.Value->RefCount.ToString() );
node = node->Next();
}
ImGui.Text( r->RefCount.ToString() );
} );
}
private unsafe void DrawCategoryContainer( ResourceCategory category, ResourceGraph.CategoryContainer container )
private unsafe void DrawCategoryContainer( ResourceCategory category,
StdMap< uint, Pointer< StdMap< uint, Pointer< ResourceHandle > > > >* map )
{
var map = container.MainMap;
if( map == null || !ImGui.TreeNodeEx( $"({( uint )category:D2}) {category} - {map->Count}###{( uint )category}Debug" ) )
{
return;
}
using var raii = ImGuiRaii.DeferredEnd( ImGui.TreePop );
ResourceLoader.IterateExtMap( map, ( ext, map ) => DrawResourceMap( category, ext, map ) );
}
var node = map->SmallestValue;
while( !node->IsNil )
private static unsafe void DrawResourceProblems()
{
if( !ImGui.CollapsingHeader( "Resource Problems##ResourceManager" )
|| !ImGui.BeginTable( "##ProblemsTable", 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit ) )
{
DrawResourceMap( GetNodeLabel( ( uint )category, node->KeyValuePair.Item1, node->KeyValuePair.Item2.Value->Count ),
node->KeyValuePair.Item2.Value );
node = node->Next();
return;
}
using var end = ImGuiRaii.DeferredEnd( ImGui.EndTable );
ResourceLoader.IterateResources( ( _, r ) =>
{
if( r->RefCount < 10000 )
{
return;
}
ImGui.TableNextColumn();
ImGui.Text( r->Category.ToString() );
ImGui.TableNextColumn();
ImGui.Text( r->FileType.ToString( "X" ) );
ImGui.TableNextColumn();
ImGui.Text( r->Id.ToString( "X" ) );
ImGui.TableNextColumn();
ImGui.Text( ( ( ulong )r ).ToString( "X" ) );
ImGui.TableNextColumn();
ImGui.Text( r->RefCount.ToString() );
ImGui.TableNextColumn();
ref var name = ref r->FileName;
if( name.Capacity > 15 )
{
ImGuiNative.igTextUnformatted( name.BufferPtr, name.BufferPtr + name.Length );
}
else
{
fixed( byte* ptr = name.Buffer )
{
ImGuiNative.igTextUnformatted( ptr, ptr + name.Length );
}
}
} );
}
private unsafe void DrawResourceManagerTab()
@ -107,7 +157,7 @@ public partial class SettingsInterface
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
var resourceHandler = *( ResourceManager** )Dalamud.SigScanner.GetStaticAddressFromSig( "48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 32 C0" );
var resourceHandler = *ResourceLoader.ResourceManager;
if( resourceHandler == null )
{
@ -120,20 +170,6 @@ public partial class SettingsInterface
return;
}
DrawCategoryContainer( ResourceCategory.Common, resourceHandler->ResourceGraph->CommonContainer );
DrawCategoryContainer( ResourceCategory.BgCommon, resourceHandler->ResourceGraph->BgCommonContainer );
DrawCategoryContainer( ResourceCategory.Bg, resourceHandler->ResourceGraph->BgContainer );
DrawCategoryContainer( ResourceCategory.Cut, resourceHandler->ResourceGraph->CutContainer );
DrawCategoryContainer( ResourceCategory.Chara, resourceHandler->ResourceGraph->CharaContainer );
DrawCategoryContainer( ResourceCategory.Shader, resourceHandler->ResourceGraph->ShaderContainer );
DrawCategoryContainer( ResourceCategory.Ui, resourceHandler->ResourceGraph->UiContainer );
DrawCategoryContainer( ResourceCategory.Sound, resourceHandler->ResourceGraph->SoundContainer );
DrawCategoryContainer( ResourceCategory.Vfx, resourceHandler->ResourceGraph->VfxContainer );
DrawCategoryContainer( ResourceCategory.UiScript, resourceHandler->ResourceGraph->UiScriptContainer );
DrawCategoryContainer( ResourceCategory.Exd, resourceHandler->ResourceGraph->ExdContainer );
DrawCategoryContainer( ResourceCategory.GameScript, resourceHandler->ResourceGraph->GameScriptContainer );
DrawCategoryContainer( ResourceCategory.Music, resourceHandler->ResourceGraph->MusicContainer );
DrawCategoryContainer( ResourceCategory.SqpackTest, resourceHandler->ResourceGraph->SqpackTestContainer );
DrawCategoryContainer( ResourceCategory.Debug, resourceHandler->ResourceGraph->DebugContainer );
ResourceLoader.IterateGraphs( DrawCategoryContainer );
}
}

View file

@ -3,12 +3,12 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text.RegularExpressions;
using Dalamud.Interface;
using Dalamud.Interface.Components;
using Dalamud.Logging;
using ImGuiNET;
using Penumbra.GameData.ByteString;
using Penumbra.Interop;
using Penumbra.Mods;
using Penumbra.UI.Custom;
using Penumbra.Util;
@ -71,7 +71,8 @@ public partial class SettingsInterface
+ "It should also be placed near the root of a logical drive - the shorter the total path to this folder, the better.\n"
+ "Definitely do not place it in your Dalamud directory or any sub-directory thereof." );
ImGui.SameLine();
DrawOpenDirectoryButton( 0, _base._modManager.BasePath, _base._modManager.Valid );
var modManager = Penumbra.ModManager;
DrawOpenDirectoryButton( 0, modManager.BasePath, modManager.Valid );
ImGui.EndGroup();
if( _config.ModDirectory == _newModDirectory || !_newModDirectory.Any() )
@ -82,7 +83,7 @@ public partial class SettingsInterface
if( save || DrawPressEnterWarning( _config.ModDirectory ) )
{
_base._menu.InstalledTab.Selector.ClearSelection();
_base._modManager.DiscoverMods( _newModDirectory );
modManager.DiscoverMods( _newModDirectory );
_base._menu.InstalledTab.Selector.Cache.TriggerListReset();
_newModDirectory = _config.ModDirectory;
}
@ -99,7 +100,8 @@ public partial class SettingsInterface
+ "A directory 'penumbrametatmp' will be created as a sub-directory to the specified directory.\n"
+ "If none is specified (i.e. this is blank) this directory will be created in the root directory instead.\n" );
ImGui.SameLine();
DrawOpenDirectoryButton( 1, _base._modManager.TempPath, _base._modManager.TempWritable );
var modManager = Penumbra.ModManager;
DrawOpenDirectoryButton( 1, modManager.TempPath, modManager.TempWritable );
ImGui.EndGroup();
if( _newTempDirectory == _config.TempDirectory )
@ -109,7 +111,7 @@ public partial class SettingsInterface
if( save || DrawPressEnterWarning( _config.TempDirectory ) )
{
_base._modManager.SetTempDirectory( _newTempDirectory );
modManager.SetTempDirectory( _newTempDirectory );
_newTempDirectory = _config.TempDirectory;
}
}
@ -119,7 +121,7 @@ public partial class SettingsInterface
if( ImGui.Button( "Rediscover Mods" ) )
{
_base._menu.InstalledTab.Selector.ClearSelection();
_base._modManager.DiscoverMods();
Penumbra.ModManager.DiscoverMods();
_base._menu.InstalledTab.Selector.Cache.TriggerListReset();
}
@ -208,26 +210,26 @@ public partial class SettingsInterface
private void DrawLogLoadedFilesBox()
{
ImGui.Checkbox( "Log Loaded Files", ref _base._penumbra.ResourceLoader.LogAllFiles );
ImGui.SameLine();
var regex = _base._penumbra.ResourceLoader.LogFileFilter?.ToString() ?? string.Empty;
var tmp = regex;
ImGui.SetNextItemWidth( SettingsMenu.InputTextWidth );
if( ImGui.InputTextWithHint( "##LogFilter", "Matching this Regex...", ref tmp, 64 ) && tmp != regex )
{
try
{
var newRegex = tmp.Length > 0 ? new Regex( tmp, RegexOptions.Compiled ) : null;
_base._penumbra.ResourceLoader.LogFileFilter = newRegex;
}
catch( Exception e )
{
PluginLog.Debug( "Could not create regex:\n{Exception}", e );
}
}
ImGui.SameLine();
ImGuiComponents.HelpMarker( "Log all loaded files that match the given Regex to the PluginLog." );
//ImGui.Checkbox( "Log Loaded Files", ref _base._penumbra.ResourceLoader.LogAllFiles );
//ImGui.SameLine();
//var regex = _base._penumbra.ResourceLoader.LogFileFilter?.ToString() ?? string.Empty;
//var tmp = regex;
//ImGui.SetNextItemWidth( SettingsMenu.InputTextWidth );
//if( ImGui.InputTextWithHint( "##LogFilter", "Matching this Regex...", ref tmp, 64 ) && tmp != regex )
//{
// try
// {
// var newRegex = tmp.Length > 0 ? new Regex( tmp, RegexOptions.Compiled ) : null;
// _base._penumbra.ResourceLoader.LogFileFilter = newRegex;
// }
// catch( Exception e )
// {
// PluginLog.Debug( "Could not create regex:\n{Exception}", e );
// }
//}
//
//ImGui.SameLine();
//ImGuiComponents.HelpMarker( "Log all loaded files that match the given Regex to the PluginLog." );
}
private void DrawDisableNotificationsBox()
@ -307,7 +309,7 @@ public partial class SettingsInterface
{
if( ImGui.Button( "Reload Resident Resources" ) )
{
Service< ResidentResources >.Get().ReloadResidentResources();
Penumbra.ResidentResources.Reload();
}
ImGui.SameLine();
@ -325,6 +327,11 @@ public partial class SettingsInterface
DrawReloadResourceButton();
}
public static unsafe void Text( Utf8String s )
{
ImGuiNative.igTextUnformatted( ( byte* )s.Path, ( byte* )s.Path + s.Length );
}
public void Draw()
{
if( !ImGui.BeginTabItem( "Settings" ) )

View file

@ -1,7 +1,5 @@
using System;
using System.Numerics;
using Penumbra.Mods;
using Penumbra.Util;
namespace Penumbra.UI;
@ -15,17 +13,13 @@ public partial class SettingsInterface : IDisposable
private readonly Penumbra _penumbra;
private readonly ManageModsButton _manageModsButton;
private readonly MenuBar _menuBar;
private readonly SettingsMenu _menu;
private readonly ModManager _modManager;
public SettingsInterface( Penumbra penumbra )
{
_penumbra = penumbra;
_manageModsButton = new ManageModsButton( this );
_menuBar = new MenuBar( this );
_menu = new SettingsMenu( this );
_modManager = Service< ModManager >.Get();
Dalamud.PluginInterface.UiBuilder.DisableGposeUiHide = true;
Dalamud.PluginInterface.UiBuilder.Draw += Draw;
@ -51,31 +45,31 @@ public partial class SettingsInterface : IDisposable
public void Draw()
{
_menuBar.Draw();
_menu.Draw();
}
private void ReloadMods()
{
_menu.InstalledTab.Selector.ClearSelection();
_modManager.DiscoverMods( Penumbra.Config.ModDirectory );
Penumbra.ModManager.DiscoverMods( Penumbra.Config.ModDirectory );
_menu.InstalledTab.Selector.Cache.TriggerListReset();
}
private void SaveCurrentCollection( bool recalculateMeta )
{
var current = _modManager.Collections.CurrentCollection;
var current = Penumbra.ModManager.Collections.CurrentCollection;
current.Save();
RecalculateCurrent( recalculateMeta );
}
private void RecalculateCurrent( bool recalculateMeta )
{
var current = _modManager.Collections.CurrentCollection;
var modManager = Penumbra.ModManager;
var current = modManager.Collections.CurrentCollection;
if( current.Cache != null )
{
current.CalculateEffectiveFileList( _modManager.TempPath, recalculateMeta,
current == _modManager.Collections.ActiveCollection );
current.CalculateEffectiveFileList( modManager.TempPath, recalculateMeta,
current == modManager.Collections.ActiveCollection );
_menu.InstalledTab.Selector.Cache.TriggerFilterReset();
}
}

View file

@ -74,7 +74,7 @@ public partial class SettingsInterface
CollectionsTab.Draw();
_importTab.Draw();
if( Service< ModManager >.Get().Valid && !_importTab.IsImporting() )
if( Penumbra.ModManager.Valid && !_importTab.IsImporting() )
{
_browserTab.Draw();
InstalledTab.Draw();