rlabrecque / Steamworks.NET

Steamworks wrapper for Unity / C#
http://steamworks.github.io
MIT License
2.81k stars 368 forks source link

CallResult not Called on Steam API 15.0.0 and Higher #413

Open Vercidium opened 3 years ago

Vercidium commented 3 years ago

I tried upgrading my game from Steam API 14.0.0 to 15.0.0 today and noticed that any CallResults I set are not called back.

I tested again, and shipping the game with the Windows-x64 DLLs from the Steamworks.NET-Standalone_14.0.0 folder works great, but things break when shipping with the DLLs from the Steamworks.NET-Standalone_15.0.1 folder.

I then built the game against the latest GitHub source code and everything worked properly in my debug build, but on my release build the CallResults were not called.

I added the following logging (Console.Writeline) into this function in CallbackDispatcher.cs:

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;

    Console.WriteLine($"m_registeredCallbacks.Count: {m_registeredCallbacks.Count}");

    while (NativeMethods.SteamAPI_ManualDispatch_GetNextCallback(hSteamPipe, m_pCallbackMsg))
    {
        Console.WriteLine($"m_pCallbackMsg: {m_pCallbackMsg}");
        CallbackMsg_t callbackMsg = (CallbackMsg_t)Marshal.PtrToStructure(m_pCallbackMsg, typeof(CallbackMsg_t));
        try
        {
            // Check for dispatching API call results
            Console.WriteLine($"callbackMsg.m_iCallback: {callbackMsg.m_iCallback}");
            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;

                bool result = NativeMethods.SteamAPI_ManualDispatch_GetAPICallResult(hSteamPipe, callCompletedCb.m_hAsyncCall, pTmpCallResult, (int)callCompletedCb.m_cubParam, callCompletedCb.m_iCallback, out bFailed);

                Console.WriteLine($"result: {result}");

                if (result)
                {
                    lock (m_sync)
                    {
                        List<CallResult> callResults;
                        if (m_registeredCallResults.TryGetValue((ulong)callCompletedCb.m_hAsyncCall, out callResults))
                        {
                            Console.WriteLine($"callCompletedCb.m_hAsyncCall: {(ulong)callCompletedCb.m_hAsyncCall}");
                            m_registeredCallResults.Remove((ulong)callCompletedCb.m_hAsyncCall);
                            foreach (var cr in callResults)
                            {
                                Console.WriteLine($"pTmpCallResult: {pTmpCallResult}");
                                Console.WriteLine($"bFailed: {bFailed}");
                                Console.WriteLine($"callCompletedCb.m_hAsyncCall: {(ulong)callCompletedCb.m_hAsyncCall}");
                                cr.OnRunCallResult(pTmpCallResult, bFailed, (ulong)callCompletedCb.m_hAsyncCall);
                                cr.SetUnregistered();
                            }
                        }
                        else
                            Console.WriteLine($"m_registeredCallResults: false");
                    }
                }
                Marshal.FreeHGlobal(pTmpCallResult);
            }
            else
            {
                List<Callback> callbacks;
                if (callbacksRegistry.TryGetValue(callbackMsg.m_iCallback, out 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);
        }
    }
}

On my Debug build, this produced the following output:

m_registeredCallbacks.Count: 16
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 1281
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 1222
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 1281
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 1006
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 703
result: False
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 703
result: False
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 703
result: True
callCompletedCb.m_hAsyncCall: 14108606187866503733
pTmpCallResult: 2282384251984
bFailed: False
callCompletedCb.m_hAsyncCall: 14108606187866503733
OnEncryptedAppTicketResponse called successfully
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 336
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 304
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 711
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 703
result: True
m_registeredCallResults: false
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 504
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 304
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 715
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 711
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 903
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 501
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 502
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 703
result: True
callCompletedCb.m_hAsyncCall: 16172418149805613628
pTmpCallResult: 2282376711072
bFailed: False
callCompletedCb.m_hAsyncCall: 16172418149805613628
[WORKSHOP] CreateQueryUserUGCRequest (8) RESPONSE: False, 10 results
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 715
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 703
result: False
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 304
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 304
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 1281
m_pCallbackMsg: 2282113136656
callbackMsg.m_iCallback: 1222
m_registeredCallbacks.Count: 16
m_registeredCallbacks.Count: 16
m_registeredCallbacks.Count: 16
m_registeredCallbacks.Count: 16
m_registeredCallbacks.Count: 16

