mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 10:17:22 +01:00
Add some methods and interface to view currently Changed Items.
This commit is contained in:
parent
982385ccbb
commit
0c0eeec158
9 changed files with 219 additions and 40 deletions
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
{
|
||||
|
|
@ -97,7 +138,7 @@ namespace Penumbra.Mods
|
|||
else
|
||||
{
|
||||
mod.Cache.AddConflict( oldMod, gamePath );
|
||||
if( !ReferenceEquals( mod, oldMod ) && mod.Settings.Priority == oldMod.Settings.Priority)
|
||||
if( !ReferenceEquals( mod, oldMod ) && mod.Settings.Priority == oldMod.Settings.Priority )
|
||||
{
|
||||
oldMod.Cache.AddConflict( mod, gamePath );
|
||||
}
|
||||
|
|
|
|||
72
Penumbra/UI/MenuTabs/TabChangedItems.cs
Normal file
72
Penumbra/UI/MenuTabs/TabChangedItems.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
39
Penumbra/UI/UiHelpers.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue