/// <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> /// 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(); } }
internal static void RunFrame(bool isGameServer) { if (!IsInitialized) { throw new InvalidOperationException("Callback dispatcher is not initialized."); } HSteamPipe hSteamPipe = (HSteamPipe)(isGameServer ? NativeMethods.SteamGameServer_GetHSteamPipe() : NativeMethods.SteamAPI_GetHSteamPipe()); NativeMethods.SteamAPI_ManualDispatch_RunFrame(hSteamPipe); var callbacksRegistry = isGameServer ? m_registeredGameServerCallbacks : m_registeredCallbacks; while (NativeMethods.SteamAPI_ManualDispatch_GetNextCallback(hSteamPipe, m_pCallbackMsg)) { CallbackMsg_t callbackMsg = (CallbackMsg_t)Marshal.PtrToStructure(m_pCallbackMsg, typeof(CallbackMsg_t)); try { // Check for dispatching API call results if (callbackMsg.m_iCallback == SteamAPICallCompleted_t.k_iCallback) { SteamAPICallCompleted_t callCompletedCb = (SteamAPICallCompleted_t)Marshal.PtrToStructure(callbackMsg.m_pubParam, typeof(SteamAPICallCompleted_t)); IntPtr pTmpCallResult = Marshal.AllocHGlobal((int)callCompletedCb.m_cubParam); bool bFailed; if (NativeMethods.SteamAPI_ManualDispatch_GetAPICallResult(hSteamPipe, callCompletedCb.m_hAsyncCall, pTmpCallResult, (int)callCompletedCb.m_cubParam, callCompletedCb.m_iCallback, out bFailed)) { lock (m_sync) { if (m_registeredCallResults.TryGetValue((ulong)callCompletedCb.m_hAsyncCall, out var callResults)) { m_registeredCallResults.Remove((ulong)callCompletedCb.m_hAsyncCall); foreach (var cr in callResults) { cr.OnRunCallResult(pTmpCallResult, bFailed, (ulong)callCompletedCb.m_hAsyncCall); cr.SetUnregistered(); } } } } Marshal.FreeHGlobal(pTmpCallResult); } else { if (callbacksRegistry.TryGetValue(callbackMsg.m_iCallback, out var callbacks)) { List <Callback> callbacksCopy; lock (m_sync) { callbacksCopy = new List <Callback>(callbacks); } foreach (var callback in callbacksCopy) { callback.OnRunCallback(callbackMsg.m_pubParam); } } } } catch (Exception e) { ExceptionHandler(e); } finally { NativeMethods.SteamAPI_ManualDispatch_FreeLastCallback(hSteamPipe); } } }
/// <summary> /// A callback is a general global message /// </summary> private static void ProcessCallback(CallbackMsg_t msg) { // 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)) { foreach (var item in list) { item.action(msg.Data); } } }
/// <summary> /// Calls RunFrame and processes events from this Steam Pipe /// </summary> 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); } } }
/// <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)) { // Do we care? Should we throw errors? 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> /// Calls RunFrame and processes events from this Steam Pipe /// </summary> public 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; } }
internal static extern bool SteamAPI_ManualDispatch_GetNextCallback(HSteamPipe pipe, [In, Out] ref CallbackMsg_t msg);
internal static void RunFrame(bool isGameServer) { if (!IsInitialized) { throw new InvalidOperationException("Callback dispatcher is not initialized."); } HSteamPipe hSteamPipe = (HSteamPipe)(isGameServer ? NativeMethods.SteamGameServer_GetHSteamPipe() : NativeMethods.SteamAPI_GetHSteamPipe()); NativeMethods.SteamAPI_ManualDispatch_RunFrame(hSteamPipe); Dictionary <int, List <Callback> > dictionary = (isGameServer ? m_registeredGameServerCallbacks : m_registeredCallbacks); while (NativeMethods.SteamAPI_ManualDispatch_GetNextCallback(hSteamPipe, m_pCallbackMsg)) { CallbackMsg_t callbackMsg_t = (CallbackMsg_t)Marshal.PtrToStructure(m_pCallbackMsg, typeof(CallbackMsg_t)); try { if (callbackMsg_t.m_iCallback == 703) { SteamAPICallCompleted_t steamAPICallCompleted_t = (SteamAPICallCompleted_t)Marshal.PtrToStructure(callbackMsg_t.m_pubParam, typeof(SteamAPICallCompleted_t)); IntPtr intPtr = Marshal.AllocHGlobal((int)steamAPICallCompleted_t.m_cubParam); if (NativeMethods.SteamAPI_ManualDispatch_GetAPICallResult(hSteamPipe, steamAPICallCompleted_t.m_hAsyncCall, intPtr, (int)steamAPICallCompleted_t.m_cubParam, steamAPICallCompleted_t.m_iCallback, out var pbFailed)) { lock (m_sync) { if (m_registeredCallResults.TryGetValue((ulong)steamAPICallCompleted_t.m_hAsyncCall, out var value)) { m_registeredCallResults.Remove((ulong)steamAPICallCompleted_t.m_hAsyncCall); foreach (CallResult item in value) { item.OnRunCallResult(intPtr, pbFailed, (ulong)steamAPICallCompleted_t.m_hAsyncCall); item.SetUnregistered(); } } } } Marshal.FreeHGlobal(intPtr); } else { if (!dictionary.TryGetValue(callbackMsg_t.m_iCallback, out var value2)) { continue; } List <Callback> list; lock (m_sync) { list = new List <Callback>(value2); } foreach (Callback item2 in list) { item2.OnRunCallback(callbackMsg_t.m_pubParam); } continue; } } catch (Exception e) { ExceptionHandler(e); } finally { NativeMethods.SteamAPI_ManualDispatch_FreeLastCallback(hSteamPipe); } } }