(965c31410a) Unstable v0.10.4.0

This commit is contained in:
Juan Pablo Arce
2020-07-21 08:57:50 -03:00
parent 4f8bd39789
commit 33d3a41104
546 changed files with 45952 additions and 25762 deletions
@@ -0,0 +1,95 @@
using Steamworks.Data;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace Steamworks
{
/// <summary>
/// An awaitable version of a SteamAPICall_t
/// </summary>
internal struct CallResult<T> : INotifyCompletion where T : struct, ICallbackData
{
SteamAPICall_t call;
ISteamUtils utils;
bool server;
public CallResult( SteamAPICall_t call, bool server )
{
this.call = call;
this.server = server;
utils = (server ? SteamUtils.InterfaceServer : SteamUtils.InterfaceClient) as ISteamUtils;
if ( utils == null )
utils = SteamUtils.Interface as ISteamUtils;
}
/// <summary>
/// This gets called if IsComplete returned false on the first call.
/// The Action "continues" the async call. We pass it to the Dispatch
/// to be called when the callback returns.
/// </summary>
public void OnCompleted( Action continuation )
{
Dispatch.OnCallComplete<T>( call, continuation, server );
}
/// <summary>
/// Gets the result. This is called internally by the async shit.
/// </summary>
public T? GetResult()
{
bool failed = false;
if ( !utils.IsAPICallCompleted( call, ref failed ) || failed )
return null;
var t = default( T );
var size = t.DataSize;
var ptr = Marshal.AllocHGlobal( size );
try
{
if ( !utils.GetAPICallResult( call, ptr, size, (int)t.CallbackType, ref failed ) || failed )
{
Dispatch.OnDebugCallback?.Invoke( t.CallbackType, "!GetAPICallResult or failed", server );
return null;
}
Dispatch.OnDebugCallback?.Invoke( t.CallbackType, Dispatch.CallbackToString( t.CallbackType, ptr, size ), server );
return ((T)Marshal.PtrToStructure( ptr, typeof( T ) ));
}
finally
{
Marshal.FreeHGlobal( ptr );
}
}
/// <summary>
/// Return true if complete or failed
/// </summary>
public bool IsCompleted
{
get
{
bool failed = false;
if ( utils.IsAPICallCompleted( call, ref failed ) || failed )
return true;
return false;
}
}
/// <summary>
/// This is what makes this struct awaitable
/// </summary>
internal CallResult<T> GetAwaiter()
{
return this;
}
}
}
@@ -1,43 +0,0 @@
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using Steamworks.Data;
namespace Steamworks
{
[StructLayout( LayoutKind.Sequential )]
internal partial class Callback
{
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void Run( IntPtr thisptr, IntPtr pvParam );
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void RunCall( IntPtr thisptr, IntPtr pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall );
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate int GetCallbackSizeBytes( IntPtr thisptr );
internal enum Flags : byte
{
Registered = 0x01,
GameServer = 0x02
}
public IntPtr vTablePtr;
public byte CallbackFlags;
public int CallbackId;
//
// These are functions that are on CCallback but are never called
// We could just send a IntPtr.Zero but it's probably safer to throw a
// big apeshit message if steam changes its behaviour at some point
//
[MonoPInvokeCallback]
internal static void RunStub( IntPtr self, IntPtr param, bool failure, SteamAPICall_t call ) =>
throw new System.Exception( "Something changed in the Steam API and now CCallbackBack is calling the CallResult function [Run( void *pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall )]" );
[MonoPInvokeCallback]
internal static int SizeStub( IntPtr self ) =>
throw new System.Exception( "Something changed in the Steam API and now CCallbackBack is calling the GetSize function [GetCallbackSizeBytes()]" );
};
}
@@ -1,135 +0,0 @@
using Steamworks.Data;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Steamworks
{
//
// Created on registration of a callback
//
internal class Event : IDisposable
{
internal static List<IDisposable> AllClient = new List<IDisposable>();
internal static List<IDisposable> AllServer = new List<IDisposable>();
internal static void DisposeAllClient()
{
foreach ( var a in AllClient.ToArray() )
{
a.Dispose();
}
AllClient.Clear();
}
internal static void DisposeAllServer()
{
foreach ( var a in AllServer.ToArray() )
{
a.Dispose();
}
AllServer.Clear();
}
internal static void Register( Callback.Run func, int size, int callbackId, bool gameserver )
{
var r = new Event();
r.vTablePtr = BuildVTable( func, r.Allocations );
//
// Create the callback object
//
var cb = new Callback();
cb.vTablePtr = r.vTablePtr;
cb.CallbackFlags = gameserver ? (byte)0x02 : (byte)0;
cb.CallbackId = callbackId;
//
// Pin the callback, so it doesn't get garbage collected and we can pass the pointer to native
//
r.PinnedCallback = GCHandle.Alloc( cb, GCHandleType.Pinned );
//
// Register the callback with Steam
//
SteamClient.RegisterCallback( r.PinnedCallback.AddrOfPinnedObject(), cb.CallbackId );
r.IsAllocated = true;
if ( gameserver )
Event.AllServer.Add( r );
else
Event.AllClient.Add( r );
}
static IntPtr BuildVTable( Callback.Run run, List<GCHandle> allocations )
{
var RunStub = (Callback.RunCall)Callback.RunStub;
var SizeStub = (Callback.GetCallbackSizeBytes)Callback.SizeStub;
allocations.Add( GCHandle.Alloc( run ) );
allocations.Add( GCHandle.Alloc( RunStub ) );
allocations.Add( GCHandle.Alloc( SizeStub ) );
var a = Marshal.GetFunctionPointerForDelegate<Callback.Run>( run );
var b = Marshal.GetFunctionPointerForDelegate<Callback.RunCall>( RunStub );
var c = Marshal.GetFunctionPointerForDelegate<Callback.GetCallbackSizeBytes>( SizeStub );
var vt = Marshal.AllocHGlobal( IntPtr.Size * 3 );
// Windows switches the function positions
#if PLATFORM_WIN
Marshal.WriteIntPtr( vt, IntPtr.Size * 0, b );
Marshal.WriteIntPtr( vt, IntPtr.Size * 1, a );
Marshal.WriteIntPtr( vt, IntPtr.Size * 2, c );
#else
Marshal.WriteIntPtr( vt, IntPtr.Size * 0, a );
Marshal.WriteIntPtr( vt, IntPtr.Size * 1, b );
Marshal.WriteIntPtr( vt, IntPtr.Size * 2, c );
#endif
return vt;
}
bool IsAllocated;
List<GCHandle> Allocations = new List<GCHandle>();
internal IntPtr vTablePtr;
internal GCHandle PinnedCallback;
public void Dispose()
{
if ( !IsAllocated ) return;
IsAllocated = false;
if ( !PinnedCallback.IsAllocated )
throw new System.Exception( "Callback isn't allocated!?" );
SteamClient.UnregisterCallback( PinnedCallback.AddrOfPinnedObject() );
foreach ( var a in Allocations )
{
if ( a.IsAllocated )
a.Free();
}
Allocations = null;
PinnedCallback.Free();
if ( vTablePtr != IntPtr.Zero )
{
Marshal.FreeHGlobal( vTablePtr );
vTablePtr = IntPtr.Zero;
}
}
~Event()
{
Dispose();
}
}
}
@@ -0,0 +1,17 @@
using Steamworks.Data;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace Steamworks
{
/// <summary>
/// Gives us a generic way to get the CallbackId of structs
/// </summary>
internal interface ICallbackData
{
CallbackType CallbackType { get; }
int DataSize { get; }
}
}