diff --git a/OtterGui b/OtterGui index 4e730a0d..aee8a3dc 160000 --- a/OtterGui +++ b/OtterGui @@ -1 +1 @@ -Subproject commit 4e730a0d5a86a9819bcea0b766134c02f35ac27e +Subproject commit aee8a3dc8e7eb1145c328a7c50f7e5bbcdd234f8 diff --git a/Penumbra/Penumbra.cs b/Penumbra/Penumbra.cs index 92ac8385..85f97f9e 100644 --- a/Penumbra/Penumbra.cs +++ b/Penumbra/Penumbra.cs @@ -26,6 +26,7 @@ using Penumbra.GameData.Data; using Penumbra.Interop.Loader; using Penumbra.Interop.Resolver; using Penumbra.Mods; +using Action = System.Action; using CharacterUtility = Penumbra.Interop.CharacterUtility; using ResidentResourceManager = Penumbra.Interop.ResidentResourceManager; @@ -66,8 +67,12 @@ public class Penumbra : IDalamudPlugin public static IGamePathParser GamePathParser { get; private set; } = null!; public static StainManager StainManager { get; private set; } = null!; public static ItemData ItemData { get; private set; } = null!; + + public static PerformanceTracker< PerformanceType > Performance { get; private set; } = null!; + public static StartTimeTracker< StartTimeType > StartTimer = new(); + public static readonly List< Exception > ImcExceptions = new(); public readonly ResourceLogger ResourceLogger; @@ -84,39 +89,59 @@ public class Penumbra : IDalamudPlugin internal WebServer? WebServer; + private static void Timed( StartTimeType type, Action action ) + { + using var t = StartTimer.Measure( type ); + action(); + } + public Penumbra( DalamudPluginInterface pluginInterface ) { + using var time = StartTimer.Measure( StartTimeType.Total ); + try { Dalamud.Initialize( pluginInterface ); + Performance = new PerformanceTracker< PerformanceType >( Dalamud.Framework ); Log = new Logger(); DevPenumbraExists = CheckDevPluginPenumbra(); IsNotInstalledPenumbra = CheckIsNotInstalled(); IsValidSourceRepo = CheckSourceRepo(); - GameEvents = new GameEventManager(); - Identifier = GameData.GameData.GetIdentifier( Dalamud.PluginInterface, Dalamud.GameData ); - GamePathParser = GameData.GameData.GetGamePathParser(); - StainManager = new StainManager( Dalamud.PluginInterface, Dalamud.GameData ); - ItemData = new ItemData( Dalamud.PluginInterface, Dalamud.GameData, Dalamud.GameData.Language ); - Actors = new ActorManager( Dalamud.PluginInterface, Dalamud.Objects, Dalamud.ClientState, Dalamud.Framework, Dalamud.GameData, Dalamud.GameGui, ResolveCutscene ); - Framework = new FrameworkManager(Dalamud.Framework, Log); + GameEvents = new GameEventManager(); + StartTimer.Measure( StartTimeType.Identifier, () => Identifier = GameData.GameData.GetIdentifier( Dalamud.PluginInterface, Dalamud.GameData ) ); + StartTimer.Measure( StartTimeType.GamePathParser, () => GamePathParser = GameData.GameData.GetGamePathParser() ); + StartTimer.Measure( StartTimeType.Stains, () => StainManager = new StainManager( Dalamud.PluginInterface, Dalamud.GameData ) ); + StartTimer.Measure( StartTimeType.Items, () => ItemData = new ItemData( Dalamud.PluginInterface, Dalamud.GameData, Dalamud.GameData.Language ) ); + StartTimer.Measure( StartTimeType.Actors, + () => Actors = new ActorManager( Dalamud.PluginInterface, Dalamud.Objects, Dalamud.ClientState, Dalamud.Framework, Dalamud.GameData, Dalamud.GameGui, + ResolveCutscene ) ); + + Framework = new FrameworkManager( Dalamud.Framework, Log ); CharacterUtility = new CharacterUtility(); - Backup.CreateBackup( pluginInterface.ConfigDirectory, PenumbraBackupFiles() ); + StartTimer.Measure( StartTimeType.Backup, () => Backup.CreateBackup( pluginInterface.ConfigDirectory, PenumbraBackupFiles() ) ); Config = Configuration.Load(); - + TempMods = new TempModManager(); MetaFileManager = new MetaFileManager(); ResourceLoader = new ResourceLoader( this ); ResourceLoader.EnableHooks(); ResourceLogger = new ResourceLogger( ResourceLoader ); ResidentResources = new ResidentResourceManager(); - ModManager = new Mod.Manager( Config.ModDirectory ); - ModManager.DiscoverMods(); - CollectionManager = new ModCollection.Manager( ModManager ); - CollectionManager.CreateNecessaryCaches(); + StartTimer.Measure( StartTimeType.Mods, () => + { + ModManager = new Mod.Manager( Config.ModDirectory ); + ModManager.DiscoverMods(); + } ); + + StartTimer.Measure( StartTimeType.Collections, () => + { + CollectionManager = new ModCollection.Manager( ModManager ); + CollectionManager.CreateNecessaryCaches(); + } ); + ModFileSystem = ModFileSystem.Load(); ObjectReloader = new ObjectReloader(); PathResolver = new PathResolver( ResourceLoader ); @@ -146,9 +171,13 @@ public class Penumbra : IDalamudPlugin ResourceLoader.EnableFullLogging(); } - Api = new PenumbraApi( this ); - IpcProviders = new PenumbraIpcProviders( Dalamud.PluginInterface, Api ); - SubscribeItemLinks(); + using( var tAPI = StartTimer.Measure( StartTimeType.Api ) ) + { + Api = new PenumbraApi( this ); + IpcProviders = new PenumbraIpcProviders( Dalamud.PluginInterface, Api ); + SubscribeItemLinks(); + } + if( ImcExceptions.Count > 0 ) { Log.Error( $"{ImcExceptions} IMC Exceptions thrown. Please repair your game files." ); @@ -177,6 +206,7 @@ public class Penumbra : IDalamudPlugin private void SetupInterface( out ConfigWindow cfg, out LaunchButton btn, out WindowSystem system, out Changelog changelog ) { + using var tInterface = StartTimer.Measure( StartTimeType.Interface ); cfg = new ConfigWindow( this ); btn = new LaunchButton( _configWindow ); system = new WindowSystem( Name ); @@ -341,7 +371,7 @@ public class Penumbra : IDalamudPlugin sb.Append( $"> **`Free Drive Space: `** {( drive != null ? Functions.HumanReadableSize( drive.AvailableFreeSpace ) : "Unknown" )}\n" ); sb.Append( $"> **`Auto-Deduplication: `** {Config.AutoDeduplicateOnImport}\n" ); sb.Append( $"> **`Debug Mode: `** {Config.DebugMode}\n" ); - sb.Append( $"> **`Synchronous Load (Dalamud): `** {(Dalamud.GetDalamudConfig( Dalamud.WaitingForPluginsOption, out bool v ) ? v.ToString() : "Unknown")}\n" ); + sb.Append( $"> **`Synchronous Load (Dalamud): `** {( Dalamud.GetDalamudConfig( Dalamud.WaitingForPluginsOption, out bool v ) ? v.ToString() : "Unknown" )}\n" ); sb.Append( $"> **`Logging: `** Full: {Config.EnableFullResourceLogging}, Resource: {Config.EnableResourceLogging}\n" ); sb.Append( $"> **`Use Ownership: `** {Config.UseOwnerNameForCharacterCollection}\n" ); sb.AppendLine( "**Mods**" ); diff --git a/Penumbra/UI/ConfigWindow.DebugTab.cs b/Penumbra/UI/ConfigWindow.DebugTab.cs index 10eded81..19ada144 100644 --- a/Penumbra/UI/ConfigWindow.DebugTab.cs +++ b/Penumbra/UI/ConfigWindow.DebugTab.cs @@ -48,13 +48,13 @@ public partial class ConfigWindow return; } - using var tab = ImRaii.TabItem( "Debug" ); + using var tab = TabItem( "Debug" ); if( !tab ) { return; } - using var child = ImRaii.Child( "##DebugTab", -Vector2.One ); + using var child = Child( "##DebugTab", -Vector2.One ); if( !child ) { return; @@ -93,7 +93,7 @@ public partial class ConfigWindow return; } - using var table = ImRaii.Table( "##DebugGeneralTable", 2, ImGuiTableFlags.SizingFixedFit, + using var table = Table( "##DebugGeneralTable", 2, ImGuiTableFlags.SizingFixedFit, new Vector2( -1, ImGui.GetTextLineHeightWithSpacing() * 1 ) ); if( !table ) { @@ -125,7 +125,9 @@ public partial class ConfigWindow return; } - Penumbra.Performance.Draw( "##performance", "Enable Performance Tracking", PerformanceTypeExtensions.ToName ); + Penumbra.StartTimer.Draw( "##startTimer", TimingExtensions.ToName ); + ImGui.NewLine(); + Penumbra.Performance.Draw( "##performance", "Enable Runtime Performance Tracking", TimingExtensions.ToName ); } // Draw all resources currently replaced by Penumbra and (if existing) the resources they replace. @@ -144,7 +146,7 @@ public partial class ConfigWindow return; } - using var table = ImRaii.Table( "##ReplacedResources", 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit, + using var table = Table( "##ReplacedResources", 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit, -Vector2.UnitX ); if( !table ) { @@ -182,7 +184,7 @@ public partial class ConfigWindow return; } - using var table = ImRaii.Table( "##actors", 4, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit, + using var table = Table( "##actors", 4, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit, -Vector2.UnitX ); if( !table ) { @@ -229,11 +231,11 @@ public partial class ConfigWindow ImGui.TextUnformatted( $"Last Game Object: 0x{_window._penumbra.PathResolver.LastGameObject:X} ({_window._penumbra.PathResolver.LastGameObjectData.ModCollection.Name})" ); - using( var drawTree = ImRaii.TreeNode( "Draw Object to Object" ) ) + using( var drawTree = TreeNode( "Draw Object to Object" ) ) { if( drawTree ) { - using var table = ImRaii.Table( "###DrawObjectResolverTable", 5, ImGuiTableFlags.SizingFixedFit ); + using var table = Table( "###DrawObjectResolverTable", 5, ImGuiTableFlags.SizingFixedFit ); if( table ) { foreach( var (ptr, (c, idx)) in _window._penumbra.PathResolver.DrawObjectMap ) @@ -256,11 +258,11 @@ public partial class ConfigWindow } } - using( var pathTree = ImRaii.TreeNode( "Path Collections" ) ) + using( var pathTree = TreeNode( "Path Collections" ) ) { if( pathTree ) { - using var table = ImRaii.Table( "###PathCollectionResolverTable", 3, ImGuiTableFlags.SizingFixedFit ); + using var table = Table( "###PathCollectionResolverTable", 3, ImGuiTableFlags.SizingFixedFit ); if( table ) { foreach( var (path, collection) in _window._penumbra.PathResolver.PathCollections ) @@ -276,11 +278,11 @@ public partial class ConfigWindow } } - using( var resourceTree = ImRaii.TreeNode( "Subfile Collections" ) ) + using( var resourceTree = TreeNode( "Subfile Collections" ) ) { if( resourceTree ) { - using var table = ImRaii.Table( "###ResourceCollectionResolverTable", 3, ImGuiTableFlags.SizingFixedFit ); + using var table = Table( "###ResourceCollectionResolverTable", 3, ImGuiTableFlags.SizingFixedFit ); if( table ) { ImGuiUtil.DrawTableColumn( "Current Mtrl Data" ); @@ -305,11 +307,11 @@ public partial class ConfigWindow } } - using( var identifiedTree = ImRaii.TreeNode( "Identified Collections" ) ) + using( var identifiedTree = TreeNode( "Identified Collections" ) ) { if( identifiedTree ) { - using var table = ImRaii.Table( "##PathCollectionsIdentifiedTable", 3, ImGuiTableFlags.SizingFixedFit ); + using var table = Table( "##PathCollectionsIdentifiedTable", 3, ImGuiTableFlags.SizingFixedFit ); if( table ) { foreach( var (address, identifier, collection) in PathResolver.IdentifiedCache ) @@ -322,11 +324,11 @@ public partial class ConfigWindow } } - using( var cutsceneTree = ImRaii.TreeNode( "Cutscene Actors" ) ) + using( var cutsceneTree = TreeNode( "Cutscene Actors" ) ) { if( cutsceneTree ) { - using var table = ImRaii.Table( "###PCutsceneResolverTable", 2, ImGuiTableFlags.SizingFixedFit ); + using var table = Table( "###PCutsceneResolverTable", 2, ImGuiTableFlags.SizingFixedFit ); if( table ) { foreach( var (idx, actor) in _window._penumbra.PathResolver.CutsceneActors ) @@ -338,11 +340,11 @@ public partial class ConfigWindow } } - using( var groupTree = ImRaii.TreeNode( "Group" ) ) + using( var groupTree = TreeNode( "Group" ) ) { if( groupTree ) { - using var table = ImRaii.Table( "###PGroupTable", 2, ImGuiTableFlags.SizingFixedFit ); + using var table = Table( "###PGroupTable", 2, ImGuiTableFlags.SizingFixedFit ); if( table ) { ImGuiUtil.DrawTableColumn( "Group Members" ); @@ -357,16 +359,19 @@ public partial class ConfigWindow } } - using( var bannerTree = ImRaii.TreeNode( "Party Banner" ) ) + using( var bannerTree = TreeNode( "Party Banner" ) ) { if( bannerTree ) { var agent = &AgentBannerParty.Instance()->AgentBannerInterface; if( agent->Data == null ) + { agent = &AgentBannerMIP.Instance()->AgentBannerInterface; + } + if( agent->Data != null ) { - using var table = ImRaii.Table( "###PBannerTable", 2, ImGuiTableFlags.SizingFixedFit ); + using var table = Table( "###PBannerTable", 2, ImGuiTableFlags.SizingFixedFit ); if( table ) { for( var i = 0; i < 8; ++i ) @@ -395,13 +400,13 @@ public partial class ConfigWindow foreach( var (key, data) in Penumbra.StainManager.StmFile.Entries ) { - using var tree = ImRaii.TreeNode( $"Template {key}" ); + using var tree = TreeNode( $"Template {key}" ); if( !tree ) { continue; } - using var table = ImRaii.Table( "##table", 5, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg ); + using var table = Table( "##table", 5, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg ); if( !table ) { continue; @@ -436,7 +441,7 @@ public partial class ConfigWindow return; } - using var table = ImRaii.Table( "##CharacterUtility", 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit, + using var table = Table( "##CharacterUtility", 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit, -Vector2.UnitX ); if( !table ) { @@ -491,7 +496,7 @@ public partial class ConfigWindow return; } - using var table = ImRaii.Table( "##DebugMetaTable", 3, ImGuiTableFlags.SizingFixedFit ); + using var table = Table( "##DebugMetaTable", 3, ImGuiTableFlags.SizingFixedFit ); if( !table ) { return; @@ -518,7 +523,7 @@ public partial class ConfigWindow return; } - using var table = ImRaii.Table( "##ResidentResources", 2, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit, + using var table = Table( "##ResidentResources", 2, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit, -Vector2.UnitX ); if( !table ) { @@ -551,7 +556,7 @@ public partial class ConfigWindow return; } - using( var t1 = ImRaii.Table( "##table", 2, ImGuiTableFlags.SizingFixedFit ) ) + using( var t1 = Table( "##table", 2, ImGuiTableFlags.SizingFixedFit ) ) { if( t1 ) { @@ -564,7 +569,7 @@ public partial class ConfigWindow } } - using var table = ImRaii.Table( $"##{name}DrawTable", 5, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit ); + using var table = Table( $"##{name}DrawTable", 5, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit ); if( !table ) { return; @@ -620,7 +625,7 @@ public partial class ConfigWindow return; } - using var table = ImRaii.Table( "##ProblemsTable", 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit ); + using var table = Table( "##ProblemsTable", 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit ); if( !table ) { return; diff --git a/Penumbra/Util/PerformanceType.cs b/Penumbra/Util/PerformanceType.cs index 9328d750..80205f7c 100644 --- a/Penumbra/Util/PerformanceType.cs +++ b/Penumbra/Util/PerformanceType.cs @@ -1,5 +1,24 @@ +using Lumina.Excel.GeneratedSheets; +using OtterGui.Classes; +using Penumbra.GameData; + namespace Penumbra.Util; +public enum StartTimeType +{ + Total, + Identifier, + GamePathParser, + Stains, + Items, + Actors, + Backup, + Mods, + Collections, + Api, + Interface, +} + public enum PerformanceType { UiMainWindow, @@ -28,8 +47,25 @@ public enum PerformanceType DebugTimes, } -public static class PerformanceTypeExtensions +public static class TimingExtensions { + public static string ToName( this StartTimeType type ) + => type switch + { + StartTimeType.Total => "Total Construction", + StartTimeType.Identifier => "Identification Data", + StartTimeType.GamePathParser => "Game Path Data", + StartTimeType.Stains => "Stain Data", + StartTimeType.Items => "Item Data", + StartTimeType.Actors => "Actor Data", + StartTimeType.Backup => "Checking Backups", + StartTimeType.Mods => "Loading Mods", + StartTimeType.Collections => "Loading Collections", + StartTimeType.Api => "Setting Up API", + StartTimeType.Interface => "Setting Up Interface", + _ => $"Unknown {( int )type}", + }; + public static string ToName( this PerformanceType type ) => type switch {