On my Release build, it produced the following output:

m_registeredCallbacks.Count: 16
m_registeredCallbacks.Count: 16
m_registeredCallbacks.Count: 16
m_registeredCallbacks.Count: 16
m_registeredCallbacks.Count: 16
m_registeredCallbacks.Count: 16

Here is my code for setting up the EncryptedAppTicket CallResult, which I can confirm works on the 14.0.0 build:

public CallResult<EncryptedAppTicketResponse_t> m_EncryptedAppTicketResponse;

public void InitialiseSteam()
{
    steamManager = new SteamManager(this);

    if (steamManager.Initialized)
    {
        var name = SteamFriends.GetPersonaName();
        Console.Writeline($"Received persona name: {name}");

        m_EncryptedAppTicketResponse = CallResult<EncryptedAppTicketResponse_t>.Create(OnEncryptedAppTicketResponse);

        var data = Encoding.UTF8.GetBytes(name);
        var hAPICall = SteamUser.RequestEncryptedAppTicket(data, data.Length);

        m_EncryptedAppTicketResponse.Set(hAPICall);
    }
}

public void OnEncryptedAppTicketResponse(EncryptedAppTicketResponse_t pCallback, bool failure)
{
    ClientLog.Log($"OnEncryptedAppTicketResponse called successfully");
    SteamUser.GetEncryptedAppTicket(EAC.authBytesEncrypted, 1024, out uint pcbTicket);
    // Do stuff with pcbTicket here...
}

I don't believe this is caused by a DLL mismatch as the Steamworks.NET.dll and steam_api64.dll files I ship with the game are always copied straight from the Windows-x64 folder in the Steamworks.NET standalone folder.

Any help with this would be greatly appreciated.

rlabrecque commented 3 years ago

Hey there @Vercidium, sorry about this!

Just to clarify a couple things;

The pre-built 15.0.1 binaries did not work, but building it yourself allowed it to work in Debug?

I wasn't really able to reproduce this on the StandaloneTest project:

https://github.com/rlabrecque/Steamworks.NET-StandaloneTest

Are you able to reproduce it there?

Additionally, which framework are you using for your project?

image

Vercidium commented 3 years ago

Hey thank you for the quick reply, no worries I'm happy with switching back to 14.0.0 for the time being as everything's working great there.

The pre-built 15.0.1 binaries did not work, but building it yourself allowed it to work in Debug?

Yep that's right, I also faced the same issue with the prebuilt 15.0.0 binaries. I'll try reproducing this on the StandaloneTest project.

I'm using .NET Framework 4.8

Vercidium commented 3 years ago

Hey, just letting you know that this issue was caused by Easy Anti Cheat blocking the EncryptedAppTicketResponse_t callback and I've closed this issue :)

rlabrecque commented 3 years ago

Awesome, how did you track this down? What was your solution to this?

Vercidium commented 3 years ago

It took me a while to track down, I ended up packaging a small test program with the game that requests an encrypted app ticket and logs when it receives the callback.

The encrypted app ticket callback fired when running this test program directly, but when running the program through EAC the callback didn't fire.

I filed a ticket with EAC and they did some testing and said it's an issue with the latest Steamworks.NET: steam_api64.dll ( 1.5 ) + Steamworks.NET.dll( 15.0.1 ): the error is occurring steam_api64.dll ( 1.5 ) + Steamworks.NET.dll( 14.0.0 ): it's working

They also provided me with these error messages:

