mirror of
https://github.com/Facepunch/Facepunch.Steamworks.git
synced 2024-12-25 14:15:47 +03:00
Struct packing, first pass
This commit is contained in:
parent
f0e09d4331
commit
dfbbaaae47
@ -72,10 +72,15 @@ public enum MessageType : int
|
||||
/// <summary>
|
||||
/// Global callback type
|
||||
/// </summary>
|
||||
internal void AddCallback<T, TSmall>( Action<T> Callback, int id )
|
||||
{
|
||||
var callback = new Callback<T, TSmall>( IsGameServer, id, Callback );
|
||||
Disposables.Add( callback );
|
||||
}
|
||||
|
||||
internal void AddCallback<T>( Action<T> Callback, int id )
|
||||
{
|
||||
var callback = new Callback<T>( IsGameServer, id, Callback );
|
||||
Disposables.Add( callback );
|
||||
AddCallback<T, T>( Callback, id );
|
||||
}
|
||||
|
||||
public Action OnUpdate;
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
namespace Facepunch.Steamworks.Callbacks.Networking
|
||||
{
|
||||
[StructLayout( LayoutKind.Sequential )]
|
||||
[StructLayout( LayoutKind.Sequential, Pack = 1 )]
|
||||
internal class P2PSessionRequest
|
||||
{
|
||||
public ulong SteamID;
|
||||
@ -14,7 +14,7 @@ internal class P2PSessionRequest
|
||||
public const int CallbackId = Index.Networking + 2;
|
||||
};
|
||||
|
||||
[StructLayout( LayoutKind.Sequential )]
|
||||
[StructLayout( LayoutKind.Sequential, Pack = 1 )]
|
||||
internal class P2PSessionConnectFail
|
||||
{
|
||||
public ulong SteamID;
|
||||
|
@ -6,9 +6,15 @@
|
||||
|
||||
namespace Facepunch.Steamworks.Callbacks.User
|
||||
{
|
||||
[StructLayout( LayoutKind.Explicit )]
|
||||
[StructLayout( LayoutKind.Sequential, Pack = 1 )]
|
||||
internal struct ValidateAuthTicketResponse
|
||||
{
|
||||
public ulong SteamID;
|
||||
public int AuthResponse;
|
||||
public ulong OwnerSteamID;
|
||||
|
||||
public const int CallbackId = Index.User + 43;
|
||||
|
||||
public enum Response : int
|
||||
{
|
||||
Okay = 0, // Steam has verified the user is online, the ticket is valid and ticket has not been reused.
|
||||
@ -22,15 +28,6 @@ public enum Response : int
|
||||
AuthTicketInvalid = 8, // This ticket is not from a user instance currently connected to steam.
|
||||
PublisherIssuedBan = 9, // The user is banned for this game. The ban came via the web api and not VAC
|
||||
};
|
||||
|
||||
[FieldOffset(0)]
|
||||
public ulong SteamID;
|
||||
[FieldOffset(8)]
|
||||
public Response AuthResponse;
|
||||
[FieldOffset(12)]
|
||||
public ulong OwnerSteamID;
|
||||
|
||||
public const int CallbackId = Index.User + 43;
|
||||
};
|
||||
|
||||
|
||||
|
@ -4,70 +4,104 @@
|
||||
namespace Facepunch.Steamworks.Callbacks.Workshop
|
||||
{
|
||||
|
||||
[StructLayout( LayoutKind.Explicit )]
|
||||
internal class ItemInstalled
|
||||
[StructLayout( LayoutKind.Sequential, Pack = 8 )]
|
||||
internal struct ItemInstalled
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public uint AppId;
|
||||
[FieldOffset(4)]
|
||||
public ulong FileId;
|
||||
|
||||
public const int CallbackId = Index.UGC + 5;
|
||||
|
||||
[StructLayout( LayoutKind.Sequential, Pack = 4 )]
|
||||
internal struct Small
|
||||
{
|
||||
public uint AppId;
|
||||
public ulong FileId;
|
||||
};
|
||||
};
|
||||
|
||||
[StructLayout( LayoutKind.Explicit )]
|
||||
internal class DownloadResult
|
||||
[StructLayout( LayoutKind.Sequential, Pack = 8 )]
|
||||
internal struct DownloadResult
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public uint AppId;
|
||||
[FieldOffset(4)]
|
||||
public ulong FileId;
|
||||
[FieldOffset(12)]
|
||||
public Result Result;
|
||||
|
||||
public const int CallbackId = Index.UGC + 6;
|
||||
|
||||
[StructLayout( LayoutKind.Sequential, Pack = 4 )]
|
||||
internal struct Small
|
||||
{
|
||||
public uint AppId;
|
||||
public ulong FileId;
|
||||
public Result Result;
|
||||
};
|
||||
};
|
||||
|
||||
internal class QueryCompleted : CallResult<QueryCompleted.Data>
|
||||
|
||||
internal class QueryCompleted : CallResult<QueryCompleted.Data, QueryCompleted.Data.Small>
|
||||
{
|
||||
public override int CallbackId { get { return Index.UGC + 1; } }
|
||||
|
||||
[StructLayout( LayoutKind.Sequential )]
|
||||
[StructLayout( LayoutKind.Sequential, Pack = 8 )]
|
||||
internal struct Data
|
||||
{
|
||||
internal ulong Handle;
|
||||
internal int Result;
|
||||
internal uint m_unNumResultsReturned;
|
||||
internal uint m_unTotalMatchingResults;
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
internal bool m_bCachedData; // indicates whether this data was retrieved from the local on-disk cache
|
||||
internal uint NumResultsReturned;
|
||||
internal uint TotalMatchingResults;
|
||||
internal bool CachedData;
|
||||
|
||||
[StructLayout( LayoutKind.Sequential, Pack = 4 )]
|
||||
internal struct Small
|
||||
{
|
||||
internal ulong Handle;
|
||||
internal int Result;
|
||||
internal uint NumResultsReturned;
|
||||
internal uint TotalMatchingResults;
|
||||
internal bool CachedData;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
internal class CreateItem : CallResult<CreateItem.Data>
|
||||
internal class CreateItem : CallResult<CreateItem.Data, CreateItem.Data.Small>
|
||||
{
|
||||
public override int CallbackId { get { return Index.UGC + 3; } }
|
||||
|
||||
[StructLayout( LayoutKind.Sequential )]
|
||||
[StructLayout( LayoutKind.Sequential, Pack = 8 )]
|
||||
internal struct Data
|
||||
{
|
||||
internal Result Result;
|
||||
internal ulong FileId;
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
internal bool NeedsLegalAgreement;
|
||||
|
||||
[StructLayout( LayoutKind.Sequential, Pack = 4 )]
|
||||
internal struct Small
|
||||
{
|
||||
internal Result Result;
|
||||
internal ulong FileId;
|
||||
|
||||
internal bool NeedsLegalAgreement;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
internal class SubmitItemUpdate : CallResult<SubmitItemUpdate.Data>
|
||||
internal class SubmitItemUpdate : CallResult<SubmitItemUpdate.Data, SubmitItemUpdate.Data.Small>
|
||||
{
|
||||
public override int CallbackId { get { return Index.UGC + 4; } }
|
||||
|
||||
[StructLayout( LayoutKind.Sequential )]
|
||||
[StructLayout( LayoutKind.Sequential, Pack = 8 )]
|
||||
internal struct Data
|
||||
{
|
||||
internal Result Result;
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
internal bool NeedsLegalAgreement;
|
||||
|
||||
[StructLayout( LayoutKind.Sequential, Pack = 4 )]
|
||||
internal struct Small
|
||||
{
|
||||
internal Result Result;
|
||||
internal bool NeedsLegalAgreement;
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,11 @@ public static class Config
|
||||
/// </summary>
|
||||
public static bool UseThisCall { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Set this to true on Linux and OSX
|
||||
/// </summary>
|
||||
public static bool PackSmall { get; set; } = false;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The Native dll to look for. This is the steam_api.dll renamed.
|
||||
|
@ -65,6 +65,7 @@ public void Download( bool highPriority = true )
|
||||
|
||||
private void OnFileDownloaded( ulong fileid, Callbacks.Result result )
|
||||
{
|
||||
if ( fileid != Id ) return;
|
||||
|
||||
workshop.OnFileDownloaded -= OnFileDownloaded;
|
||||
UpdateState();
|
||||
@ -75,6 +76,7 @@ private void OnFileDownloaded( ulong fileid, Callbacks.Result result )
|
||||
|
||||
private void OnItemInstalled( ulong fileid )
|
||||
{
|
||||
if ( fileid != Id ) return;
|
||||
|
||||
workshop.OnItemInstalled -= OnItemInstalled;
|
||||
UpdateState();
|
||||
|
@ -86,8 +86,8 @@ public unsafe void Run()
|
||||
|
||||
void OnResult( QueryCompleted.Data data )
|
||||
{
|
||||
Items = new Item[data.m_unNumResultsReturned];
|
||||
for ( int i = 0; i < data.m_unNumResultsReturned; i++ )
|
||||
Items = new Item[data.NumResultsReturned];
|
||||
for ( int i = 0; i < data.NumResultsReturned; i++ )
|
||||
{
|
||||
SteamUGCDetails_t details = new SteamUGCDetails_t();
|
||||
workshop.ugc.GetQueryUGCResult( data.Handle, (uint)i, ref details );
|
||||
@ -95,7 +95,7 @@ void OnResult( QueryCompleted.Data data )
|
||||
Items[i] = Item.From( details, workshop );
|
||||
}
|
||||
|
||||
TotalResults = (int)data.m_unTotalMatchingResults;
|
||||
TotalResults = (int)data.TotalMatchingResults;
|
||||
|
||||
Callback.Dispose();
|
||||
Callback = null;
|
||||
|
@ -22,8 +22,8 @@ internal Workshop( BaseSteamworks steamworks, ISteamUGC ugc, ISteamRemoteStorage
|
||||
this.steamworks = steamworks;
|
||||
this.remoteStorage = remoteStorage;
|
||||
|
||||
steamworks.AddCallback<DownloadResult>( onDownloadResult, DownloadResult.CallbackId );
|
||||
steamworks.AddCallback<ItemInstalled>( onItemInstalled, ItemInstalled.CallbackId );
|
||||
steamworks.AddCallback<DownloadResult, DownloadResult.Small>( onDownloadResult, DownloadResult.CallbackId );
|
||||
steamworks.AddCallback<ItemInstalled, DownloadResult.Small>( onItemInstalled, ItemInstalled.CallbackId );
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Valve.Steamworks;
|
||||
@ -19,14 +20,19 @@ public void Dispose()
|
||||
internal abstract void Run( ISteamUtils utils );
|
||||
}
|
||||
|
||||
internal unsafe abstract class CallResult<T> : CallResult
|
||||
internal unsafe abstract class CallResult<T, TSmall> : CallResult where T: new()
|
||||
{
|
||||
public static FieldInfo[] SourceFields = typeof( TSmall ).GetFields();
|
||||
public static FieldInfo[] DestFields = typeof( T ).GetFields();
|
||||
|
||||
public abstract int CallbackId { get; }
|
||||
public Action<T> OnResult;
|
||||
|
||||
internal override void Run( ISteamUtils utils )
|
||||
{
|
||||
var datasize = Marshal.SizeOf( typeof( T ) );
|
||||
var packSmall = Config.PackSmall;
|
||||
|
||||
var datasize = packSmall ? Marshal.SizeOf( typeof( TSmall ) ) : Marshal.SizeOf( typeof( T ) );
|
||||
var data = stackalloc byte[ datasize ];
|
||||
bool failed = false;
|
||||
|
||||
@ -36,10 +42,28 @@ internal override void Run( ISteamUtils utils )
|
||||
return;
|
||||
}
|
||||
|
||||
if ( packSmall )
|
||||
{
|
||||
var dataTarget = new T();
|
||||
var dataObject = (TSmall)Marshal.PtrToStructure( (IntPtr) data, typeof( TSmall ) );
|
||||
|
||||
for ( int i=0; i<SourceFields.Length; i++ )
|
||||
{
|
||||
DestFields[i].SetValue( dataTarget, SourceFields[i].GetValue( dataObject ) );
|
||||
}
|
||||
|
||||
if ( OnResult != null )
|
||||
OnResult( dataTarget );
|
||||
}
|
||||
else
|
||||
{
|
||||
var dataObject = (T)Marshal.PtrToStructure( (IntPtr) data, typeof( T ) );
|
||||
|
||||
if ( OnResult != null )
|
||||
OnResult( dataObject );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -9,37 +9,28 @@ namespace Facepunch.Steamworks.Interop.VTable.This
|
||||
[StructLayout( LayoutKind.Sequential )]
|
||||
internal struct Callback
|
||||
{
|
||||
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
|
||||
public delegate void Result( IntPtr thisptr, IntPtr pvParam );
|
||||
[UnmanagedFunctionPointer( CallingConvention.ThisCall )] public delegate void Result( IntPtr thisptr, IntPtr pvParam );
|
||||
[UnmanagedFunctionPointer( CallingConvention.ThisCall )] public delegate int GetSize( IntPtr thisptr );
|
||||
|
||||
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
|
||||
public delegate int GetSize( IntPtr thisptr );
|
||||
[MarshalAs(UnmanagedType.FunctionPtr)] public Result RunCallResult;
|
||||
[MarshalAs(UnmanagedType.FunctionPtr)] public Result RunCallback;
|
||||
[MarshalAs(UnmanagedType.FunctionPtr)] public GetSize GetCallbackSizeBytes;
|
||||
|
||||
[MarshalAs(UnmanagedType.FunctionPtr)]
|
||||
public Result m_RunCallback;
|
||||
|
||||
[MarshalAs(UnmanagedType.FunctionPtr)]
|
||||
public Result m_RunCallResult;
|
||||
|
||||
[MarshalAs(UnmanagedType.FunctionPtr)]
|
||||
public GetSize m_GetCallbackSizeBytes;
|
||||
|
||||
internal static IntPtr Get( Action<IntPtr> onRunCallback, Func<int> getSize, Interop.Callback cb )
|
||||
internal static IntPtr Get( Action<IntPtr, IntPtr> onRunCallback, int size, Interop.Callback cb )
|
||||
{
|
||||
var size = Marshal.SizeOf( typeof( Callback ) );
|
||||
var ptr = Marshal.AllocHGlobal( size );
|
||||
var ptr = Marshal.AllocHGlobal( Marshal.SizeOf( typeof( Callback ) ) );
|
||||
|
||||
Callback.Result da = ( _, p ) => onRunCallback( p );
|
||||
Callback.GetSize dc = ( _ ) => getSize();
|
||||
Callback.Result da = ( _, p ) => { onRunCallback( _, p ); Console.WriteLine( "Callback.Result: {0}", _.ToInt64() ); };
|
||||
Callback.GetSize dc = ( _ ) => { return size; };
|
||||
|
||||
cb.AddHandle( GCHandle.Alloc( da ) );
|
||||
cb.AddHandle( GCHandle.Alloc( dc ) );
|
||||
|
||||
var table = new Callback()
|
||||
{
|
||||
m_RunCallResult = da,
|
||||
m_RunCallback = da,
|
||||
m_GetCallbackSizeBytes = dc
|
||||
RunCallback = da,
|
||||
RunCallResult = da,
|
||||
GetCallbackSizeBytes = dc
|
||||
};
|
||||
|
||||
Marshal.StructureToPtr( table, ptr, false );
|
||||
|
@ -48,7 +48,7 @@ internal void AddHandle( GCHandle gCHandle )
|
||||
}
|
||||
}
|
||||
|
||||
internal partial class Callback<T> : Callback
|
||||
internal partial class Callback<T, TSmall> : Callback
|
||||
{
|
||||
public int CallbackId = 0;
|
||||
public bool GameServer = false;
|
||||
@ -87,10 +87,13 @@ public override void Dispose()
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
private void OnRunCallback( IntPtr ptr )
|
||||
private void OnRunCallback( IntPtr thisObject, IntPtr ptr )
|
||||
{
|
||||
if ( callbackPin == null ) throw new System.Exception( "Callback wasn't pinned!" );
|
||||
if ( vTablePtr == IntPtr.Zero ) throw new System.Exception( "vTablePtr wasn't pinned!" );
|
||||
if ( thisObject != IntPtr.Zero && thisObject != callbackPin.AddrOfPinnedObject() ) throw new System.Exception( "This wasn't valid!" );
|
||||
|
||||
if ( Config.PackSmall && typeof(T) != typeof( TSmall ) ) throw new System.Exception( "Callback should use PackSmall" );
|
||||
|
||||
T data = (T) Marshal.PtrToStructure( ptr, typeof(T) );
|
||||
Function( data );
|
||||
@ -121,7 +124,7 @@ void InitVTable()
|
||||
{
|
||||
if ( Config.UseThisCall )
|
||||
{
|
||||
vTablePtr = VTable.This.Callback.Get( OnRunCallback, GetSize, this );
|
||||
vTablePtr = VTable.This.Callback.Get( OnRunCallback, Marshal.SizeOf( typeof( T ) ), this );
|
||||
return;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user