New dispatch system

This commit is contained in:
Garry Newman 2020-02-19 13:57:17 +00:00
parent 8c603d4880
commit 3f88106c0b
5 changed files with 183 additions and 48 deletions

View File

@ -15,19 +15,12 @@ namespace Steamworks
public CallbackResult( SteamAPICall_t call )
{
this.call = call;
Console.WriteLine( $"{this.GetType().ToString()} == {call.Value}" );
}
public void OnCompleted( Action continuation )
{
var ts = TaskScheduler.Current;
var sc = SynchronizationContext.Current;
while ( !IsCompleted )
{
// Nothing
}
continuation();
Dispatch.OnCallComplete( call, continuation );
}
public T? GetResult()

View File

@ -0,0 +1,146 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Steamworks.Data;
namespace Steamworks
{
internal static class Dispatch
{
#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 m_pubParam; // Points to the callback structure
public int m_cubParam; // Size of the data pointed to by m_pubParam
};
#endregion
internal static HSteamPipe ClientPipe { get; set; }
internal static HSteamPipe ServerPipe { get; set; }
public static void Init()
{
SteamAPI_ManualDispatch_Init();
}
public static void Frame()
{
if ( ClientPipe != 0 )
Frame( ClientPipe );
if ( ServerPipe != 0)
Frame( ServerPipe );
}
public static void Frame( HSteamPipe pipe )
{
SteamAPI_ManualDispatch_RunFrame( pipe );
CallbackMsg_t msg = default;
while ( SteamAPI_ManualDispatch_GetNextCallback( pipe, ref msg ) )
{
try
{
ProcessCallback( msg );
}
finally
{
SteamAPI_ManualDispatch_FreeLastCallback( pipe );
}
}
}
private static void ProcessCallback( CallbackMsg_t msg )
{
if ( msg.Type == CallbackType.SteamAPICallCompleted )
{
ProcessResult( msg );
return;
}
Console.WriteLine( $"Callback: {msg.Type}" );
}
private static void ProcessResult( CallbackMsg_t msg )
{
var result = SteamAPICallCompleted_t.Fill( msg.m_pubParam );
Console.WriteLine( $"Result: {result.AsyncCall} / {result.Callback}" );
//
// Do we have an entry added via OnCallComplete
//
if ( !Callbacks.TryGetValue( result.AsyncCall, out var callbackInfo ) )
{
// Do we care? Should we throw errors?
return;
}
Callbacks.Remove( result.AsyncCall );
// At this point whatever async routine called this
// continues running.
callbackInfo.continuation();
}
public static async void LoopClientAsync()
{
while ( ClientPipe != 0 )
{
Frame( ClientPipe );
await Task.Delay( 16 );
}
Console.WriteLine( $"Exiting ClientPipe: {ClientPipe}" );
}
public static async void LoopServerAsync()
{
while ( ServerPipe != 0 )
{
Frame( ServerPipe );
await Task.Delay( 32 );
}
Console.WriteLine( $"Exiting ServerPipe: {ServerPipe}" );
}
struct CallbackInfo
{
public Action continuation;
}
static Dictionary<ulong, CallbackInfo> Callbacks = new Dictionary<ulong, CallbackInfo>();
/// <summary>
/// Watch for a steam api call
/// </summary>
internal static void OnCallComplete( SteamAPICall_t call, Action continuation )
{
Callbacks[call.Value] = new CallbackInfo
{
continuation = continuation
};
}
}
}

View File

@ -29,6 +29,14 @@ namespace Steamworks
initialized = true;
//
// Dispatch is responsible for pumping the
// event loop.
//
Dispatch.Init();
Dispatch.ClientPipe = SteamAPI.GetHSteamPipe();
Console.WriteLine( $"Dispatch.ClientPipe = {Dispatch.ClientPipe.Value}" );
AddInterface<SteamApps>();
AddInterface<SteamFriends>();
AddInterface<SteamInput>();
@ -51,7 +59,11 @@ namespace Steamworks
if ( asyncCallbacks )
{
RunCallbacksAsync();
//
// This will keep looping in the background every 16 ms
// until we shut down.
//
Dispatch.LoopClientAsync();
}
}
@ -78,22 +90,6 @@ namespace Steamworks
public static bool IsValid => initialized;
internal static async void RunCallbacksAsync()
{
while ( IsValid )
{
await Task.Delay( 16 );
try
{
RunCallbacks();
}
catch ( System.Exception e )
{
OnCallbackException?.Invoke( e );
}
}
}
public static void Shutdown()
{
@ -106,6 +102,8 @@ namespace Steamworks
internal static void Cleanup()
{
Dispatch.ClientPipe = 0;
initialized = false;
Event.DisposeAllClient();
@ -119,9 +117,8 @@ namespace Steamworks
public static void RunCallbacks()
{
if ( !IsValid ) return;
SteamAPI.RunCallbacks();
if ( Dispatch.ClientPipe != 0 )
Dispatch.Frame( Dispatch.ClientPipe );
}
internal static void UnregisterCallback( IntPtr intPtr )

View File

@ -85,6 +85,14 @@ namespace Steamworks
throw new System.Exception( $"InitGameServer returned false ({ipaddress},{init.SteamPort},{init.GamePort},{init.QueryPort},{secure},\"{init.VersionString}\")" );
}
//
// Dispatch is responsible for pumping the
// event loop.
//
Dispatch.Init();
Dispatch.ServerPipe = SteamGameServer.GetHSteamPipe();
Console.WriteLine( $"Dispatch.ServerPipe = {Dispatch.ServerPipe.Value}" );
AddInterface<SteamServer>();
//
@ -103,7 +111,11 @@ namespace Steamworks
if ( asyncCallbacks )
{
RunCallbacksAsync();
//
// This will keep looping in the background every 16 ms
// until we shut down.
//
Dispatch.LoopServerAsync();
}
}
@ -136,29 +148,15 @@ namespace Steamworks
SteamGameServer.Shutdown();
}
internal static async void RunCallbacksAsync()
{
while ( IsValid )
{
try
{
RunCallbacks();
}
catch ( System.Exception e )
{
OnCallbackException?.Invoke( e );
}
await Task.Delay( 16 );
}
}
/// <summary>
/// Run the callbacks. This is also called in Async callbacks.
/// </summary>
public static void RunCallbacks()
{
SteamGameServer.RunCallbacks();
if ( Dispatch.ServerPipe != 0 )
{
Dispatch.Frame( Dispatch.ServerPipe );
}
}
/// <summary>

View File

@ -49,6 +49,7 @@
<ItemGroup>
<Compile Include="CodeWriter\ClassVTable.cs" />
<Compile Include="CodeWriter\Constants.cs" />
<Compile Include="CodeWriter\CustomEnums.cs" />
<Compile Include="CodeWriter\StructCallbacks.cs" />
<Compile Include="CodeWriter\Types\BaseType.cs" />
<Compile Include="CodeWriter\Writing.cs" />