Restructuring of the files
This commit is contained in:
30
Facepunch.Steamworks/Classes/AuthTicket.cs
Normal file
30
Facepunch.Steamworks/Classes/AuthTicket.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
|
||||
namespace Facepunch.Steamworks
|
||||
{
|
||||
public class AuthTicket : IDisposable
|
||||
{
|
||||
public byte[] Data;
|
||||
public uint Handle;
|
||||
|
||||
/// <summary>
|
||||
/// Cancels a ticket.
|
||||
/// You should cancel your ticket when you close the game or leave a server.
|
||||
/// </summary>
|
||||
public void Cancel()
|
||||
{
|
||||
if ( Handle != 0 )
|
||||
{
|
||||
SteamUser.Internal.CancelAuthTicket( Handle );
|
||||
}
|
||||
|
||||
Handle = 0;
|
||||
Data = null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
333
Facepunch.Steamworks/Classes/Dispatch.cs
Normal file
333
Facepunch.Steamworks/Classes/Dispatch.cs
Normal file
@@ -0,0 +1,333 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using Facepunch.Steamworks.Data;
|
||||
using System.Linq;
|
||||
|
||||
namespace Facepunch.Steamworks
|
||||
{
|
||||
/// <summary>
|
||||
/// Responsible for all callback/callresult handling
|
||||
///
|
||||
/// This manually pumps Steam's message queue and dispatches those
|
||||
/// events to any waiting callbacks/callresults.
|
||||
/// </summary>
|
||||
public static class Dispatch
|
||||
{
|
||||
/// <summary>
|
||||
/// If set then we'll call this function every time a callback is generated.
|
||||
///
|
||||
/// This is SLOW!! - it's for debugging - don't keep it on all the time. If you want to access a specific
|
||||
/// callback then please create an issue on github and I'll add it!
|
||||
///
|
||||
/// Params are : [Callback Type] [Callback Contents] [server]
|
||||
///
|
||||
/// </summary>
|
||||
public static Action<CallbackType, string, bool> OnDebugCallback;
|
||||
|
||||
/// <summary>
|
||||
/// Called if an exception happens during a callback/callresult.
|
||||
/// This is needed because the exception isn't always accessible when running
|
||||
/// async.. and can fail silently. With this hooked you won't be stuck wondering
|
||||
/// what happened.
|
||||
/// </summary>
|
||||
public static Action<Exception> OnException;
|
||||
|
||||
#region interop
|
||||
[DllImport( Platform.LibraryName, EntryPoint = "SteamAPI_ManualDispatch_Init", CallingConvention = CallingConvention.Cdecl )]
|
||||
internal static extern void SteamAPI_ManualDispatch_Init();
|
||||
|
||||
[DllImport( Platform.LibraryName, EntryPoint = "SteamAPI_ManualDispatch_RunFrame", CallingConvention = CallingConvention.Cdecl )]
|
||||
internal static extern void SteamAPI_ManualDispatch_RunFrame( HSteamPipe pipe );
|
||||
|
||||
[DllImport( Platform.LibraryName, EntryPoint = "SteamAPI_ManualDispatch_GetNextCallback", CallingConvention = CallingConvention.Cdecl )]
|
||||
[return: MarshalAs( UnmanagedType.I1 )]
|
||||
internal static extern bool SteamAPI_ManualDispatch_GetNextCallback( HSteamPipe pipe, [In, Out] ref CallbackMsg_t msg );
|
||||
|
||||
[DllImport( Platform.LibraryName, EntryPoint = "SteamAPI_ManualDispatch_FreeLastCallback", CallingConvention = CallingConvention.Cdecl )]
|
||||
[return: MarshalAs( UnmanagedType.I1 )]
|
||||
internal static extern bool SteamAPI_ManualDispatch_FreeLastCallback( HSteamPipe pipe );
|
||||
|
||||
[StructLayout( LayoutKind.Sequential, Pack = Platform.StructPlatformPackSize )]
|
||||
internal struct CallbackMsg_t
|
||||
{
|
||||
public HSteamUser m_hSteamUser; // Specific user to whom this callback applies.
|
||||
public CallbackType Type; // Callback identifier. (Corresponds to the k_iCallback enum in the callback structure.)
|
||||
public IntPtr Data; // Points to the callback structure
|
||||
public int DataSize; // Size of the data pointed to by m_pubParam
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
internal static HSteamPipe ClientPipe { get; set; }
|
||||
internal static HSteamPipe ServerPipe { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This gets called from Client/Server Init
|
||||
/// It's important to switch to the manual dispatcher
|
||||
/// </summary>
|
||||
internal static void Init()
|
||||
{
|
||||
SteamAPI_ManualDispatch_Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make sure we don't call Frame in a callback - because that'll cause some issues for everyone.
|
||||
/// </summary>
|
||||
static bool runningFrame = false;
|
||||
|
||||
/// <summary>
|
||||
/// Calls RunFrame and processes events from this Steam Pipe
|
||||
/// </summary>
|
||||
internal static void Frame( HSteamPipe pipe )
|
||||
{
|
||||
if ( runningFrame )
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
runningFrame = true;
|
||||
|
||||
SteamAPI_ManualDispatch_RunFrame( pipe );
|
||||
SteamNetworkingUtils.OutputDebugMessages();
|
||||
|
||||
CallbackMsg_t msg = default;
|
||||
|
||||
while ( SteamAPI_ManualDispatch_GetNextCallback( pipe, ref msg ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
ProcessCallback( msg, pipe == ServerPipe );
|
||||
}
|
||||
finally
|
||||
{
|
||||
SteamAPI_ManualDispatch_FreeLastCallback( pipe );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( System.Exception e )
|
||||
{
|
||||
OnException?.Invoke( e );
|
||||
}
|
||||
finally
|
||||
{
|
||||
runningFrame = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// To be safe we don't call the continuation functions while iterating
|
||||
/// the Callback list. This is maybe overly safe because the only way this
|
||||
/// could be an issue is if the callback list is modified in the continuation
|
||||
/// which would only happen if starting or shutting down in the callback.
|
||||
/// </summary>
|
||||
static List<Action<IntPtr>> actionsToCall = new List<Action<IntPtr>>();
|
||||
|
||||
/// <summary>
|
||||
/// A callback is a general global message
|
||||
/// </summary>
|
||||
private static void ProcessCallback( CallbackMsg_t msg, bool isServer )
|
||||
{
|
||||
OnDebugCallback?.Invoke( msg.Type, CallbackToString( msg.Type, msg.Data, msg.DataSize ), isServer );
|
||||
|
||||
// Is this a special callback telling us that the call result is ready?
|
||||
if ( msg.Type == CallbackType.SteamAPICallCompleted )
|
||||
{
|
||||
ProcessResult( msg );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( Callbacks.TryGetValue( msg.Type, out var list ) )
|
||||
{
|
||||
actionsToCall.Clear();
|
||||
|
||||
foreach ( var item in list )
|
||||
{
|
||||
if ( item.server != isServer )
|
||||
continue;
|
||||
|
||||
actionsToCall.Add( item.action );
|
||||
}
|
||||
|
||||
foreach ( var action in actionsToCall )
|
||||
{
|
||||
action( msg.Data );
|
||||
}
|
||||
|
||||
actionsToCall.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a callback, try to turn it into a string
|
||||
/// </summary>
|
||||
internal static string CallbackToString( CallbackType type, IntPtr data, int expectedsize )
|
||||
{
|
||||
if ( !CallbackTypeFactory.All.TryGetValue( type, out var t ) )
|
||||
return $"[{type} not in sdk]";
|
||||
|
||||
var strct = data.ToType( t );
|
||||
if ( strct == null )
|
||||
return "[null]";
|
||||
|
||||
var str = "";
|
||||
|
||||
var fields = t.GetFields( System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic );
|
||||
|
||||
if ( fields.Length == 0 )
|
||||
return "[no fields]";
|
||||
|
||||
var columnSize = fields.Max( x => x.Name.Length ) + 1;
|
||||
|
||||
if ( columnSize < 10 )
|
||||
columnSize = 10;
|
||||
|
||||
foreach ( var field in fields )
|
||||
{
|
||||
var spaces = (columnSize - field.Name.Length);
|
||||
if ( spaces < 0 ) spaces = 0;
|
||||
|
||||
str += $"{new String( ' ', spaces )}{field.Name}: {field.GetValue( strct )}\n";
|
||||
}
|
||||
|
||||
return str.Trim( '\n' );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A result is a reply to a specific command
|
||||
/// </summary>
|
||||
private static void ProcessResult( CallbackMsg_t msg )
|
||||
{
|
||||
var result = msg.Data.ToType<SteamAPICallCompleted_t>();
|
||||
|
||||
//
|
||||
// Do we have an entry added via OnCallComplete
|
||||
//
|
||||
if ( !ResultCallbacks.TryGetValue( result.AsyncCall, out var callbackInfo ) )
|
||||
{
|
||||
//
|
||||
// This can happen if the callback result was immediately available
|
||||
// so we just returned that without actually going through the callback
|
||||
// dance. It's okay for this to fail.
|
||||
//
|
||||
|
||||
//
|
||||
// But still let everyone know that this happened..
|
||||
//
|
||||
OnDebugCallback?.Invoke( (CallbackType)result.Callback, $"[no callback waiting/required]", false );
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove it before we do anything, incase the continuation throws exceptions
|
||||
ResultCallbacks.Remove( result.AsyncCall );
|
||||
|
||||
// At this point whatever async routine called this
|
||||
// continues running.
|
||||
callbackInfo.continuation();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pumps the queue in an async loop so we don't
|
||||
/// have to think about it. This has the advantage that
|
||||
/// you can call .Wait() on async shit and it still works.
|
||||
/// </summary>
|
||||
internal static async void LoopClientAsync()
|
||||
{
|
||||
while ( ClientPipe != 0 )
|
||||
{
|
||||
Frame( ClientPipe );
|
||||
await Task.Delay( 16 );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pumps the queue in an async loop so we don't
|
||||
/// have to think about it. This has the advantage that
|
||||
/// you can call .Wait() on async shit and it still works.
|
||||
/// </summary>
|
||||
internal static async void LoopServerAsync()
|
||||
{
|
||||
while ( ServerPipe != 0 )
|
||||
{
|
||||
Frame( ServerPipe );
|
||||
await Task.Delay( 32 );
|
||||
}
|
||||
}
|
||||
|
||||
struct ResultCallback
|
||||
{
|
||||
public Action continuation;
|
||||
public bool server;
|
||||
}
|
||||
|
||||
static Dictionary<ulong, ResultCallback> ResultCallbacks = new Dictionary<ulong, ResultCallback>();
|
||||
|
||||
/// <summary>
|
||||
/// Watch for a steam api call
|
||||
/// </summary>
|
||||
internal static void OnCallComplete<T>( SteamAPICall_t call, Action continuation, bool server ) where T : struct, ICallbackData
|
||||
{
|
||||
ResultCallbacks[call.Value] = new ResultCallback
|
||||
{
|
||||
continuation = continuation,
|
||||
server = server
|
||||
};
|
||||
}
|
||||
|
||||
struct Callback
|
||||
{
|
||||
public Action<IntPtr> action;
|
||||
public bool server;
|
||||
}
|
||||
|
||||
static Dictionary<CallbackType, List<Callback>> Callbacks = new Dictionary<CallbackType, List<Callback>>();
|
||||
|
||||
/// <summary>
|
||||
/// Install a global callback. The passed function will get called if it's all good.
|
||||
/// </summary>
|
||||
internal static void Install<T>( Action<T> p, bool server = false ) where T : ICallbackData
|
||||
{
|
||||
var t = default( T );
|
||||
var type = t.CallbackType;
|
||||
|
||||
if ( !Callbacks.TryGetValue( type, out var list ) )
|
||||
{
|
||||
list = new List<Callback>();
|
||||
Callbacks[type] = list;
|
||||
}
|
||||
|
||||
list.Add( new Callback
|
||||
{
|
||||
action = x => p( x.ToType<T>() ),
|
||||
server = server
|
||||
} );
|
||||
}
|
||||
|
||||
internal static void ShutdownServer()
|
||||
{
|
||||
ServerPipe = 0;
|
||||
|
||||
foreach ( var callback in Callbacks )
|
||||
{
|
||||
Callbacks[callback.Key].RemoveAll( x => x.server );
|
||||
}
|
||||
|
||||
ResultCallbacks = ResultCallbacks.Where( x => !x.Value.server )
|
||||
.ToDictionary( x => x.Key, x => x.Value );
|
||||
}
|
||||
|
||||
internal static void ShutdownClient()
|
||||
{
|
||||
ClientPipe = 0;
|
||||
|
||||
foreach ( var callback in Callbacks )
|
||||
{
|
||||
Callbacks[callback.Key].RemoveAll( x => !x.server );
|
||||
}
|
||||
|
||||
ResultCallbacks = ResultCallbacks.Where( x => x.Value.server )
|
||||
.ToDictionary( x => x.Key, x => x.Value );
|
||||
}
|
||||
}
|
||||
}
|
||||
50
Facepunch.Steamworks/Classes/SteamApi.cs
Normal file
50
Facepunch.Steamworks/Classes/SteamApi.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Facepunch.Steamworks.Data;
|
||||
|
||||
|
||||
namespace Facepunch.Steamworks
|
||||
{
|
||||
internal static class SteamAPI
|
||||
{
|
||||
internal static class Native
|
||||
{
|
||||
[DllImport( Platform.LibraryName, EntryPoint = "SteamAPI_Init", CallingConvention = CallingConvention.Cdecl )]
|
||||
[return: MarshalAs( UnmanagedType.I1 )]
|
||||
public static extern bool SteamAPI_Init();
|
||||
|
||||
[DllImport( Platform.LibraryName, EntryPoint = "SteamAPI_Shutdown", CallingConvention = CallingConvention.Cdecl )]
|
||||
public static extern void SteamAPI_Shutdown();
|
||||
|
||||
[DllImport( Platform.LibraryName, EntryPoint = "SteamAPI_GetHSteamPipe", CallingConvention = CallingConvention.Cdecl )]
|
||||
public static extern HSteamPipe SteamAPI_GetHSteamPipe();
|
||||
|
||||
[DllImport( Platform.LibraryName, EntryPoint = "SteamAPI_RestartAppIfNecessary", CallingConvention = CallingConvention.Cdecl )]
|
||||
[return: MarshalAs( UnmanagedType.I1 )]
|
||||
public static extern bool SteamAPI_RestartAppIfNecessary( uint unOwnAppID );
|
||||
|
||||
}
|
||||
static internal bool Init()
|
||||
{
|
||||
return Native.SteamAPI_Init();
|
||||
}
|
||||
|
||||
static internal void Shutdown()
|
||||
{
|
||||
Native.SteamAPI_Shutdown();
|
||||
}
|
||||
|
||||
static internal HSteamPipe GetHSteamPipe()
|
||||
{
|
||||
return Native.SteamAPI_GetHSteamPipe();
|
||||
}
|
||||
|
||||
static internal bool RestartAppIfNecessary( uint unOwnAppID )
|
||||
{
|
||||
return Native.SteamAPI_RestartAppIfNecessary( unOwnAppID );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
40
Facepunch.Steamworks/Classes/SteamGameServer.cs
Normal file
40
Facepunch.Steamworks/Classes/SteamGameServer.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Facepunch.Steamworks.Data;
|
||||
|
||||
|
||||
namespace Facepunch.Steamworks
|
||||
{
|
||||
internal static class SteamGameServer
|
||||
{
|
||||
internal static class Native
|
||||
{
|
||||
[DllImport( Platform.LibraryName, EntryPoint = "SteamGameServer_RunCallbacks", CallingConvention = CallingConvention.Cdecl )]
|
||||
public static extern void SteamGameServer_RunCallbacks();
|
||||
|
||||
[DllImport( Platform.LibraryName, EntryPoint = "SteamGameServer_Shutdown", CallingConvention = CallingConvention.Cdecl )]
|
||||
public static extern void SteamGameServer_Shutdown();
|
||||
|
||||
[DllImport( Platform.LibraryName, EntryPoint = "SteamGameServer_GetHSteamPipe", CallingConvention = CallingConvention.Cdecl )]
|
||||
public static extern HSteamPipe SteamGameServer_GetHSteamPipe();
|
||||
|
||||
}
|
||||
static internal void RunCallbacks()
|
||||
{
|
||||
Native.SteamGameServer_RunCallbacks();
|
||||
}
|
||||
|
||||
static internal void Shutdown()
|
||||
{
|
||||
Native.SteamGameServer_Shutdown();
|
||||
}
|
||||
|
||||
static internal HSteamPipe GetHSteamPipe()
|
||||
{
|
||||
return Native.SteamGameServer_GetHSteamPipe();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
24
Facepunch.Steamworks/Classes/SteamInternal.cs
Normal file
24
Facepunch.Steamworks/Classes/SteamInternal.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Facepunch.Steamworks.Data;
|
||||
|
||||
|
||||
namespace Facepunch.Steamworks
|
||||
{
|
||||
internal static class SteamInternal
|
||||
{
|
||||
internal static class Native
|
||||
{
|
||||
[DllImport( Platform.LibraryName, EntryPoint = "SteamInternal_GameServer_Init", CallingConvention = CallingConvention.Cdecl )]
|
||||
[return: MarshalAs( UnmanagedType.I1 )]
|
||||
public static extern bool SteamInternal_GameServer_Init( uint unIP, ushort usPort, ushort usGamePort, ushort usQueryPort, int eServerMode, [MarshalAs( UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof( Utf8StringToNative ) )] string pchVersionString );
|
||||
}
|
||||
|
||||
static internal bool GameServer_Init( uint unIP, ushort usPort, ushort usGamePort, ushort usQueryPort, int eServerMode, [MarshalAs( UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof( Utf8StringToNative ) )] string pchVersionString )
|
||||
{
|
||||
return Native.SteamInternal_GameServer_Init( unIP, usPort, usGamePort, usQueryPort, eServerMode, pchVersionString );
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user