Add some methods and interface to view currently Changed Items.

This commit is contained in:
Ottermandias 2021-10-19 18:45:22 +02:00
parent 982385ccbb
commit 0c0eeec158
9 changed files with 219 additions and 40 deletions

View file

@ -1,3 +1,4 @@
using System.Collections.Generic;
using Dalamud.Game.ClientState.Objects.Types;
using Lumina.Data;
using Penumbra.GameData.Enums;
@ -43,5 +44,8 @@ namespace Penumbra.Api
// Try to load a given gamePath with the resolved path from Penumbra.
public T? GetFile<T>( string gamePath, string characterName ) where T : FileResource;
// Gets a dictionary of effected items from a collection
public IReadOnlyDictionary< string, object? > GetChangedItemsForCollection(string collectionName);
}
}

View file

@ -1,9 +1,13 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Logging;
using Lumina.Data;
using Lumina.Data.Parsing;
using Lumina.Excel.GeneratedSheets;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Util;
using Penumbra.Mods;
@ -131,5 +135,32 @@ namespace Penumbra.Api
public T? GetFile< T >( string gamePath, string characterName ) where T : FileResource
=> GetFileIntern< T >( ResolvePath( gamePath, characterName ) );
public IReadOnlyDictionary< string, object? > GetChangedItemsForCollection( string collectionName )
{
CheckInitialized();
try
{
var modManager = Service< ModManager >.Get();
if( !modManager.Collections.Collections.TryGetValue( collectionName, out var collection ) )
{
collection = ModCollection.Empty;
}
if( collection.Cache != null )
{
return collection.Cache.ChangedItems;
}
PluginLog.Warning( $"Collection {collectionName} does not exist or is not loaded." );
return new Dictionary< string, object? >();
}
catch( Exception e )
{
PluginLog.Error( $"Could not obtain Changed Items for {collectionName}:\n{e}" );
throw;
}
}
}
}

View file

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Logging;
using Dalamud.Plugin;
@ -18,6 +19,7 @@ namespace Penumbra.Api
public const string LabelProviderChangedItemTooltip = "Penumbra.ChangedItemTooltip";
public const string LabelProviderChangedItemClick = "Penumbra.ChangedItemClick";
public const string LabelProviderGetChangedItems = "Penumbra.GetChangedItems";
internal ICallGateProvider< int >? ProviderApiVersion;
internal ICallGateProvider< string, int, object >? ProviderRedrawName;
@ -27,6 +29,7 @@ namespace Penumbra.Api
internal ICallGateProvider< string, string, string >? ProviderResolveCharacter;
internal ICallGateProvider< ChangedItemType, uint, object >? ProviderChangedItemTooltip;
internal ICallGateProvider< MouseButton, ChangedItemType, uint, object >? ProviderChangedItemClick;
internal ICallGateProvider< string, IReadOnlyDictionary< string, object? > >? ProviderGetChangedItems;
internal readonly IPenumbraApi Api;
@ -137,6 +140,16 @@ namespace Penumbra.Api
{
PluginLog.Error( $"Error registering IPC provider for {LabelProviderChangedItemClick}:\n{e}" );
}
try
{
ProviderGetChangedItems = pi.GetIpcProvider< string, IReadOnlyDictionary< string, object? > >( LabelProviderGetChangedItems );
ProviderGetChangedItems.RegisterFunc( api.GetChangedItemsForCollection );
}
catch( Exception e )
{
PluginLog.Error( $"Error registering IPC provider for {LabelProviderChangedItemClick}:\n{e}" );
}
}
public void Dispose()
@ -147,6 +160,7 @@ namespace Penumbra.Api
ProviderRedrawAll?.UnregisterAction();
ProviderResolveDefault?.UnregisterFunc();
ProviderResolveCharacter?.UnregisterFunc();
ProviderGetChangedItems?.UnregisterFunc();
Api.ChangedItemClicked -= OnClick;
Api.ChangedItemTooltip -= OnTooltip;
}

