docs.unity3d.com
Search Results for

    Show / Hide Table of Contents

    Choose a callback dispatch mode

    Select a dispatch mode to allow the package or your application code to read the callback queue.

    A dispatch mode determines whether the package or your application code reads callbacks and call results from the callback queue. By default, the package reads the queue on the background thread and delivers each message to your handlers with SteamCallbacks.

    If you want your application code to read the queue, select a different dispatch mode when you initialize the Steamworks API. To select a callback dispatch mode, pass a SteamDispatchMode value to SteamAPI.InitEx, or GameServer.InitEx.

    For more information on how the package reads and delivers messages, refer to Callback delivery.

    Compare dispatch modes

    The following table shows whether the package or your application code reads the callback queue in each dispatch mode and whether you can use SteamCallbacks to subscribe to callbacks and await call results.

    Dispatch mode Who reads the message queue Subscribe and await with SteamCallbacks When to use
    Package (default) The package, on a background thread Supported Most applications. The package reads the message queue and delivers callbacks and call results on the main thread. You don't need to write code to read callbacks. The Platform Toolkit package for Steamworks uses this mode.
    ExternalPoll Your application code, when it calls SteamCallbacks.RunFrameCallbacks or SteamCallbacks.SubmitCallback Supported When you need to control when callbacks run, such as at a fixed point in your game loop or at a regular interval on a server while still using Subscribe, CallResultAsync and the Async methods.
    External Your application code, through its own bindings to the Steamworks SDK Not supported. Subscribe throws exceptions, and awaiting an Async method fails with an InvalidOperationException. When another library or your own code already handles Steamworks callbacks through its own bindings, and you only want to use this package to call the Steamworks API.

    Read callbacks at your own schedule

    Use ExternalPoll mode to read callbacks at a time that you choose, such as in your own update loop or at a regular interval. You can still use Subscribe, CallResultAsync, and the Async methods.

    In ExternalPoll mode, you can read callbacks in one of two ways:

    • Call SteamCallbacks.RunFrameCallbacks and the package delivers the callbacks.
    • Read the messages with your own bindings and pass each message to SteamCallbacks.SubmitCallback.

    To read callbacks on your own schedule:

    1. Initialize the Steamworks API with SteamDispatchMode.ExternalPoll.
    2. Call SteamCallbacks.RunFrameCallbacks where you want to read callbacks.
    SteamAPI.InitEx(out var errMsg, SteamDispatchMode.ExternalPoll);
    ...
    // Call this wherever you want to read callbacks
    SteamCallbacks.RunFrameCallbacks();
    

    If you call RunFrameCallbacks on the main thread, the handlers run before the method returns. If you call it from another thread, the handlers run later on the main thread. To run the handlers immediately on the calling thread, call SteamCallbacks.DeliverQueuedCallbacks.

    If you already read the callback queue with your own bindings, pass each message to SubmitCallback instead. Include SteamAPICallCompleted_t messages, because they complete an awaited call result.

    while (SteamAPI_ManualDispatch_GetNextCallback(pipe, ref msg))
    {
        // SteamCallbacks copies the payload
        SteamCallbacks.SubmitCallback(pipe, in msg);
        SteamAPI_ManualDispatch_FreeLastCallback(pipe);
    }
    
    Note

    Use either RunFrameCallbacks or your own read loop to read the callback queue, not both. Each pipe allows only one of them to read it.

    Handle callbacks in your own code

    To handle callbacks in your own code, pass SteamDispatchMode.External to SteamAPI.InitEx or GameServer.InitEx.

    The package sets up the interface pointers, which are the addresses of the native Steamworks interface, such as ISteamUser, that the package's C# classes use to call the Steamworks API. The package doesn't start a background thread or call SteamAPI_ManualDispatch_Init. Because the package never receives callbacks, the following methods throw an exception for the client and game server:

    • Subscribe
    • OnCallback
    • OnGameServerCallback
    • CallResultAsync
    • Every Async method

    Dispatch modes for client and game server

    Set a dispatch mode separately for the client and the game server. Use SteamAPI.InitEx to set the client mode and GameServer.InitEx for the game server. RunFrameCallbacks, SubmitCallback, and DeliverQueuedCallbacks accept the same gameServer parameter as the other SteamCallbacks methods.

    Don't combine External with Package or ExternalPoll across the client and the game server. The client and the game server each have their own Steamworks API pipe.

    The package receives callbacks through manual dispatch in the Steamworks API. In manual dispatch, the package or your application code fetches callbacks from the callback queue one at a time, instead of SteamAPI_RunCallbacks calling registered handlers.

    The dispatch modes differ in how they use manual dispatch:

    • Package and ExternalPoll: These modes switch the whole application to manual dispatch.
    • External: This mode doesn't switch the application to manual dispatch. Your code reads the callbacks itself, either by calling SteamAPI_RunCallbacks or by enabling manual dispatch and reading the queue. SteamCallbacks subscription methods and CallResultAsync throw exceptions.

    When you use both the client and the game server, the following combinations of dispatch modes are valid:

    • Client and game server both use External.
    • Client and game server both use Package or ExternalPoll in any combination.

    InitEx throws an exception before it initializes, if one of the client and the game server uses External and the other doesn't. To avoid the exception, use External for both the client and the game server, or for neither. You can combine Package and ExternalPoll.

    Additional resources

    • Callback delivery
    • Handle callbacks and call results
    • Steam Game Servers (Valve)
    • Asynchronous programming in C# (Microsoft)
    In This Article
    Back to top
    Copyright © 2026 Unity Technologies — Trademarks and terms of use
    • Legal
    • Privacy Policy
    • Cookie Policy
    • Do Not Sell or Share My Personal Information
    • Your Privacy Choices (Cookie Settings)