diff --git a/Facepunch.Steamworks/Classes/Dispatch.cs b/Facepunch.Steamworks/Classes/Dispatch.cs
index 26b32cd..599e20e 100644
--- a/Facepunch.Steamworks/Classes/Dispatch.cs
+++ b/Facepunch.Steamworks/Classes/Dispatch.cs
@@ -65,30 +65,54 @@ internal static void Init()
SteamAPI_ManualDispatch_Init();
}
+ ///
+ /// Make sure we don't call Frame in a callback - because that'll cause some issues for everyone.
+ ///
+ static bool runningFrame = false;
///
/// Calls RunFrame and processes events from this Steam Pipe
///
internal static void Frame( HSteamPipe pipe )
- {
- SteamAPI_ManualDispatch_RunFrame( pipe );
- SteamNetworkingUtils.OutputDebugMessages();
+ {
+ if ( runningFrame )
+ return;
- CallbackMsg_t msg = default;
-
- while ( SteamAPI_ManualDispatch_GetNextCallback( pipe, ref msg ) )
+ try
{
- try
+ runningFrame = true;
+
+ SteamAPI_ManualDispatch_RunFrame( pipe );
+ SteamNetworkingUtils.OutputDebugMessages();
+
+ CallbackMsg_t msg = default;
+
+ while ( SteamAPI_ManualDispatch_GetNextCallback( pipe, ref msg ) )
{
- ProcessCallback( msg, pipe == ServerPipe );
- }
- finally
- {
- SteamAPI_ManualDispatch_FreeLastCallback( pipe );
+ try
+ {
+ ProcessCallback( msg, pipe == ServerPipe );
+ }
+ finally
+ {
+ SteamAPI_ManualDispatch_FreeLastCallback( pipe );
+ }
}
}
+ finally
+ {
+ runningFrame = false;
+ }
}
+ ///
+ /// 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.
+ ///
+ static List> actionsToCall = new List>();
+
///
/// A callback is a general global message
///
@@ -108,13 +132,22 @@ private static void ProcessCallback( CallbackMsg_t msg, bool isServer )
if ( Callbacks.TryGetValue( msg.Type, out var list ) )
{
+ actionsToCall.Clear();
+
foreach ( var item in list )
{
if ( item.server != isServer )
continue;
- item.action( msg.Data );
+ actionsToCall.Add( item.action );
}
+
+ foreach ( var action in actionsToCall )
+ {
+ action( msg.Data );
+ }
+
+ actionsToCall.Clear();
}
}