Skip to content

Commit e1b53ca

Browse files
committed
fix(managed): Fix steam api callback
1 parent 6a952b8 commit e1b53ca

File tree

2 files changed

+72
-37
lines changed

2 files changed

+72
-37
lines changed

managed/src/SwiftlyS2.Shared/Modules/SteamAPI/CallbackDispatcher.cs

Lines changed: 68 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ public static class CallbackDispatcher
2222
/// <summary>
2323
/// Register a callback handler
2424
/// </summary>
25-
internal static unsafe void RegisterCallback<T>(ICallbackHandler<T> handler) where T : struct
25+
internal static unsafe void RegisterCallback<T>( ICallbackHandler<T> handler ) where T : struct
2626
{
2727
var callbackId = CallbackIdentities.GetCallbackIdentity(typeof(T));
2828

2929
// Add handler to dictionary
3030
s_callbackHandlers.AddOrUpdate(
3131
callbackId,
3232
_ => [handler],
33-
(_, list) => { list.Add(handler); return list; }
33+
( _, list ) => { list.Add(handler); return list; }
3434
);
3535

3636
// Register with Steam if this is the first handler for this callback
@@ -40,8 +40,8 @@ internal static unsafe void RegisterCallback<T>(ICallbackHandler<T> handler) whe
4040
var pCallback = Marshal.AllocHGlobal(Marshal.SizeOf<CCallbackBase>());
4141
var callback = (CCallbackBase*)pCallback;
4242

43-
callback->m_vfptr = CCallbackBaseVTable.VTablePtr;
44-
callback->m_nCallbackFlags = 0;
43+
callback->m_vfptr = CCallbackBaseVTable.CallbackVTablePtr;
44+
callback->m_nCallbackFlags = 0x02; // k_ECallbackFlagsGameServer
4545
callback->m_iCallback = callbackId;
4646

4747
// Register with Steam API
@@ -55,7 +55,7 @@ internal static unsafe void RegisterCallback<T>(ICallbackHandler<T> handler) whe
5555
/// <summary>
5656
/// Unregister a callback handler
5757
/// </summary>
58-
internal static unsafe void UnregisterCallback<T>(ICallbackHandler<T> handler) where T : struct
58+
internal static unsafe void UnregisterCallback<T>( ICallbackHandler<T> handler ) where T : struct
5959
{
6060
var callbackId = CallbackIdentities.GetCallbackIdentity(typeof(T));
6161

@@ -80,7 +80,7 @@ internal static unsafe void UnregisterCallback<T>(ICallbackHandler<T> handler) w
8080
/// <summary>
8181
/// Register a call result handler
8282
/// </summary>
83-
internal static unsafe void RegisterCallResult<T>(ulong hAPICall, ICallResultHandler<T> handler) where T : struct
83+
internal static unsafe void RegisterCallResult<T>( ulong hAPICall, ICallResultHandler<T> handler ) where T : struct
8484
{
8585
var callbackId = CallbackIdentities.GetCallbackIdentity(typeof(T));
8686

@@ -91,8 +91,8 @@ internal static unsafe void RegisterCallResult<T>(ulong hAPICall, ICallResultHan
9191
var pCallback = Marshal.AllocHGlobal(Marshal.SizeOf<CCallbackBase>());
9292
var callback = (CCallbackBase*)pCallback;
9393

94-
callback->m_vfptr = CCallbackBaseVTable.VTablePtr;
95-
callback->m_nCallbackFlags = 1; // Flag indicating this is a call result
94+
callback->m_vfptr = CCallbackBaseVTable.CallResultVTablePtr;
95+
callback->m_nCallbackFlags = 0x02; // k_ECallbackFlagsGameServer
9696
callback->m_iCallback = callbackId;
9797

9898
// Register with Steam API
@@ -105,7 +105,7 @@ internal static unsafe void RegisterCallResult<T>(ulong hAPICall, ICallResultHan
105105
/// <summary>
106106
/// Unregister a call result
107107
/// </summary>
108-
internal static unsafe void UnregisterCallResult(ulong hAPICall, IntPtr pCallback)
108+
internal static unsafe void UnregisterCallResult( ulong hAPICall, IntPtr pCallback )
109109
{
110110
_ = s_callResultHandlers.TryRemove(hAPICall, out _);
111111

@@ -119,7 +119,7 @@ internal static unsafe void UnregisterCallResult(ulong hAPICall, IntPtr pCallbac
119119
/// <summary>
120120
/// Internal method called from VTable Run function
121121
/// </summary>
122-
internal static unsafe void DispatchCallback(int callbackId, void* param)
122+
internal static unsafe void DispatchCallback( int callbackId, void* param )
123123
{
124124
if (s_callbackHandlers.TryGetValue(callbackId, out var handlers))
125125
{
@@ -140,7 +140,7 @@ internal static unsafe void DispatchCallback(int callbackId, void* param)
140140
/// <summary>
141141
/// Internal method called from VTable RunCallResult function
142142
/// </summary>
143-
internal static unsafe void DispatchCallResult(void* param, bool ioFailure, ulong hAPICall)
143+
internal static unsafe void DispatchCallResult( void* param, bool ioFailure, ulong hAPICall )
144144
{
145145
if (s_callResultHandlers.TryRemove(hAPICall, out var handler))
146146
{
@@ -150,7 +150,7 @@ internal static unsafe void DispatchCallResult(void* param, bool ioFailure, ulon
150150
}
151151
catch (Exception ex)
152152
{
153-
Console.WriteLine($"Error dispatching call result {hAPICall}: {ex}");
153+
Console.WriteLine($"Error dispatching call result: {ex}");
154154
}
155155
}
156156
}
@@ -161,7 +161,7 @@ internal static unsafe void DispatchCallResult(void* param, bool ioFailure, ulon
161161
/// </summary>
162162
internal interface ICallbackHandler
163163
{
164-
internal unsafe void Run(void* param);
164+
internal unsafe void Run( void* param );
165165
}
166166

167167
/// <summary>
@@ -176,8 +176,8 @@ internal interface ICallbackHandler<T> : ICallbackHandler where T : struct
176176
/// </summary>
177177
internal interface ICallResultHandler
178178
{
179-
internal unsafe void Run(void* param, bool ioFailure);
180-
internal void SetAPICall(ulong hAPICall, IntPtr pCallback);
179+
internal unsafe void Run( void* param, bool ioFailure );
180+
internal void SetAPICall( ulong hAPICall, IntPtr pCallback );
181181
}
182182

183183
/// <summary>
@@ -196,15 +196,15 @@ public sealed class Callback<T> : ICallbackHandler<T>, IDisposable where T : str
196196
private bool _isRegistered;
197197
private bool _disposed;
198198

199-
private Callback(Action<T> callback)
199+
private Callback( Action<T> callback )
200200
{
201201
_callback = callback;
202202
}
203203

204204
/// <summary>
205205
/// Create and register a new callback
206206
/// </summary>
207-
public static Callback<T> Create(Action<T> callback)
207+
public static Callback<T> Create( Action<T> callback )
208208
{
209209
var instance = new Callback<T>(callback);
210210
instance.Register();
@@ -229,7 +229,7 @@ private void Unregister()
229229
}
230230
}
231231

232-
unsafe void ICallbackHandler.Run(void* param)
232+
unsafe void ICallbackHandler.Run( void* param )
233233
{
234234
if (_callback != null && !_disposed)
235235
{
@@ -265,15 +265,15 @@ public sealed class CallResult<T> : ICallResultHandler<T>, IDisposable where T :
265265
private IntPtr _pCallback;
266266
private bool _disposed;
267267

268-
private CallResult(Action<T, bool> callback)
268+
private CallResult( Action<T, bool> callback )
269269
{
270270
_callback = callback;
271271
}
272272

273273
/// <summary>
274274
/// Create and register a new call result
275275
/// </summary>
276-
public static CallResult<T> Create(ulong hAPICall, Action<T, bool> callback)
276+
public static CallResult<T> Create( ulong hAPICall, Action<T, bool> callback )
277277
{
278278
var instance = new CallResult<T>(callback);
279279
instance.Set(hAPICall);
@@ -283,7 +283,7 @@ public static CallResult<T> Create(ulong hAPICall, Action<T, bool> callback)
283283
/// <summary>
284284
/// Set or change the API call to wait for
285285
/// </summary>
286-
public void Set(ulong hAPICall)
286+
public void Set( ulong hAPICall )
287287
{
288288
if (_disposed)
289289
return;
@@ -302,13 +302,13 @@ public void Set(ulong hAPICall)
302302
}
303303
}
304304

305-
void ICallResultHandler.SetAPICall(ulong hAPICall, IntPtr pCallback)
305+
void ICallResultHandler.SetAPICall( ulong hAPICall, IntPtr pCallback )
306306
{
307307
_hAPICall = hAPICall;
308308
_pCallback = pCallback;
309309
}
310310

311-
unsafe void ICallResultHandler.Run(void* param, bool ioFailure)
311+
unsafe void ICallResultHandler.Run( void* param, bool ioFailure )
312312
{
313313
if (_callback != null && !_disposed)
314314
{
@@ -346,7 +346,7 @@ public void Dispose()
346346
/// Native callback structure that matches C++ CCallbackBase layout
347347
/// This structure is passed to SteamAPI_RegisterCallback
348348
/// </summary>
349-
[StructLayout(LayoutKind.Sequential)]
349+
[StructLayout(LayoutKind.Sequential, Pack = 4)]
350350
internal unsafe struct CCallbackBase
351351
{
352352
public IntPtr m_vfptr;
@@ -359,24 +359,31 @@ internal unsafe struct CCallbackBase
359359
/// </summary>
360360
internal static class CCallbackBaseVTable
361361
{
362-
public static IntPtr VTablePtr { get; private set; }
362+
public static IntPtr CallbackVTablePtr { get; private set; }
363+
public static IntPtr CallResultVTablePtr { get; private set; }
363364

364365
static unsafe CCallbackBaseVTable()
365366
{
366367
// Allocate VTable with 3 function pointers
367-
VTablePtr = Marshal.AllocHGlobal(IntPtr.Size * 3);
368-
Span<IntPtr> vtable = new((void*)VTablePtr, 3);
369-
370-
vtable[0] = (IntPtr)(delegate* unmanaged<CCallbackBase*, void*, void>)&Run;
371-
vtable[1] = (IntPtr)(delegate* unmanaged<CCallbackBase*, void*, bool, ulong, void>)&RunCallResult;
372-
vtable[2] = (IntPtr)(delegate* unmanaged<CCallbackBase*, int>)&GetCallbackSizeBytes;
368+
CallbackVTablePtr = Marshal.AllocHGlobal(IntPtr.Size * 3);
369+
CallResultVTablePtr = Marshal.AllocHGlobal(IntPtr.Size * 3);
370+
Span<IntPtr> vtable = new((void*)CallbackVTablePtr, 3);
371+
Span<IntPtr> callResultVtable = new((void*)CallResultVTablePtr, 3);
372+
373+
vtable[0] = (IntPtr)(delegate* unmanaged< CCallbackBase*, void*, void >)&RunCallback;
374+
vtable[1] = (IntPtr)(delegate* unmanaged< CCallbackBase*, void*, byte, ulong, void >)&RunCallbackOverload;
375+
vtable[2] = (IntPtr)(delegate* unmanaged< CCallbackBase*, int >)&GetCallbackSizeBytes;
376+
377+
callResultVtable[0] = (IntPtr)(delegate* unmanaged< CCallbackBase*, void*, void >)&RunCallResult;
378+
callResultVtable[1] = (IntPtr)(delegate* unmanaged< CCallbackBase*, void*, byte, ulong, void >)&RunCallResultOverload;
379+
callResultVtable[2] = (IntPtr)(delegate* unmanaged< CCallbackBase*, int >)&GetCallbackSizeBytes;
373380
}
374381

375382
/// <summary>
376383
/// Called by Steam when a callback is triggered
377384
/// </summary>
378385
[UnmanagedCallersOnly]
379-
private static unsafe void Run(CCallbackBase* self, void* param)
386+
private static unsafe void RunCallback( CCallbackBase* self, void* param )
380387
{
381388
try
382389
{
@@ -389,15 +396,40 @@ private static unsafe void Run(CCallbackBase* self, void* param)
389396
}
390397
}
391398

399+
400+
/// <summary>
401+
/// Called by Steam when a callback is triggered, overload version
402+
/// </summary>
403+
[UnmanagedCallersOnly]
404+
private static unsafe void RunCallbackOverload( CCallbackBase* self, void* param, byte ioFailure, ulong hAPICall )
405+
{
406+
try
407+
{
408+
var callbackId = self->m_iCallback;
409+
CallbackDispatcher.DispatchCallback(callbackId, param);
410+
}
411+
catch (Exception ex)
412+
{
413+
Console.WriteLine($"Exception in CCallbackBase.RunCallResult: {ex}");
414+
}
415+
}
416+
417+
[UnmanagedCallersOnly]
418+
private static unsafe void RunCallResult( CCallbackBase* self, void* param )
419+
{
420+
throw new NotImplementedException("Shouldn't be called.");
421+
}
422+
423+
392424
/// <summary>
393425
/// Called by Steam when a call result is ready
394426
/// </summary>
395427
[UnmanagedCallersOnly]
396-
private static unsafe void RunCallResult(CCallbackBase* self, void* param, bool ioFailure, ulong hAPICall)
428+
private static unsafe void RunCallResultOverload( CCallbackBase* self, void* param, byte ioFailure, ulong hAPICall )
397429
{
398430
try
399431
{
400-
CallbackDispatcher.DispatchCallResult(param, ioFailure, hAPICall);
432+
CallbackDispatcher.DispatchCallResult(param, ioFailure == 1, hAPICall);
401433
}
402434
catch (Exception ex)
403435
{
@@ -409,8 +441,9 @@ private static unsafe void RunCallResult(CCallbackBase* self, void* param, bool
409441
/// Returns the size of the callback structure
410442
/// </summary>
411443
[UnmanagedCallersOnly]
412-
private static unsafe int GetCallbackSizeBytes(CCallbackBase* self)
444+
private static unsafe int GetCallbackSizeBytes( CCallbackBase* self )
413445
{
446+
Console.WriteLine($"GetCallbackSizeBytes");
414447
try
415448
{
416449
int callbackId = self->m_iCallback;

managed/src/TestPlugin/TestPlugin.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,9 @@ public void TestCommand( ICommandContext context )
327327
public void TestCommand1( ICommandContext context )
328328
{
329329
var ret = SteamGameServerUGC.DownloadItem(new PublishedFileId_t(3596198331), true);
330-
Console.WriteLine(Core.Engine.ServerIP);
330+
Console.WriteLine(SteamGameServer.GetPublicIP().ToIPAddress());
331+
332+
331333
}
332334

333335
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
@@ -544,7 +546,7 @@ public void OnSteamAPIActivated()
544546

545547
public void AuthResponse( ValidateAuthTicketResponse_t param )
546548
{
547-
Console.WriteLine($"AuthResponse: {param.m_eAuthSessionResponse} -> {param.m_SteamID.m_SteamID}");
549+
Console.WriteLine($"AuthResponse {param.m_eAuthSessionResponse} -> {param.m_SteamID.m_SteamID}");
548550
}
549551

550552
[Command("getip")]

0 commit comments

Comments
 (0)