diff --git a/Penumbra/Api/IPenumbraApi.cs b/Penumbra/Api/IPenumbraApi.cs index 65b406ca..43ccd0c5 100644 --- a/Penumbra/Api/IPenumbraApi.cs +++ b/Penumbra/Api/IPenumbraApi.cs @@ -10,7 +10,11 @@ namespace Penumbra.Api; public interface IPenumbraApiBase { - public int ApiVersion { get; } + // The API version is staggered in two parts. + // The major/Breaking version only increments if there are changes breaking backwards compatibility. + // The minor/Feature version increments any time there is something added + // and resets when Breaking is incremented. + public (int Breaking, int Feature) ApiVersion { get; } public bool Valid { get; } } diff --git a/Penumbra/Api/IpcTester.cs b/Penumbra/Api/IpcTester.cs index b457aaf1..87669449 100644 --- a/Penumbra/Api/IpcTester.cs +++ b/Penumbra/Api/IpcTester.cs @@ -104,7 +104,7 @@ public class IpcTester : IDisposable return; } - ImGui.TextUnformatted( $"API Version: {_ipc.Api.ApiVersion}" ); + ImGui.TextUnformatted( $"API Version: {_ipc.Api.ApiVersion.Breaking}.{_ipc.Api.ApiVersion.Feature:D4}" ); ImGui.TextUnformatted( "Available subscriptions:" ); using var indent = ImRaii.PushIndent(); @@ -168,8 +168,9 @@ public class IpcTester : IDisposable DrawList( PenumbraIpc.LabelProviderDisposed, "Last Disposed", _disposedList ); DrawIntro( PenumbraIpc.LabelProviderPostSettingsDraw, "Last Drawn Mod" ); ImGui.TextUnformatted( _lastDrawnMod.Length > 0 ? $"{_lastDrawnMod} at {_lastDrawnModTime}" : "None" ); - DrawIntro( PenumbraIpc.LabelProviderApiVersion, "Current Version" ); - ImGui.TextUnformatted( _pi.GetIpcSubscriber< int >( PenumbraIpc.LabelProviderApiVersion ).InvokeFunc().ToString() ); + DrawIntro( PenumbraIpc.LabelProviderApiVersions, "Current Version" ); + var (breaking, features) = _pi.GetIpcSubscriber< (int, int) >( PenumbraIpc.LabelProviderApiVersions ).InvokeFunc(); + ImGui.TextUnformatted( $"{breaking}.{features:D4}" ); DrawIntro( PenumbraIpc.LabelProviderGetModDirectory, "Current Mod Directory" ); ImGui.TextUnformatted( _pi.GetIpcSubscriber< string >( PenumbraIpc.LabelProviderGetModDirectory ).InvokeFunc() ); DrawIntro( PenumbraIpc.LabelProviderGetConfiguration, "Configuration" ); diff --git a/Penumbra/Api/PenumbraApi.cs b/Penumbra/Api/PenumbraApi.cs index b15ff691..7797b2c9 100644 --- a/Penumbra/Api/PenumbraApi.cs +++ b/Penumbra/Api/PenumbraApi.cs @@ -20,8 +20,8 @@ namespace Penumbra.Api; public class PenumbraApi : IDisposable, IPenumbraApi { - public int ApiVersion - => 6; + public (int, int) ApiVersion + => ( 4, 8 ); private Penumbra? _penumbra; private Lumina.GameData? _lumina; diff --git a/Penumbra/Api/PenumbraIpc.cs b/Penumbra/Api/PenumbraIpc.cs index 4b14650d..ac443531 100644 --- a/Penumbra/Api/PenumbraIpc.cs +++ b/Penumbra/Api/PenumbraIpc.cs @@ -47,18 +47,20 @@ public partial class PenumbraIpc public const string LabelProviderInitialized = "Penumbra.Initialized"; public const string LabelProviderDisposed = "Penumbra.Disposed"; public const string LabelProviderApiVersion = "Penumbra.ApiVersion"; + public const string LabelProviderApiVersions = "Penumbra.ApiVersions"; public const string LabelProviderGetModDirectory = "Penumbra.GetModDirectory"; public const string LabelProviderGetConfiguration = "Penumbra.GetConfiguration"; public const string LabelProviderPreSettingsDraw = "Penumbra.PreSettingsDraw"; public const string LabelProviderPostSettingsDraw = "Penumbra.PostSettingsDraw"; - internal ICallGateProvider< object? >? ProviderInitialized; - internal ICallGateProvider< object? >? ProviderDisposed; - internal ICallGateProvider< int >? ProviderApiVersion; - internal ICallGateProvider< string >? ProviderGetModDirectory; - internal ICallGateProvider< string >? ProviderGetConfiguration; - internal ICallGateProvider< string, object? >? ProviderPreSettingsDraw; - internal ICallGateProvider< string, object? >? ProviderPostSettingsDraw; + internal ICallGateProvider< object? >? ProviderInitialized; + internal ICallGateProvider< object? >? ProviderDisposed; + internal ICallGateProvider< int >? ProviderApiVersion; + internal ICallGateProvider< (int Breaking, int Features) >? ProviderApiVersions; + internal ICallGateProvider< string >? ProviderGetModDirectory; + internal ICallGateProvider< string >? ProviderGetConfiguration; + internal ICallGateProvider< string, object? >? ProviderPreSettingsDraw; + internal ICallGateProvider< string, object? >? ProviderPostSettingsDraw; private void InitializeGeneralProviders( DalamudPluginInterface pi ) { @@ -83,13 +85,27 @@ public partial class PenumbraIpc try { ProviderApiVersion = pi.GetIpcProvider< int >( LabelProviderApiVersion ); - ProviderApiVersion.RegisterFunc( () => Api.ApiVersion ); + ProviderApiVersion.RegisterFunc( () => + { + PluginLog.Warning( $"{LabelProviderApiVersion} is outdated. Please use {LabelProviderApiVersions} instead." ); + return Api.ApiVersion.Breaking; + } ); } catch( Exception e ) { PluginLog.Error( $"Error registering IPC provider for {LabelProviderApiVersion}:\n{e}" ); } + try + { + ProviderApiVersions = pi.GetIpcProvider< ( int, int ) >( LabelProviderApiVersions ); + ProviderApiVersions.RegisterFunc( () => Api.ApiVersion ); + } + catch( Exception e ) + { + PluginLog.Error( $"Error registering IPC provider for {LabelProviderApiVersions}:\n{e}" ); + } + try { ProviderGetModDirectory = pi.GetIpcProvider< string >( LabelProviderGetModDirectory ); @@ -136,6 +152,7 @@ public partial class PenumbraIpc ProviderGetConfiguration?.UnregisterFunc(); ProviderGetModDirectory?.UnregisterFunc(); ProviderApiVersion?.UnregisterFunc(); + ProviderApiVersions?.UnregisterFunc(); Api.PreSettingsPanelDraw -= InvokeSettingsPreDraw; Api.PostSettingsPanelDraw -= InvokeSettingsPostDraw; } diff --git a/Penumbra/Import/Dds/DdsFile.cs b/Penumbra/Import/Dds/DdsFile.cs index 1b0f973a..ec67ea3b 100644 --- a/Penumbra/Import/Dds/DdsFile.cs +++ b/Penumbra/Import/Dds/DdsFile.cs @@ -229,7 +229,7 @@ public class DdsFile public class TmpTexFile { public TexFile.TexHeader Header; - public byte[] RgbaData; + public byte[] RgbaData = Array.Empty< byte >(); public void Load( BinaryReader br ) {