From 173a132d6e0fe7bb1c172e862aba491b5e629d05 Mon Sep 17 00:00:00 2001 From: Garry Newman Date: Sat, 13 Apr 2019 22:02:52 +0100 Subject: [PATCH] SteamApiCallback to result --- Facepunch.Steamworks.Test/Client/AppTest.cs | 5 + .../Callbacks/ISteamCallback.cs | 11 ++ .../{SteamApiCallback.cs => Result.cs} | 14 +- Facepunch.Steamworks/Client/App.cs | 2 +- .../Generated/Interfaces/ISteamApps.cs | 2 +- .../Generated/Interfaces/ISteamUtils.cs | 2 +- Facepunch.Steamworks/Redux/Apps.cs | 1 + .../SteamNative/SteamNative.Structs.cs | 166 ++++++++++++++++++ Generator/CodeWriter/Types/BaseType.cs | 2 +- Generator/steam_api_missing.json | 27 ++- 10 files changed, 205 insertions(+), 27 deletions(-) create mode 100644 Facepunch.Steamworks/Callbacks/ISteamCallback.cs rename Facepunch.Steamworks/Callbacks/{SteamApiCallback.cs => Result.cs} (70%) diff --git a/Facepunch.Steamworks.Test/Client/AppTest.cs b/Facepunch.Steamworks.Test/Client/AppTest.cs index fedf1cd..a796796 100644 --- a/Facepunch.Steamworks.Test/Client/AppTest.cs +++ b/Facepunch.Steamworks.Test/Client/AppTest.cs @@ -17,6 +17,11 @@ public static void AssemblyInit( TestContext context ) Steamworks.Steam.Init( 4000 ); } + static void OnNewUrlLaunchParameters() + { + // Wow! + } + [TestMethod] public void GameLangauge() { diff --git a/Facepunch.Steamworks/Callbacks/ISteamCallback.cs b/Facepunch.Steamworks/Callbacks/ISteamCallback.cs new file mode 100644 index 0000000..5778851 --- /dev/null +++ b/Facepunch.Steamworks/Callbacks/ISteamCallback.cs @@ -0,0 +1,11 @@ +using System; + +namespace Steamworks +{ + public interface ISteamCallback + { + int GetCallbackId(); + int GetStructSize(); + ISteamCallback Fill( IntPtr ptr, int size ); + } +} \ No newline at end of file diff --git a/Facepunch.Steamworks/Callbacks/SteamApiCallback.cs b/Facepunch.Steamworks/Callbacks/Result.cs similarity index 70% rename from Facepunch.Steamworks/Callbacks/SteamApiCallback.cs rename to Facepunch.Steamworks/Callbacks/Result.cs index f452318..8324271 100644 --- a/Facepunch.Steamworks/Callbacks/SteamApiCallback.cs +++ b/Facepunch.Steamworks/Callbacks/Result.cs @@ -7,11 +7,14 @@ namespace Steamworks { - public struct SteamApiCallback where T : struct, ISteamCallback + /// + /// Results are Steam Callbacks that are direct responses to function calls + /// + public struct Result where T : struct, ISteamCallback { public ulong CallHandle; - public SteamApiCallback( ulong callbackHandle ) + public Result( ulong callbackHandle ) { CallHandle = callbackHandle; } @@ -36,11 +39,4 @@ public bool IsComplete( out bool failed ) return Utils.GetResult( CallHandle ); } } - - public interface ISteamCallback - { - int GetCallbackId(); - int GetStructSize(); - ISteamCallback Fill( IntPtr ptr, int size ); - } } \ No newline at end of file diff --git a/Facepunch.Steamworks/Client/App.cs b/Facepunch.Steamworks/Client/App.cs index 404887b..a94a052 100644 --- a/Facepunch.Steamworks/Client/App.cs +++ b/Facepunch.Steamworks/Client/App.cs @@ -17,7 +17,7 @@ internal App( Client c ) client.RegisterCallback( DlcInstalled ); } - public delegate void DlcInstalledDelegate( uint appid ); + public delegate void DlcInstalledDelegate( uint appid ); /// /// Triggered after the current user gains ownership of DLC and that DLC is installed. diff --git a/Facepunch.Steamworks/Generated/Interfaces/ISteamApps.cs b/Facepunch.Steamworks/Generated/Interfaces/ISteamApps.cs index de33f68..43cd912 100644 --- a/Facepunch.Steamworks/Generated/Interfaces/ISteamApps.cs +++ b/Facepunch.Steamworks/Generated/Interfaces/ISteamApps.cs @@ -340,7 +340,7 @@ public void RequestAllProofOfPurchaseKeys() #endregion public async Task GetFileDetails( string pszFileName ) { - return await (new SteamApiCallback( GetFileDetailsDelegatePointer( Self, pszFileName ) )).GetResult(); + return await (new Result( GetFileDetailsDelegatePointer( Self, pszFileName ) )).GetResult(); } #region FunctionMeta diff --git a/Facepunch.Steamworks/Generated/Interfaces/ISteamUtils.cs b/Facepunch.Steamworks/Generated/Interfaces/ISteamUtils.cs index 59b4e92..271bfe7 100644 --- a/Facepunch.Steamworks/Generated/Interfaces/ISteamUtils.cs +++ b/Facepunch.Steamworks/Generated/Interfaces/ISteamUtils.cs @@ -269,7 +269,7 @@ public bool BOverlayNeedsPresent() #endregion public async Task CheckFileSignature( string szFileName ) { - return await (new SteamApiCallback( CheckFileSignatureDelegatePointer( Self, szFileName ) )).GetResult(); + return await (new Result( CheckFileSignatureDelegatePointer( Self, szFileName ) )).GetResult(); } #region FunctionMeta diff --git a/Facepunch.Steamworks/Redux/Apps.cs b/Facepunch.Steamworks/Redux/Apps.cs index 7427870..6b092cb 100644 --- a/Facepunch.Steamworks/Redux/Apps.cs +++ b/Facepunch.Steamworks/Redux/Apps.cs @@ -24,6 +24,7 @@ internal static Internal.ISteamApps steamapps } } + /// /// Checks if the active user is subscribed to the current App ID /// diff --git a/Facepunch.Steamworks/SteamNative/SteamNative.Structs.cs b/Facepunch.Steamworks/SteamNative/SteamNative.Structs.cs index 68135fc..febbb8a 100644 --- a/Facepunch.Steamworks/SteamNative/SteamNative.Structs.cs +++ b/Facepunch.Steamworks/SteamNative/SteamNative.Structs.cs @@ -31481,6 +31481,171 @@ internal static void OnResultWithInfo( IntPtr param, bool failure, SteamNative.S } } + public struct NewUrlLaunchParameters_t : Steamworks.ISteamCallback + { + internal const int CallbackId = CallbackIdentifiers.SteamApps + 14; + public int GetCallbackId() => CallbackId; + public int GetStructSize() => StructSize(); + public Steamworks.ISteamCallback Fill( IntPtr p, int size) + { + return FromPointer( p ); // TODO - USE SIZE HERE SOMEHOW + } + + // + // Read this struct from a pointer, usually from Native. It will automatically do the awesome stuff. + // + internal static NewUrlLaunchParameters_t FromPointer( IntPtr p ) => + Platform.PackSmall ? ((NewUrlLaunchParameters_t)(Pack4) Marshal.PtrToStructure( p, typeof(Pack4) )) : ((NewUrlLaunchParameters_t)(Pack8) Marshal.PtrToStructure( p, typeof(Pack8) )); + + // + // Get the size of the structure we're going to be using. + // + internal static int StructSize() + { + return System.Runtime.InteropServices.Marshal.SizeOf( Platform.PackSmall ? typeof(Pack4) : typeof(Pack8) ); + } + + [StructLayout( LayoutKind.Sequential, Pack = 4 )] + public struct Pack4 + { + + public static implicit operator NewUrlLaunchParameters_t ( NewUrlLaunchParameters_t.Pack4 d ) => new NewUrlLaunchParameters_t{ }; + } + + [StructLayout( LayoutKind.Sequential, Pack = 8 )] + public struct Pack8 + { + + public static implicit operator NewUrlLaunchParameters_t ( NewUrlLaunchParameters_t.Pack8 d ) => new NewUrlLaunchParameters_t{ }; + } + + internal static void Register( Facepunch.Steamworks.BaseSteamworks steamworks ) + { + var handle = new CallbackHandle( steamworks ); + + // + // Create the functions we need for the vtable + // + if ( Facepunch.Steamworks.Config.UseThisCall ) + { + // + // Create the VTable by manually allocating the memory and copying across + // + if ( Platform.IsWindows ) + { + handle.vTablePtr = Marshal.AllocHGlobal( Marshal.SizeOf( typeof( Callback.VTableWinThis ) ) ); + var vTable = new Callback.VTableWinThis + { + ResultA = OnResultThis, + ResultB = OnResultWithInfoThis, + GetSize = OnGetSizeThis, + }; + handle.FuncA = GCHandle.Alloc( vTable.ResultA ); + handle.FuncB = GCHandle.Alloc( vTable.ResultB ); + handle.FuncC = GCHandle.Alloc( vTable.GetSize ); + Marshal.StructureToPtr( vTable, handle.vTablePtr, false ); + } + else + { + handle.vTablePtr = Marshal.AllocHGlobal( Marshal.SizeOf( typeof( Callback.VTableThis ) ) ); + var vTable = new Callback.VTableThis + { + ResultA = OnResultThis, + ResultB = OnResultWithInfoThis, + GetSize = OnGetSizeThis, + }; + handle.FuncA = GCHandle.Alloc( vTable.ResultA ); + handle.FuncB = GCHandle.Alloc( vTable.ResultB ); + handle.FuncC = GCHandle.Alloc( vTable.GetSize ); + Marshal.StructureToPtr( vTable, handle.vTablePtr, false ); + } + } + else + { + // + // Create the VTable by manually allocating the memory and copying across + // + if ( Platform.IsWindows ) + { + handle.vTablePtr = Marshal.AllocHGlobal( Marshal.SizeOf( typeof( Callback.VTableWin ) ) ); + var vTable = new Callback.VTableWin + { + ResultA = OnResult, + ResultB = OnResultWithInfo, + GetSize = OnGetSize, + }; + handle.FuncA = GCHandle.Alloc( vTable.ResultA ); + handle.FuncB = GCHandle.Alloc( vTable.ResultB ); + handle.FuncC = GCHandle.Alloc( vTable.GetSize ); + Marshal.StructureToPtr( vTable, handle.vTablePtr, false ); + } + else + { + handle.vTablePtr = Marshal.AllocHGlobal( Marshal.SizeOf( typeof( Callback.VTable ) ) ); + var vTable = new Callback.VTable + { + ResultA = OnResult, + ResultB = OnResultWithInfo, + GetSize = OnGetSize, + }; + handle.FuncA = GCHandle.Alloc( vTable.ResultA ); + handle.FuncB = GCHandle.Alloc( vTable.ResultB ); + handle.FuncC = GCHandle.Alloc( vTable.GetSize ); + Marshal.StructureToPtr( vTable, handle.vTablePtr, false ); + } + } + + // + // Create the callback object + // + var cb = new Callback(); + cb.vTablePtr = handle.vTablePtr; + cb.CallbackFlags = steamworks.IsGameServer ? (byte) SteamNative.Callback.Flags.GameServer : (byte) 0; + cb.CallbackId = CallbackId; + + // + // Pin the callback, so it doesn't get garbage collected and we can pass the pointer to native + // + handle.PinnedCallback = GCHandle.Alloc( cb, GCHandleType.Pinned ); + + // + // Register the callback with Steam + // + steamworks.native.api.SteamAPI_RegisterCallback( handle.PinnedCallback.AddrOfPinnedObject(), CallbackId ); + + steamworks.RegisterCallbackHandle( handle ); + } + + [MonoPInvokeCallback] + internal static void OnResultThis( IntPtr self, IntPtr param ){ OnResult( param ); } + [MonoPInvokeCallback] + internal static void OnResultWithInfoThis( IntPtr self, IntPtr param, bool failure, SteamNative.SteamAPICall_t call ){ OnResultWithInfo( param, failure, call ); } + [MonoPInvokeCallback] + internal static int OnGetSizeThis( IntPtr self ){ return OnGetSize(); } + [MonoPInvokeCallback] + internal static int OnGetSize(){ return StructSize(); } + + [MonoPInvokeCallback] + internal static void OnResult( IntPtr param ) + { + OnResultWithInfo( param, false, 0 ); + } + + [MonoPInvokeCallback] + internal static void OnResultWithInfo( IntPtr param, bool failure, SteamNative.SteamAPICall_t call ) + { + if ( failure ) return; + + var value = FromPointer( param ); + + if ( Facepunch.Steamworks.Client.Instance != null ) + Facepunch.Steamworks.Client.Instance.OnCallback( value ); + + if ( Facepunch.Steamworks.Server.Instance != null ) + Facepunch.Steamworks.Server.Instance.OnCallback( value ); + } + } + public struct ItemInstalled_t : Steamworks.ISteamCallback { internal const int CallbackId = CallbackIdentifiers.ClientUGC + 5; @@ -33670,6 +33835,7 @@ internal static void RegisterCallbacks( Facepunch.Steamworks.BaseSteamworks stea GSStatsReceived_t.Register( steamworks ); GSStatsStored_t.Register( steamworks ); GSStatsUnloaded_t.Register( steamworks ); + NewUrlLaunchParameters_t.Register( steamworks ); ItemInstalled_t.Register( steamworks ); SteamInventoryDefinitionUpdate_t.Register( steamworks ); SteamParentalSettingsChanged_t.Register( steamworks ); diff --git a/Generator/CodeWriter/Types/BaseType.cs b/Generator/CodeWriter/Types/BaseType.cs index 53ad04e..b979ad9 100644 --- a/Generator/CodeWriter/Types/BaseType.cs +++ b/Generator/CodeWriter/Types/BaseType.cs @@ -73,7 +73,7 @@ internal class SteamApiCallType : BaseType { public string CallResult; public override string TypeName => "SteamAPICall_t"; - public override string Return( string varname ) => $"return await (new SteamApiCallback<{CallResult}>( {varname} )).GetResult();"; + public override string Return( string varname ) => $"return await (new Result<{CallResult}>( {varname} )).GetResult();"; public override string ReturnType => $"async Task<{CallResult}?>"; } diff --git a/Generator/steam_api_missing.json b/Generator/steam_api_missing.json index 22e91ac..7216000 100644 --- a/Generator/steam_api_missing.json +++ b/Generator/steam_api_missing.json @@ -1,10 +1,14 @@ { - "structs": - [ + "structs": [ + { + "struct": "NewUrlLaunchParameters_t", + "fields": [ + ] + }, + { "struct": "ItemInstalled_t", - "fields": - [ + "fields": [ { "fieldname": "m_unAppID", "fieldtype": "AppId_t" @@ -18,8 +22,7 @@ { "struct": "InputAnalogActionData_t", - "fields": - [ + "fields": [ { "fieldname": "eMode", "fieldtype": "EInputSourceMode" @@ -41,8 +44,7 @@ { "struct": "InputMotionData_t", - "fields": - [ + "fields": [ { "fieldname": "rotQuatX", "fieldtype": "float" @@ -98,8 +100,7 @@ { "struct": "InputDigitalActionData_t", - "fields": - [ + "fields": [ { "fieldname": "bState", "fieldtype": "bool" @@ -128,8 +129,7 @@ { "struct": "GCMessageAvailable_t", - "fields": - [ + "fields": [ { "fieldname": "m_nMessageSize", "fieldtype": "uint32" @@ -153,8 +153,7 @@ }, { "struct": "IPCFailure_t", - "fields": - [ + "fields": [ { "fieldname": "m_eFailureType", "fieldtype": "uint8"