From dcd1ea850370f2f58caf1a144164778d7e6e8940 Mon Sep 17 00:00:00 2001 From: Garry Newman Date: Mon, 15 Apr 2019 10:24:44 +0100 Subject: [PATCH] Steamworks.User functions --- Facepunch.Steamworks/Client/Auth.cs | 1 - .../Generated/Interfaces/ISteamUser.cs | 389 ++++++++++++++++++ .../Redux/Classes/AuthTicket.cs | 30 ++ Facepunch.Steamworks/Redux/User.cs | 265 ++++++++++++ Facepunch.Steamworks/Server/Auth.cs | 3 +- .../SteamNative/SteamNative.Helpers.cs | 34 +- Generator/CodeWriter/CodeWriter.cs | 1 + Generator/CodeWriter/Types/BaseType.cs | 1 + 8 files changed, 721 insertions(+), 3 deletions(-) create mode 100644 Facepunch.Steamworks/Generated/Interfaces/ISteamUser.cs create mode 100644 Facepunch.Steamworks/Redux/Classes/AuthTicket.cs create mode 100644 Facepunch.Steamworks/Redux/User.cs diff --git a/Facepunch.Steamworks/Client/Auth.cs b/Facepunch.Steamworks/Client/Auth.cs index d33ff40..d807ae9 100644 --- a/Facepunch.Steamworks/Client/Auth.cs +++ b/Facepunch.Steamworks/Client/Auth.cs @@ -53,7 +53,6 @@ public void Dispose() } /// - /// Creates an auth ticket. /// Which you can send to a server to authenticate that you are who you say you are. /// public unsafe Ticket GetAuthSessionTicket() diff --git a/Facepunch.Steamworks/Generated/Interfaces/ISteamUser.cs b/Facepunch.Steamworks/Generated/Interfaces/ISteamUser.cs new file mode 100644 index 0000000..b91bf2d --- /dev/null +++ b/Facepunch.Steamworks/Generated/Interfaces/ISteamUser.cs @@ -0,0 +1,389 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using SteamNative; + + +namespace Steamworks.Internal +{ + public class ISteamUser : BaseSteamInterface + { + public override string InterfaceName => "SteamUser020"; + + public override void InitInternals() + { + GetHSteamUserDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 0) ); + BLoggedOnDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 8) ); + GetSteamIDDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 16) ); + InitiateGameConnectionDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 24) ); + TerminateGameConnectionDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 32) ); + TrackAppUsageEventDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 40) ); + GetUserDataFolderDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 48) ); + StartVoiceRecordingDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 56) ); + StopVoiceRecordingDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 64) ); + GetAvailableVoiceDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 72) ); + GetVoiceDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 80) ); + DecompressVoiceDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 88) ); + GetVoiceOptimalSampleRateDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 96) ); + GetAuthSessionTicketDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 104) ); + BeginAuthSessionDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 112) ); + EndAuthSessionDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 120) ); + CancelAuthTicketDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 128) ); + UserHasLicenseForAppDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 136) ); + BIsBehindNATDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 144) ); + AdvertiseGameDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 152) ); + RequestEncryptedAppTicketDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 160) ); + GetEncryptedAppTicketDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 168) ); + GetGameBadgeLevelDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 176) ); + GetPlayerSteamLevelDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 184) ); + RequestStoreAuthURLDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 192) ); + BIsPhoneVerifiedDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 200) ); + BIsTwoFactorEnabledDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 208) ); + BIsPhoneIdentifyingDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 216) ); + BIsPhoneRequiringVerificationDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 224) ); + GetMarketEligibilityDelegatePointer = Marshal.GetDelegateForFunctionPointer( Marshal.ReadIntPtr( VTable, 232) ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate HSteamUser GetHSteamUserDelegate( IntPtr self ); + private GetHSteamUserDelegate GetHSteamUserDelegatePointer; + + #endregion + public HSteamUser GetHSteamUser() + { + return GetHSteamUserDelegatePointer( Self ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + [return: MarshalAs( UnmanagedType.I1 )] + public delegate bool BLoggedOnDelegate( IntPtr self ); + private BLoggedOnDelegate BLoggedOnDelegatePointer; + + #endregion + public bool BLoggedOn() + { + return BLoggedOnDelegatePointer( Self ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate void GetSteamIDDelegate( IntPtr self, ref CSteamID retVal ); + private GetSteamIDDelegate GetSteamIDDelegatePointer; + + #endregion + public CSteamID GetSteamID() + { + var retVal = default( CSteamID ); + GetSteamIDDelegatePointer( Self, ref retVal ); + return retVal; + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate int InitiateGameConnectionDelegate( IntPtr self, IntPtr pAuthBlob, int cbMaxAuthBlob, CSteamID steamIDGameServer, uint unIPServer, ushort usPortServer, [MarshalAs( UnmanagedType.U1 )] bool bSecure ); + private InitiateGameConnectionDelegate InitiateGameConnectionDelegatePointer; + + #endregion + public int InitiateGameConnection( IntPtr pAuthBlob, int cbMaxAuthBlob, CSteamID steamIDGameServer, uint unIPServer, ushort usPortServer, [MarshalAs( UnmanagedType.U1 )] bool bSecure ) + { + return InitiateGameConnectionDelegatePointer( Self, pAuthBlob, cbMaxAuthBlob, steamIDGameServer, unIPServer, usPortServer, bSecure ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate void TerminateGameConnectionDelegate( IntPtr self, uint unIPServer, ushort usPortServer ); + private TerminateGameConnectionDelegate TerminateGameConnectionDelegatePointer; + + #endregion + public void TerminateGameConnection( uint unIPServer, ushort usPortServer ) + { + TerminateGameConnectionDelegatePointer( Self, unIPServer, usPortServer ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate void TrackAppUsageEventDelegate( IntPtr self, CGameID gameID, int eAppUsageEvent, string pchExtraInfo ); + private TrackAppUsageEventDelegate TrackAppUsageEventDelegatePointer; + + #endregion + public void TrackAppUsageEvent( CGameID gameID, int eAppUsageEvent, string pchExtraInfo ) + { + TrackAppUsageEventDelegatePointer( Self, gameID, eAppUsageEvent, pchExtraInfo ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + [return: MarshalAs( UnmanagedType.I1 )] + public delegate bool GetUserDataFolderDelegate( IntPtr self, StringBuilder pchBuffer, int cubBuffer ); + private GetUserDataFolderDelegate GetUserDataFolderDelegatePointer; + + #endregion + public bool GetUserDataFolder( StringBuilder pchBuffer, int cubBuffer ) + { + return GetUserDataFolderDelegatePointer( Self, pchBuffer, cubBuffer ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate void StartVoiceRecordingDelegate( IntPtr self ); + private StartVoiceRecordingDelegate StartVoiceRecordingDelegatePointer; + + #endregion + public void StartVoiceRecording() + { + StartVoiceRecordingDelegatePointer( Self ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate void StopVoiceRecordingDelegate( IntPtr self ); + private StopVoiceRecordingDelegate StopVoiceRecordingDelegatePointer; + + #endregion + public void StopVoiceRecording() + { + StopVoiceRecordingDelegatePointer( Self ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate VoiceResult GetAvailableVoiceDelegate( IntPtr self, ref uint pcbCompressed, ref uint pcbUncompressed_Deprecated, uint nUncompressedVoiceDesiredSampleRate_Deprecated ); + private GetAvailableVoiceDelegate GetAvailableVoiceDelegatePointer; + + #endregion + public VoiceResult GetAvailableVoice( ref uint pcbCompressed, ref uint pcbUncompressed_Deprecated, uint nUncompressedVoiceDesiredSampleRate_Deprecated ) + { + return GetAvailableVoiceDelegatePointer( Self, ref pcbCompressed, ref pcbUncompressed_Deprecated, nUncompressedVoiceDesiredSampleRate_Deprecated ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate VoiceResult GetVoiceDelegate( IntPtr self, [MarshalAs( UnmanagedType.U1 )] bool bWantCompressed, IntPtr pDestBuffer, uint cbDestBufferSize, ref uint nBytesWritten, [MarshalAs( UnmanagedType.U1 )] bool bWantUncompressed_Deprecated, IntPtr pUncompressedDestBuffer_Deprecated, uint cbUncompressedDestBufferSize_Deprecated, ref uint nUncompressBytesWritten_Deprecated, uint nUncompressedVoiceDesiredSampleRate_Deprecated ); + private GetVoiceDelegate GetVoiceDelegatePointer; + + #endregion + public VoiceResult GetVoice( [MarshalAs( UnmanagedType.U1 )] bool bWantCompressed, IntPtr pDestBuffer, uint cbDestBufferSize, ref uint nBytesWritten, [MarshalAs( UnmanagedType.U1 )] bool bWantUncompressed_Deprecated, IntPtr pUncompressedDestBuffer_Deprecated, uint cbUncompressedDestBufferSize_Deprecated, ref uint nUncompressBytesWritten_Deprecated, uint nUncompressedVoiceDesiredSampleRate_Deprecated ) + { + return GetVoiceDelegatePointer( Self, bWantCompressed, pDestBuffer, cbDestBufferSize, ref nBytesWritten, bWantUncompressed_Deprecated, pUncompressedDestBuffer_Deprecated, cbUncompressedDestBufferSize_Deprecated, ref nUncompressBytesWritten_Deprecated, nUncompressedVoiceDesiredSampleRate_Deprecated ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate VoiceResult DecompressVoiceDelegate( IntPtr self, IntPtr pCompressed, uint cbCompressed, IntPtr pDestBuffer, uint cbDestBufferSize, ref uint nBytesWritten, uint nDesiredSampleRate ); + private DecompressVoiceDelegate DecompressVoiceDelegatePointer; + + #endregion + public VoiceResult DecompressVoice( IntPtr pCompressed, uint cbCompressed, IntPtr pDestBuffer, uint cbDestBufferSize, ref uint nBytesWritten, uint nDesiredSampleRate ) + { + return DecompressVoiceDelegatePointer( Self, pCompressed, cbCompressed, pDestBuffer, cbDestBufferSize, ref nBytesWritten, nDesiredSampleRate ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate uint GetVoiceOptimalSampleRateDelegate( IntPtr self ); + private GetVoiceOptimalSampleRateDelegate GetVoiceOptimalSampleRateDelegatePointer; + + #endregion + public uint GetVoiceOptimalSampleRate() + { + return GetVoiceOptimalSampleRateDelegatePointer( Self ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate HAuthTicket GetAuthSessionTicketDelegate( IntPtr self, IntPtr pTicket, int cbMaxTicket, ref uint pcbTicket ); + private GetAuthSessionTicketDelegate GetAuthSessionTicketDelegatePointer; + + #endregion + public HAuthTicket GetAuthSessionTicket( IntPtr pTicket, int cbMaxTicket, ref uint pcbTicket ) + { + return GetAuthSessionTicketDelegatePointer( Self, pTicket, cbMaxTicket, ref pcbTicket ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate BeginAuthSessionResult BeginAuthSessionDelegate( IntPtr self, IntPtr pAuthTicket, int cbAuthTicket, CSteamID steamID ); + private BeginAuthSessionDelegate BeginAuthSessionDelegatePointer; + + #endregion + public BeginAuthSessionResult BeginAuthSession( IntPtr pAuthTicket, int cbAuthTicket, CSteamID steamID ) + { + return BeginAuthSessionDelegatePointer( Self, pAuthTicket, cbAuthTicket, steamID ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate void EndAuthSessionDelegate( IntPtr self, CSteamID steamID ); + private EndAuthSessionDelegate EndAuthSessionDelegatePointer; + + #endregion + public void EndAuthSession( CSteamID steamID ) + { + EndAuthSessionDelegatePointer( Self, steamID ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate void CancelAuthTicketDelegate( IntPtr self, HAuthTicket hAuthTicket ); + private CancelAuthTicketDelegate CancelAuthTicketDelegatePointer; + + #endregion + public void CancelAuthTicket( HAuthTicket hAuthTicket ) + { + CancelAuthTicketDelegatePointer( Self, hAuthTicket ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate UserHasLicenseForAppResult UserHasLicenseForAppDelegate( IntPtr self, CSteamID steamID, AppId_t appID ); + private UserHasLicenseForAppDelegate UserHasLicenseForAppDelegatePointer; + + #endregion + public UserHasLicenseForAppResult UserHasLicenseForApp( CSteamID steamID, AppId_t appID ) + { + return UserHasLicenseForAppDelegatePointer( Self, steamID, appID ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + [return: MarshalAs( UnmanagedType.I1 )] + public delegate bool BIsBehindNATDelegate( IntPtr self ); + private BIsBehindNATDelegate BIsBehindNATDelegatePointer; + + #endregion + public bool BIsBehindNAT() + { + return BIsBehindNATDelegatePointer( Self ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate void AdvertiseGameDelegate( IntPtr self, CSteamID steamIDGameServer, uint unIPServer, ushort usPortServer ); + private AdvertiseGameDelegate AdvertiseGameDelegatePointer; + + #endregion + public void AdvertiseGame( CSteamID steamIDGameServer, uint unIPServer, ushort usPortServer ) + { + AdvertiseGameDelegatePointer( Self, steamIDGameServer, unIPServer, usPortServer ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate SteamAPICall_t RequestEncryptedAppTicketDelegate( IntPtr self, IntPtr pDataToInclude, int cbDataToInclude ); + private RequestEncryptedAppTicketDelegate RequestEncryptedAppTicketDelegatePointer; + + #endregion + public async Task RequestEncryptedAppTicket( IntPtr pDataToInclude, int cbDataToInclude ) + { + return await (new Result( RequestEncryptedAppTicketDelegatePointer( Self, pDataToInclude, cbDataToInclude ) )).GetResult(); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + [return: MarshalAs( UnmanagedType.I1 )] + public delegate bool GetEncryptedAppTicketDelegate( IntPtr self, IntPtr pTicket, int cbMaxTicket, ref uint pcbTicket ); + private GetEncryptedAppTicketDelegate GetEncryptedAppTicketDelegatePointer; + + #endregion + public bool GetEncryptedAppTicket( IntPtr pTicket, int cbMaxTicket, ref uint pcbTicket ) + { + return GetEncryptedAppTicketDelegatePointer( Self, pTicket, cbMaxTicket, ref pcbTicket ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate int GetGameBadgeLevelDelegate( IntPtr self, int nSeries, [MarshalAs( UnmanagedType.U1 )] bool bFoil ); + private GetGameBadgeLevelDelegate GetGameBadgeLevelDelegatePointer; + + #endregion + public int GetGameBadgeLevel( int nSeries, [MarshalAs( UnmanagedType.U1 )] bool bFoil ) + { + return GetGameBadgeLevelDelegatePointer( Self, nSeries, bFoil ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate int GetPlayerSteamLevelDelegate( IntPtr self ); + private GetPlayerSteamLevelDelegate GetPlayerSteamLevelDelegatePointer; + + #endregion + public int GetPlayerSteamLevel() + { + return GetPlayerSteamLevelDelegatePointer( Self ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate SteamAPICall_t RequestStoreAuthURLDelegate( IntPtr self, string pchRedirectURL ); + private RequestStoreAuthURLDelegate RequestStoreAuthURLDelegatePointer; + + #endregion + public async Task RequestStoreAuthURL( string pchRedirectURL ) + { + return await (new Result( RequestStoreAuthURLDelegatePointer( Self, pchRedirectURL ) )).GetResult(); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + [return: MarshalAs( UnmanagedType.I1 )] + public delegate bool BIsPhoneVerifiedDelegate( IntPtr self ); + private BIsPhoneVerifiedDelegate BIsPhoneVerifiedDelegatePointer; + + #endregion + public bool BIsPhoneVerified() + { + return BIsPhoneVerifiedDelegatePointer( Self ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + [return: MarshalAs( UnmanagedType.I1 )] + public delegate bool BIsTwoFactorEnabledDelegate( IntPtr self ); + private BIsTwoFactorEnabledDelegate BIsTwoFactorEnabledDelegatePointer; + + #endregion + public bool BIsTwoFactorEnabled() + { + return BIsTwoFactorEnabledDelegatePointer( Self ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + [return: MarshalAs( UnmanagedType.I1 )] + public delegate bool BIsPhoneIdentifyingDelegate( IntPtr self ); + private BIsPhoneIdentifyingDelegate BIsPhoneIdentifyingDelegatePointer; + + #endregion + public bool BIsPhoneIdentifying() + { + return BIsPhoneIdentifyingDelegatePointer( Self ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + [return: MarshalAs( UnmanagedType.I1 )] + public delegate bool BIsPhoneRequiringVerificationDelegate( IntPtr self ); + private BIsPhoneRequiringVerificationDelegate BIsPhoneRequiringVerificationDelegatePointer; + + #endregion + public bool BIsPhoneRequiringVerification() + { + return BIsPhoneRequiringVerificationDelegatePointer( Self ); + } + + #region FunctionMeta + [UnmanagedFunctionPointer( CallingConvention.ThisCall )] + public delegate SteamAPICall_t GetMarketEligibilityDelegate( IntPtr self ); + private GetMarketEligibilityDelegate GetMarketEligibilityDelegatePointer; + + #endregion + public async Task GetMarketEligibility() + { + return await (new Result( GetMarketEligibilityDelegatePointer( Self ) )).GetResult(); + } + + } +} diff --git a/Facepunch.Steamworks/Redux/Classes/AuthTicket.cs b/Facepunch.Steamworks/Redux/Classes/AuthTicket.cs new file mode 100644 index 0000000..3366a2f --- /dev/null +++ b/Facepunch.Steamworks/Redux/Classes/AuthTicket.cs @@ -0,0 +1,30 @@ +using System; + +namespace Steamworks +{ + public class AuthTicket : IDisposable + { + public byte[] Data; + public uint Handle; + + /// + /// Cancels a ticket. + /// You should cancel your ticket when you close the game or leave a server. + /// + public void Cancel() + { + if ( Handle != 0 ) + { + User.Internal.CancelAuthTicket( Handle ); + } + + Handle = 0; + Data = null; + } + + public void Dispose() + { + Cancel(); + } + } +} \ No newline at end of file diff --git a/Facepunch.Steamworks/Redux/User.cs b/Facepunch.Steamworks/Redux/User.cs new file mode 100644 index 0000000..79ad38c --- /dev/null +++ b/Facepunch.Steamworks/Redux/User.cs @@ -0,0 +1,265 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using SteamNative; + +namespace Steamworks +{ + /// + /// Undocumented Parental Settings + /// + public static class User + { + static Internal.ISteamUser _internal; + internal static Internal.ISteamUser Internal + { + get + { + if ( _internal == null ) + { + _internal = new Internal.ISteamUser(); + + richPresence = new Dictionary(); + + SampleRate = OptimalSampleRate; + } + + return _internal; + } + } + + static Dictionary richPresence; + + internal static void InstallEvents() + { + // new Event( x => OnBroadcastStarted?.Invoke() ); + // new Event( x => OnBroadcastStopped?.Invoke( x.Result ) ); + } + + // public static event Action OnBroadcastStarted; + + /// + /// Checks if the current user's Steam client is connected to the Steam servers. + /// If it's not then no real-time services provided by the Steamworks API will be enabled. The Steam + /// client will automatically be trying to recreate the connection as often as possible. When the + /// connection is restored a SteamServersConnected_t callback will be posted. + /// You usually don't need to check for this yourself. All of the API calls that rely on this will + /// check internally. Forcefully disabling stuff when the player loses access is usually not a + /// very good experience for the player and you could be preventing them from accessing APIs that do not + /// need a live connection to Steam. + /// + public static bool IsLoggedOn => Internal.BLoggedOn(); + + /// + /// Gets the Steam ID of the account currently logged into the Steam client. This is + /// commonly called the 'current user', or 'local user'. + /// A Steam ID is a unique identifier for a Steam accounts, Steam groups, Lobbies and Chat + /// rooms, and used to differentiate users in all parts of the Steamworks API. + /// + public static CSteamID SteamID => Internal.GetSteamID(); + + + /// + /// Starts voice recording. + /// Once started, use GetAvailableVoice and GetVoice to get the data, and then call StopVoiceRecording + /// when the user has released their push-to-talk hotkey or the game session has completed. + /// + public static void StartVoiceRecording() => Internal.StartVoiceRecording(); + + /// + /// Stops voice recording. + /// Because people often release push-to-talk keys early, the system will keep recording for a little bit + /// after this function is called.As such, GetVoice should continue to be called until it returns k_EVoiceResultNotRecording, + /// only then will voice recording be stopped. + /// + public static void StopVoiceRecording() => Internal.StopVoiceRecording(); + + + /// + /// Returns true if we have voice data waiting to be read + /// + public static bool HasVoiceData + { + get + { + uint szCompressed = 0, deprecated = 0; + + if ( Internal.GetAvailableVoice( ref szCompressed, ref deprecated, 0 ) != VoiceResult.OK ) + return false; + + return szCompressed > 0; + } + } + + static byte[] readBuffer = new byte[1024*128]; + + /// + /// Reads the voice data and returns the number of bytes written. + /// The compressed data can be transmitted by your application and decoded back into raw audio data using + /// DecompressVoice on the other side. The compressed data provided is in an arbitrary format and is not meant to be played directly. + /// This should be called once per frame, and at worst no more than four times a second to keep the microphone input delay as low as + /// possible. Calling this any less may result in gaps in the returned stream. + /// + public static unsafe int ReadVoiceData( System.IO.Stream stream ) + { + if ( !HasVoiceData ) + return 0; + + uint szWritten = 0; + uint deprecated = 0; + + fixed ( byte* b = readBuffer ) + { + if ( Internal.GetVoice( true, (IntPtr)b, (uint)readBuffer.Length, ref szWritten, false, IntPtr.Zero, 0, ref deprecated, 0 ) != VoiceResult.OK ) + return 0; + } + + if ( szWritten == 0 ) + return 0; + + stream.Write( readBuffer, 0, (int) szWritten ); + + return (int) szWritten; + } + + static uint sampleRate = 48000; + + public static uint SampleRate + { + get => sampleRate; + + set + { + if ( SampleRate < 11025 ) throw new System.Exception( "Sample Rate must be between 11025 and 48000" ); + if ( SampleRate > 48000 ) throw new System.Exception( "Sample Rate must be between 11025 and 48000" ); + + sampleRate = value; + } + } + + public static uint OptimalSampleRate => Internal.GetVoiceOptimalSampleRate(); + + + /// + /// Decodes the compressed voice data returned by GetVoice. + /// The output data is raw single-channel 16-bit PCM audio.The decoder supports any sample rate from 11025 to 48000. + /// + public static unsafe int DecompressVoice( System.IO.Stream input, int length, System.IO.Stream output ) + { + var from = Helpers.TakeBuffer( length ); + var to = Helpers.TakeBuffer( 1024 * 64 ); + + // + // Copy from input stream to a pinnable buffer + // + using ( var s = new System.IO.MemoryStream( from ) ) + { + input.CopyTo( s ); + } + + uint szWritten = 0; + + fixed ( byte* frm = from ) + fixed ( byte* dst = to ) + { + if ( Internal.DecompressVoice( (IntPtr) frm, (uint) length, (IntPtr)dst, (uint)to.Length, ref szWritten, SampleRate ) != VoiceResult.OK ) + return 0; + } + + if ( szWritten == 0 ) + return 0; + + // + // Copy to output buffer + // + output.Write( to, 0, (int)szWritten ); + return (int)szWritten; + } + + /// + /// Retrieve a authentication ticket to be sent to the entity who wishes to authenticate you. + /// + public static unsafe AuthTicket GetAuthSessionTicket() + { + var data = Helpers.TakeBuffer( 1024 ); + + fixed ( byte* b = data ) + { + uint ticketLength = 0; + uint ticket = Internal.GetAuthSessionTicket( (IntPtr)b, data.Length, ref ticketLength ); + + if ( ticket == 0 ) + return null; + + return new AuthTicket() + { + Data = data.Take( (int)ticketLength ).ToArray(), + Handle = ticket + }; + } + } + + public static unsafe BeginAuthSessionResult BeginAuthSession( byte[] ticketData, CSteamID steamid ) + { + fixed ( byte* ptr = ticketData ) + { + return Internal.BeginAuthSession( (IntPtr) ptr, ticketData.Length, steamid ); + } + } + + public static void EndAuthSession( CSteamID steamid ) => Internal.EndAuthSession( steamid ); + + + // UserHasLicenseForApp - SERVER VERSION ( DLC CHECKING ) + + /// + /// Checks if the current users looks like they are behind a NAT device. + /// This is only valid if the user is connected to the Steam servers and may not catch all forms of NAT. + /// + public static bool IsBehindNAT => Internal.BIsBehindNAT(); + + /// + /// Gets the Steam level of the user, as shown on their Steam community profile. + /// + public static int SteamLevel => Internal.GetPlayerSteamLevel(); + + /// + /// Requests a URL which authenticates an in-game browser for store check-out, and then redirects to the specified URL. + /// As long as the in-game browser accepts and handles session cookies, Steam microtransaction checkout pages will automatically recognize the user instead of presenting a login page. + /// NOTE: The URL has a very short lifetime to prevent history-snooping attacks, so you should only call this API when you are about to launch the browser, or else immediately navigate to the result URL using a hidden browser window. + /// NOTE: The resulting authorization cookie has an expiration time of one day, so it would be a good idea to request and visit a new auth URL every 12 hours. + /// + public static async Task GetStoreAuthUrlAsync( string url ) + { + var response = await Internal.RequestStoreAuthURL( url ); + if ( !response.HasValue ) + return null; + + return response.Value.URL; + } + + /// + /// Checks whether the current user has verified their phone number. + /// + public static bool IsPhoneVerified => Internal.BIsPhoneVerified(); + + /// + /// Checks whether the current user has Steam Guard two factor authentication enabled on their account. + /// + public static bool IsTwoFactorEnabled => Internal.BIsTwoFactorEnabled(); + + /// + /// Checks whether the user's phone number is used to uniquely identify them. + /// + public static bool IsPhoneIdentifying => Internal.BIsPhoneIdentifying(); + + /// + /// Checks whether the current user's phone number is awaiting (re)verification. + /// + public static bool IsPhoneRequiringVerification => Internal.BIsPhoneRequiringVerification(); + + } +} \ No newline at end of file diff --git a/Facepunch.Steamworks/Server/Auth.cs b/Facepunch.Steamworks/Server/Auth.cs index f94cddc..306a8ed 100644 --- a/Facepunch.Steamworks/Server/Auth.cs +++ b/Facepunch.Steamworks/Server/Auth.cs @@ -68,5 +68,6 @@ public void EndSession( ulong steamid ) server.native.gameServer.EndAuthSession( steamid ); } - } + + } } diff --git a/Facepunch.Steamworks/SteamNative/SteamNative.Helpers.cs b/Facepunch.Steamworks/SteamNative/SteamNative.Helpers.cs index 6f2db07..a1b9344 100644 --- a/Facepunch.Steamworks/SteamNative/SteamNative.Helpers.cs +++ b/Facepunch.Steamworks/SteamNative/SteamNative.Helpers.cs @@ -36,5 +36,37 @@ public static StringBuilder TakeStringBuilder() return StringBuilderPool[StringBuilderPoolIndex]; } - } + + + private static byte[][] BufferPool; + private static int BufferPoolIndex; + + /// + /// Returns a StringBuilder. This will get returned and reused later on. + /// + public static byte[] TakeBuffer( int minSize ) + { + if ( BufferPool == null ) + { + // + // The pool has 8 items. + // + BufferPool = new byte[8][]; + + for ( int i = 0; i < BufferPool.Length; i++ ) + BufferPool[i] = new byte[ 1024 * 128 ]; + } + + BufferPoolIndex++; + if ( BufferPoolIndex >= BufferPool.Length ) + BufferPoolIndex = 0; + + if ( BufferPool[BufferPoolIndex].Length < minSize ) + { + BufferPool[BufferPoolIndex] = new byte[minSize + 1024]; + } + + return BufferPool[BufferPoolIndex]; + } + } } diff --git a/Generator/CodeWriter/CodeWriter.cs b/Generator/CodeWriter/CodeWriter.cs index 3e20a2a..d5b90dd 100644 --- a/Generator/CodeWriter/CodeWriter.cs +++ b/Generator/CodeWriter/CodeWriter.cs @@ -97,6 +97,7 @@ public void ToFolder( string folder ) GenerateVTableClass( "ISteamParentalSettings", $"{folder}../Generated/Interfaces/ISteamParentalSettings.cs" ); GenerateVTableClass( "ISteamMusic", $"{folder}../Generated/Interfaces/ISteamMusic.cs" ); GenerateVTableClass( "ISteamVideo", $"{folder}../Generated/Interfaces/ISteamVideo.cs" ); + GenerateVTableClass( "ISteamUser", $"{folder}../Generated/Interfaces/ISteamUser.cs" ); } } diff --git a/Generator/CodeWriter/Types/BaseType.cs b/Generator/CodeWriter/Types/BaseType.cs index b979ad9..cba43a4 100644 --- a/Generator/CodeWriter/Types/BaseType.cs +++ b/Generator/CodeWriter/Types/BaseType.cs @@ -24,6 +24,7 @@ public static BaseType Parse( string type, string varname = null ) var basicType = type.Trim( ' ', '*' ); if ( basicType == "void" ) return new PointerType { NativeType = type, VarName = varname }; + if ( basicType == "const void" ) return new PointerType { NativeType = type, VarName = varname }; if ( basicType == "int32" || basicType == "int" ) return new IntType { NativeType = type, VarName = varname }; if ( basicType == "uint32" ) return new UIntType { NativeType = type, VarName = varname }; if ( basicType == "uint8" ) return new UInt8Type { NativeType = type, VarName = varname };