[Error message]
[S_API FAIL] SteamAPI_ManualDispatch_Init() Cannot be used, standard dispatch has already been selected.
[S_API FAIL] SteamAPI_ManualDispatch_RunFrame() Cannot be used, must call SteamAPI_ManualDispatch_Init first.
[S_API FAIL] SteamAPI_ManualDispatch_GetNextCallback() Cannot be used, must call SteamAPI_ManualDispatch_Init first.

As well as these errors:

[OnEncryptedAppTicketResponse] Received encrypted app ticket with length 191
src\steamnetworkingsockets\clientlib\steamnetworkingsockets_lowlevel.cpp (365) : Assertion Failed: c:\buildslave\steam_rel_client_win64\build\src\steamnetworkingsockets\clientlib\steamnetworkingsockets_connections.cpp(387) held:
src\steamnetworkingsockets\clientlib\steamnetworkingsockets_lowlevel.cpp (365) : Assertion Failed: c:\buildslave\steam_rel_client_win64\build\src\steamnetworkingsockets\clientlib\steamnetworkingsockets_connections.cpp(387) held:
rlabrecque commented 3 years ago

Perfect, thanks, I'll look into it!

Vercidium commented 3 years ago

Hey Riley, just following up if there's been any progress on this?

xibz commented 3 years ago

This is affecting us too. Has there been any movement on this? If not, I may downgrade to 14

rlabrecque commented 3 years ago

I haven't had a chance yet, one thing that you could do is downgrade just https://github.com/rlabrecque/Steamworks.NET/blob/master/com.rlabrecque.steamworks.net/Runtime/CallbackDispatcher.cs to the version in 14, since this is likely an incompatibility with the new CallbackDispatcher logic. Note that this won't work if you're using Unity and IL2CPP.

RajOOI commented 2 years ago

Hello, I'm unable to run my game at all having just tried upgrading the Steam SDK to 152 (also tried 153a) and installing Steamworks.Net 20.0.0 via package, I have downloaded the full code but I also see the same code. Problem stems from CallbackDispatcher.Initialise(); call from SteamAPI.Init().

SteamManager.Instance is called which creates the gameobject and component, but during Awake on line 134 it calls SteamAPI.Init(). It bombs out with error EntryPointNotFound on line 59 of CallbackDispatcher.cs on this call: NativeMethods.SteamAPI_ManualDispatch_Init();

Our game is live and I actually need to upgrade the SDK to 153a in order to use the FloatingKeyboard for new Steam Deck functionality, and those functions are new, I see that they are exposed in Steamworks 20.0.0 and even updated it says to works with 153a.

Unsure how anybody else is able to run thier games when it's bombing out with error at such an early stage as creating SteamManager.cs

I see this issue seem to be open and says to use 14.0.0, but that does not work for me as I need to get hold of the new functions. I have also tried grabbing from master instead of the package. I replaced the steam_api.dlls with the ones from Plugins along with all the Steamworks code, as suggested here: https://github.com/Facepunch/Facepunch.Steamworks/issues/382 but get the same error

Any help appreciated, if I have a dodgy set up in some way, that would be great, but I've simply replaced the actual steam sdk, deleted the old SteamWorks code and used the package manager

Here is my Callstack: EntryPointNotFoundException: SteamAPI_ManualDispatch_Init Steamworks.CallbackDispatcher.Initialize () (at Assets/Plugins/Steamworks.NET/CallbackDispatcher.cs:59) Steamworks.SteamAPI.Init () (at Assets/Plugins/Steamworks.NET/Steam.cs:42) SteamManager.Awake () (at Assets/1_WinterAssets/3_Scripts/Features/Steam/SteamManager.cs:134) UnityEngine.GameObject:AddComponent() SteamManager:get_Instance() (at Assets/1_WinterAssets/3_Scripts/Features/Steam/SteamManager.cs:35) SteamManager:get_Initialized() (at Assets/1_WinterAssets/3_Scripts/Features/Steam/SteamManager.cs:49))

Cheers