View file

@ -1,3 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
@ -24,11 +25,21 @@ namespace Penumbra.Mods
public readonly Dictionary< string, Mod.Mod > AvailableMods = new();
private readonly SortedList< string, object? > _changedItems = new();
public readonly Dictionary< GamePath, FileInfo > ResolvedFiles = new();
public readonly Dictionary< GamePath, GamePath > SwappedFiles = new();
public readonly HashSet< FileInfo > MissingFiles = new();
public readonly MetaManager MetaManipulations;
public IReadOnlyDictionary< string, object? > ChangedItems
{
get
{
SetChangedItems();
return _changedItems;
}
}
public ModCollectionCache( string collectionName, DirectoryInfo tempDir )
=> MetaManipulations = new MetaManager( collectionName, ResolvedFiles, tempDir );
@ -52,6 +63,7 @@ namespace Penumbra.Mods
SwappedFiles.Clear();
MissingFiles.Clear();
RegisteredFiles.Clear();
_changedItems.Clear();
foreach( var mod in AvailableMods.Values
.Where( m => m.Settings.Enabled )
@ -65,6 +77,35 @@ namespace Penumbra.Mods
AddMetaFiles();
}
private void SetChangedItems()
{
if( _changedItems.Count > 0 || ResolvedFiles.Count + SwappedFiles.Count + MetaManipulations.Count == 0 )
{
return;
}
try
{
// Skip meta files because IMCs would result in far too many false-positive items,
// since they are per set instead of per item-slot/item/variant.
var metaFiles = MetaManipulations.Files.Select( p => p.Item1 ).ToHashSet();
var identifier = GameData.GameData.GetIdentifier();
foreach( var resolved in ResolvedFiles.Keys.Where( file => !metaFiles.Contains( file ) ) )
{
identifier.Identify( _changedItems, resolved );
}
foreach( var swapped in SwappedFiles.Keys )
{
identifier.Identify( _changedItems, swapped );
}
}
catch( Exception e )
{
PluginLog.Error( $"Unknown Error:\n{e}" );
}
}
private void AddFiles( Mod.Mod mod )
{

View file

@ -0,0 +1,72 @@
using System.Collections.Generic;
using System.Linq;
using ImGuiNET;
using Penumbra.Mods;
using Penumbra.UI.Custom;
using Penumbra.Util;
namespace Penumbra.UI
{
public partial class SettingsInterface
{
private class TabChangedItems
{
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 )
{
_base = ui;
_modManager = Service< ModManager >.Get();
}
public void Draw()
{
var items = _modManager.Collections.ActiveCollection.Cache?.ChangedItems ?? new Dictionary< string, object? >();
var forced = _modManager.Collections.ForcedCollection.Cache?.ChangedItems ?? new Dictionary< string, object? >();
var count = items.Count + forced.Count;
if( count > 0 && !ImGui.BeginTabItem( LabelTab ) )
{
return;
}
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
ImGui.SetNextItemWidth( -1 );
if( ImGui.InputTextWithHint( "##ChangedItemsFilter", "Filter...", ref _filter, 64 ) )
{
_filterLower = _filter.ToLowerInvariant();
}
if( !ImGui.BeginTable( "##ChangedItemsTable", 1, ImGuiTableFlags.RowBg, AutoFillSize ) )
{
return;
}
raii.Push( ImGui.EndTable );
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 );
}
}
}
}
}

View file

