From 1be3b06292d2a234dc7b5c2870122ad102684ddd Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Wed, 12 Oct 2022 17:23:11 +0200 Subject: [PATCH] Improve IMC Exception Handling. --- .../Import/TexToolsMeta.Deserialization.cs | 4 +-- Penumbra/Meta/Files/ImcFile.cs | 33 +++++++++++++++---- Penumbra/Meta/Manager/MetaManager.Imc.cs | 13 +++++--- Penumbra/Penumbra.cs | 9 +++-- Penumbra/UI/ConfigWindow.cs | 17 ++++++++-- 5 files changed, 56 insertions(+), 20 deletions(-) diff --git a/Penumbra/Import/TexToolsMeta.Deserialization.cs b/Penumbra/Import/TexToolsMeta.Deserialization.cs index e2428cbb..0142e444 100644 --- a/Penumbra/Import/TexToolsMeta.Deserialization.cs +++ b/Penumbra/Import/TexToolsMeta.Deserialization.cs @@ -132,7 +132,7 @@ public partial class TexToolsMeta { if( metaFileInfo.PrimaryType is ObjectType.Equipment or ObjectType.Accessory ) { - var def = new ImcFile( new ImcManipulation( metaFileInfo.EquipSlot, i, metaFileInfo.PrimaryId, new ImcEntry() ).GamePath() ); + var def = new ImcFile( new ImcManipulation( metaFileInfo.EquipSlot, i, metaFileInfo.PrimaryId, new ImcEntry() ) ); var partIdx = ImcFile.PartIndex( metaFileInfo.EquipSlot ); foreach( var value in values ) { @@ -148,7 +148,7 @@ public partial class TexToolsMeta { var def = new ImcFile( new ImcManipulation( metaFileInfo.PrimaryType, metaFileInfo.SecondaryType, metaFileInfo.PrimaryId, metaFileInfo.SecondaryId, i, - new ImcEntry() ).GamePath() ); + new ImcEntry() ) ); foreach( var value in values ) { if( !value.Equals( def.GetEntry( 0, i ) ) ) diff --git a/Penumbra/Meta/Files/ImcFile.cs b/Penumbra/Meta/Files/ImcFile.cs index dc9fe001..f1309e64 100644 --- a/Penumbra/Meta/Files/ImcFile.cs +++ b/Penumbra/Meta/Files/ImcFile.cs @@ -5,6 +5,7 @@ using Penumbra.GameData.ByteString; using Penumbra.GameData.Enums; using Penumbra.GameData.Util; using Penumbra.Interop.Structs; +using Penumbra.Meta.Manipulations; namespace Penumbra.Meta.Files; @@ -54,6 +55,24 @@ public readonly struct ImcEntry : IEquatable< ImcEntry > } } +public class ImcException : Exception +{ + public readonly ImcManipulation Manipulation; + public readonly string GamePath; + + public ImcException( ImcManipulation manip, Utf8GamePath path ) + { + Manipulation = manip; + GamePath = path.ToString(); + } + + public override string Message + => "Could not obtain default Imc File.\n" + + " Either the default file does not exist (possibly for offhand files from TexTools) or the installation is corrupted.\n" + + $" Game Path: {GamePath}\n" + + $" Manipulation: {Manipulation}"; +} + public unsafe class ImcFile : MetaBaseFile { private const int PreambleSize = 4; @@ -174,16 +193,14 @@ public unsafe class ImcFile : MetaBaseFile } } - public ImcFile( Utf8GamePath path ) + public ImcFile( ImcManipulation manip ) : base( 0 ) { - Path = path; - var file = Dalamud.GameData.GetFile( path.ToString() ); + Path = manip.GamePath(); + var file = Dalamud.GameData.GetFile( Path.ToString() ); if( file == null ) { - throw new Exception( - "Could not obtain default Imc File.\n" - + "Either the default file does not exist (possibly for offhand files from TexTools) or the installation is corrupted." ); + throw new ImcException( manip, Path ); } fixed( byte* ptr = file.Data ) @@ -211,6 +228,7 @@ public unsafe class ImcFile : MetaBaseFile exists = true; return *entry; } + return new ImcEntry(); } } @@ -221,9 +239,10 @@ public unsafe class ImcFile : MetaBaseFile var newData = Penumbra.MetaFileManager.AllocateDefaultMemory( ActualLength, 8 ); if( newData == null ) { - Penumbra.Log.Error($"Could not replace loaded IMC data at 0x{(ulong) resource:X}, allocation failed." ); + Penumbra.Log.Error( $"Could not replace loaded IMC data at 0x{( ulong )resource:X}, allocation failed." ); return; } + Functions.MemCpyUnchecked( newData, Data, ActualLength ); Penumbra.MetaFileManager.Free( data, length ); diff --git a/Penumbra/Meta/Manager/MetaManager.Imc.cs b/Penumbra/Meta/Manager/MetaManager.Imc.cs index cb586415..5887aba2 100644 --- a/Penumbra/Meta/Manager/MetaManager.Imc.cs +++ b/Penumbra/Meta/Manager/MetaManager.Imc.cs @@ -58,7 +58,7 @@ public partial class MetaManager { if( !_imcFiles.TryGetValue( path, out var file ) ) { - file = new ImcFile( path ); + file = new ImcFile( manip ); } if( !manip.Apply( file ) ) @@ -75,12 +75,17 @@ public partial class MetaManager return true; } + catch( ImcException e ) + { + Penumbra.ImcExceptions.Add( e ); + Penumbra.Log.Error( e.ToString() ); + } catch( Exception e ) { - ++Penumbra.ImcExceptions; - Penumbra.Log.Error( $"Could not apply IMC Manipulation:\n{e}" ); - return false; + Penumbra.Log.Error( $"Could not apply IMC Manipulation {manip}:\n{e}" ); } + + return false; } public bool RevertMod( ImcManipulation m ) diff --git a/Penumbra/Penumbra.cs b/Penumbra/Penumbra.cs index e556c740..5e886c27 100644 --- a/Penumbra/Penumbra.cs +++ b/Penumbra/Penumbra.cs @@ -17,7 +17,6 @@ using OtterGui.Log; using OtterGui.Widgets; using Penumbra.Api; using Penumbra.Api.Enums; -using Penumbra.GameData.Enums; using Penumbra.Interop; using Penumbra.UI; using Penumbra.Util; @@ -25,7 +24,6 @@ using Penumbra.Collections; 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; @@ -57,7 +55,7 @@ public class Penumbra : IDalamudPlugin public static TempModManager TempMods { get; private set; } = null!; public static ResourceLoader ResourceLoader { get; private set; } = null!; public static FrameworkManager Framework { get; private set; } = null!; - public static int ImcExceptions = 0; + public static readonly List< Exception > ImcExceptions = new(); public readonly ResourceLogger ResourceLogger; public readonly PathResolver PathResolver; @@ -134,11 +132,10 @@ public class Penumbra : IDalamudPlugin { ResidentResources.Reload(); } - Api = new PenumbraApi( this ); IpcProviders = new PenumbraIpcProviders( Dalamud.PluginInterface, Api ); SubscribeItemLinks(); - if( ImcExceptions > 0 ) + if( ImcExceptions.Count > 0 ) { Log.Error( $"{ImcExceptions} IMC Exceptions thrown. Please repair your game files." ); } @@ -205,6 +202,7 @@ public class Penumbra : IDalamudPlugin ResidentResources.Reload(); ObjectReloader.RedrawAll( RedrawType.Redraw ); } + EnabledChange?.Invoke( true ); return true; @@ -227,6 +225,7 @@ public class Penumbra : IDalamudPlugin ResidentResources.Reload(); ObjectReloader.RedrawAll( RedrawType.Redraw ); } + EnabledChange?.Invoke( false ); return true; diff --git a/Penumbra/UI/ConfigWindow.cs b/Penumbra/UI/ConfigWindow.cs index 6a46ca1b..e9ea7eff 100644 --- a/Penumbra/UI/ConfigWindow.cs +++ b/Penumbra/UI/ConfigWindow.cs @@ -3,6 +3,7 @@ using System.Numerics; using Dalamud.Interface; using Dalamud.Interface.Windowing; using ImGuiNET; +using OtterGui; using OtterGui.Raii; using Penumbra.UI.Classes; @@ -53,9 +54,9 @@ public sealed partial class ConfigWindow : Window, IDisposable { try { - if( Penumbra.ImcExceptions > 0 ) + if( Penumbra.ImcExceptions.Count > 0 ) { - DrawProblemWindow( $"There were {Penumbra.ImcExceptions} errors while trying to load IMC files from the game data.\n" + DrawProblemWindow( $"There were {Penumbra.ImcExceptions.Count} errors while trying to load IMC files from the game data.\n" + "This usually means that your game installation was corrupted by updating the game while having TexTools mods still active.\n" + "It is recommended to not use TexTools and Penumbra (or other Lumina-based tools) at the same time.\n\n" + "Please use the Launcher's Repair Game Files function to repair your client installation." ); @@ -108,6 +109,18 @@ public sealed partial class ConfigWindow : Window, IDisposable SettingsTab.DrawDiscordButton( 0 ); ImGui.SameLine(); SettingsTab.DrawSupportButton(); + ImGui.NewLine(); + ImGui.NewLine(); + + ImGui.TextUnformatted( "Exceptions" ); + ImGui.Separator(); + using var box = ImRaii.ListBox( "##Exceptions", new Vector2(-1, -1) ); + foreach( var exception in Penumbra.ImcExceptions ) + { + ImGuiUtil.TextWrapped( exception.ToString() ); + ImGui.Separator(); + ImGui.NewLine(); + } } public void Dispose()