Struct packing, first pass

This commit is contained in:
Garry Newman 2016-10-10 15:39:18 +01:00
parent f0e09d4331
commit dfbbaaae47
11 changed files with 132 additions and 71 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;
};

View File

@ -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;
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;
};
};
}
}

View File

@ -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.

View File

@ -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();

View File

@ -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;

View File

@ -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()

View File

@ -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;
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;
}
var dataObject = (T)Marshal.PtrToStructure( (IntPtr) data, typeof( T ) );
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 );
}
if ( OnResult != null )
OnResult( dataObject );
}
}
}

View File

@ -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 );

View File

@ -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;
}