@ -185,30 +185,7 @@ namespace Penumbra.UI
raii.Push( ImGui.EndListBox );
foreach( var (name, data) in Mod.Data.ChangedItems )
{
var ret = ImGui.Selectable( name ) ? MouseButton.Left : MouseButton.None;
ret = ImGui.IsItemClicked( ImGuiMouseButton.Right ) ? MouseButton.Right : ret;
ret = ImGui.IsItemClicked( ImGuiMouseButton.Middle ) ? MouseButton.Middle : ret;
if( ret != MouseButton.None )
{
_base._penumbra.Api.InvokeClick( ret, data );
}
if( _base._penumbra.Api.HasTooltip && ImGui.IsItemHovered() )
{
ImGui.BeginTooltip();
raii.Push( ImGui.EndTooltip );
_base._penumbra.Api.InvokeTooltip( data );
raii.Pop();
}
if( data is Item it )
{
var modelId = $"({( ( Quad )it.ModelMain ).A})";
var offset = ImGui.CalcTextSize( modelId ).X - ImGui.GetStyle().ItemInnerSpacing.X;
ImGui.SameLine(ImGui.GetWindowContentRegionWidth() - offset);
ImGui.TextColored( new Vector4(0.5f, 0.5f, 0.5f, 1 ), modelId );
}
_base.DrawChangedItem( name, data );
}
}

View file

@ -7,7 +7,6 @@ using System.Text.RegularExpressions;
using Dalamud.Interface;
using Dalamud.Logging;
using ImGuiNET;
using Penumbra.GameData.Enums;
using Penumbra.Interop;
using Penumbra.Mods;
using Penumbra.UI.Custom;

View file

@ -19,9 +19,10 @@ namespace Penumbra.UI
private readonly TabSettings _settingsTab;
private readonly TabImport _importTab;
private readonly TabBrowser _browserTab;
private readonly TabEffective _effectiveTab;
private readonly TabChangedItems _changedItems;
internal readonly TabCollections CollectionsTab;
internal readonly TabInstalled InstalledTab;
private readonly TabEffective _effectiveTab;
public SettingsMenu( SettingsInterface ui )
{
@ -32,6 +33,7 @@ namespace Penumbra.UI
InstalledTab = new TabInstalled( _base );
CollectionsTab = new TabCollections( InstalledTab.Selector );
_effectiveTab = new TabEffective();
_changedItems = new TabChangedItems( _base );
}
#if DEBUG
@ -72,7 +74,7 @@ namespace Penumbra.UI
{
_browserTab.Draw();
InstalledTab.Draw();
_changedItems.Draw();
if( Penumbra.Config.ShowAdvanced )
{
_effectiveTab.Draw();

39
Penumbra/UI/UiHelpers.cs Normal file
View file

@ -0,0 +1,39 @@
using System.Numerics;
using ImGuiNET;
using Lumina.Data.Parsing;
using Lumina.Excel.GeneratedSheets;
using Penumbra.GameData.Enums;
using Penumbra.UI.Custom;
namespace Penumbra.UI
{
public partial class SettingsInterface
{
internal void DrawChangedItem( string name, object? data )
{
var ret = ImGui.Selectable( name ) ? MouseButton.Left : MouseButton.None;
ret = ImGui.IsItemClicked( ImGuiMouseButton.Right ) ? MouseButton.Right : ret;
ret = ImGui.IsItemClicked( ImGuiMouseButton.Middle ) ? MouseButton.Middle : ret;
if( ret != MouseButton.None )
{
_penumbra.Api.InvokeClick( ret, data );
}
if( _penumbra.Api.HasTooltip && ImGui.IsItemHovered() )
{
ImGui.BeginTooltip();
using var tooltip = ImGuiRaii.DeferredEnd( ImGui.EndTooltip );
_penumbra.Api.InvokeTooltip( data );
}
if( data is Item it )
{
var modelId = $"({( ( Quad )it.ModelMain ).A})";
var offset = ImGui.CalcTextSize( modelId ).X - ImGui.GetStyle().ItemInnerSpacing.X;
ImGui.SameLine( ImGui.GetWindowContentRegionWidth() - offset );
ImGui.TextColored( new Vector4( 0.5f, 0.5f, 0.5f, 1 ), modelId );
}
}
}
}