diff --git a/Facepunch.Steamworks/BaseSteamworks.cs b/Facepunch.Steamworks/BaseSteamworks.cs
index 76803fb..ee06870 100644
--- a/Facepunch.Steamworks/BaseSteamworks.cs
+++ b/Facepunch.Steamworks/BaseSteamworks.cs
@@ -72,10 +72,15 @@ public enum MessageType : int
///
/// Global callback type
///
+ internal void AddCallback( Action Callback, int id )
+ {
+ var callback = new Callback( IsGameServer, id, Callback );
+ Disposables.Add( callback );
+ }
+
internal void AddCallback( Action Callback, int id )
{
- var callback = new Callback( IsGameServer, id, Callback );
- Disposables.Add( callback );
+ AddCallback( Callback, id );
}
public Action OnUpdate;
diff --git a/Facepunch.Steamworks/Callbacks/Networking.cs b/Facepunch.Steamworks/Callbacks/Networking.cs
index 1f7add2..dd77ffd 100644
--- a/Facepunch.Steamworks/Callbacks/Networking.cs
+++ b/Facepunch.Steamworks/Callbacks/Networking.cs
@@ -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;
diff --git a/Facepunch.Steamworks/Callbacks/User.cs b/Facepunch.Steamworks/Callbacks/User.cs
index b988c2d..2838f99 100644
--- a/Facepunch.Steamworks/Callbacks/User.cs
+++ b/Facepunch.Steamworks/Callbacks/User.cs
@@ -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;
};
diff --git a/Facepunch.Steamworks/Callbacks/Workshop.cs b/Facepunch.Steamworks/Callbacks/Workshop.cs
index c6a8a44..9d09270 100644
--- a/Facepunch.Steamworks/Callbacks/Workshop.cs
+++ b/Facepunch.Steamworks/Callbacks/Workshop.cs
@@ -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
+
+ internal class QueryCompleted : CallResult
{
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
+ internal class CreateItem : CallResult
{
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
+ internal class SubmitItemUpdate : CallResult
{
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;
+ };
};
}
}
diff --git a/Facepunch.Steamworks/Config.cs b/Facepunch.Steamworks/Config.cs
index 9f94f34..27d8392 100644
--- a/Facepunch.Steamworks/Config.cs
+++ b/Facepunch.Steamworks/Config.cs
@@ -18,6 +18,11 @@ public static class Config
///
public static bool UseThisCall { get; set; } = true;
+ ///
+ /// Set this to true on Linux and OSX
+ ///
+ public static bool PackSmall { get; set; } = false;
+
///
/// The Native dll to look for. This is the steam_api.dll renamed.
diff --git a/Facepunch.Steamworks/Interfaces/Workshop.Item.cs b/Facepunch.Steamworks/Interfaces/Workshop.Item.cs
index 96eaaf7..58e01da 100644
--- a/Facepunch.Steamworks/Interfaces/Workshop.Item.cs
+++ b/Facepunch.Steamworks/Interfaces/Workshop.Item.cs
@@ -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();
diff --git a/Facepunch.Steamworks/Interfaces/Workshop.Query.cs b/Facepunch.Steamworks/Interfaces/Workshop.Query.cs
index dd453a2..835b8c3 100644
--- a/Facepunch.Steamworks/Interfaces/Workshop.Query.cs
+++ b/Facepunch.Steamworks/Interfaces/Workshop.Query.cs
@@ -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;
diff --git a/Facepunch.Steamworks/Interfaces/Workshop.cs b/Facepunch.Steamworks/Interfaces/Workshop.cs
index af57e54..a99dc61 100644
--- a/Facepunch.Steamworks/Interfaces/Workshop.cs
+++ b/Facepunch.Steamworks/Interfaces/Workshop.cs
@@ -22,8 +22,8 @@ internal Workshop( BaseSteamworks steamworks, ISteamUGC ugc, ISteamRemoteStorage
this.steamworks = steamworks;
this.remoteStorage = remoteStorage;
- steamworks.AddCallback( onDownloadResult, DownloadResult.CallbackId );
- steamworks.AddCallback( onItemInstalled, ItemInstalled.CallbackId );
+ steamworks.AddCallback( onDownloadResult, DownloadResult.CallbackId );
+ steamworks.AddCallback( onItemInstalled, ItemInstalled.CallbackId );
}
public void Dispose()
diff --git a/Facepunch.Steamworks/Interop/CallResult.cs b/Facepunch.Steamworks/Interop/CallResult.cs
index 73bc612..bf40610 100644
--- a/Facepunch.Steamworks/Interop/CallResult.cs
+++ b/Facepunch.Steamworks/Interop/CallResult.cs
@@ -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 : CallResult
+ internal unsafe abstract class CallResult : 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 OnResult;
+ public Action 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 onRunCallback, Func getSize, Interop.Callback cb )
+ internal static IntPtr Get( Action 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 );
diff --git a/Facepunch.Steamworks/Interop/Callback.cs b/Facepunch.Steamworks/Interop/Callback.cs
index c6667f8..e20ecb5 100644
--- a/Facepunch.Steamworks/Interop/Callback.cs
+++ b/Facepunch.Steamworks/Interop/Callback.cs
@@ -48,7 +48,7 @@ internal void AddHandle( GCHandle gCHandle )
}
}
- internal partial class Callback : Callback
+ internal partial class Callback : 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;
}