diff --git a/Facepunch.Steamworks.Test/Client/Workshop.cs b/Facepunch.Steamworks.Test/Client/Workshop.cs
index 2ced142..b26539c 100644
--- a/Facepunch.Steamworks.Test/Client/Workshop.cs
+++ b/Facepunch.Steamworks.Test/Client/Workshop.cs
@@ -38,7 +38,7 @@ public void Query()
Console.WriteLine( "Searching" );
Query.Order = Workshop.Order.RankedByTextSearch;
- Query.QueryType = Workshop.QueryType.Items_Mtx;
+ Query.QueryType = Workshop.QueryType.MicrotransactionItems;
Query.SearchText = "shit";
Query.RequireTags.Add( "LongTShirt Skin" );
Query.Run();
@@ -237,5 +237,34 @@ public void DownloadFile()
}
}
+ [TestMethod]
+ [TestCategory( "Run Manually" )]
+ public void CreatePublish()
+ {
+ using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
+ {
+ Assert.IsTrue( client.IsValid );
+
+ var item = client.Workshop.CreateItem( Workshop.ItemType.Microtransaction );
+
+ item.Title = "Facepunch.Steamworks Unit test";
+
+ item.Publish();
+
+ while ( item.Publishing )
+ {
+ client.Update();
+ Thread.Sleep( 100 );
+ }
+
+ Assert.IsFalse( item.Publishing );
+ Assert.AreNotEqual( 0, item.Id );
+
+ Console.WriteLine( "item.Id: {0}", item.Id );
+
+ item.Delete();
+ }
+ }
+
}
}
diff --git a/Facepunch.Steamworks/BaseSteamworks.cs b/Facepunch.Steamworks/BaseSteamworks.cs
index e5554dd..42ee8dc 100644
--- a/Facepunch.Steamworks/BaseSteamworks.cs
+++ b/Facepunch.Steamworks/BaseSteamworks.cs
@@ -36,7 +36,7 @@ public void SetupCommonInterfaces()
{
Networking = new Steamworks.Networking( this, native.networking );
Inventory = new Steamworks.Inventory( native.inventory, IsGameServer );
- Workshop = new Steamworks.Workshop( this, native.ugc );
+ Workshop = new Steamworks.Workshop( this, native.ugc, native.remoteStorage );
}
public bool IsValid
@@ -88,12 +88,14 @@ public virtual void Update()
///
/// Call results are results to specific actions
///
- internal void AddCallResult( CallResult c )
+ internal void AddCallResult( CallResult call )
{
- if ( FinishCallback( c ) )
+ if ( call == null ) throw new ArgumentNullException( "call" );
+
+ if ( FinishCallback( call ) )
return;
- Callbacks.Add( c );
+ Callbacks.Add( call );
}
void RunCallbackQueue()
diff --git a/Facepunch.Steamworks/Callbacks/Workshop.cs b/Facepunch.Steamworks/Callbacks/Workshop.cs
index e4570e5..c6a8a44 100644
--- a/Facepunch.Steamworks/Callbacks/Workshop.cs
+++ b/Facepunch.Steamworks/Callbacks/Workshop.cs
@@ -1,8 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
+using System.Runtime.InteropServices;
using Facepunch.Steamworks.Interop;
namespace Facepunch.Steamworks.Callbacks.Workshop
@@ -32,8 +28,6 @@ internal class DownloadResult
public const int CallbackId = Index.UGC + 6;
};
-
-
internal class QueryCompleted : CallResult
{
public override int CallbackId { get { return Index.UGC + 1; } }
@@ -50,5 +44,30 @@ internal struct Data
};
}
+ internal class CreateItem : CallResult
+ {
+ public override int CallbackId { get { return Index.UGC + 3; } }
+ [StructLayout( LayoutKind.Sequential )]
+ internal struct Data
+ {
+ internal Result Result;
+ internal ulong FileId;
+ [MarshalAs(UnmanagedType.I1)]
+ internal bool NeedsLegalAgreement;
+ };
+ }
+
+ internal class SubmitItemUpdate : CallResult
+ {
+ public override int CallbackId { get { return Index.UGC + 4; } }
+
+ [StructLayout( LayoutKind.Sequential )]
+ internal struct Data
+ {
+ internal Result Result;
+ [MarshalAs(UnmanagedType.I1)]
+ internal bool NeedsLegalAgreement;
+ };
+ }
}
diff --git a/Facepunch.Steamworks/Facepunch.Steamworks.csproj b/Facepunch.Steamworks/Facepunch.Steamworks.csproj
index 2c6bfb4..b28786b 100644
--- a/Facepunch.Steamworks/Facepunch.Steamworks.csproj
+++ b/Facepunch.Steamworks/Facepunch.Steamworks.csproj
@@ -137,7 +137,9 @@
+
+
diff --git a/Facepunch.Steamworks/Interfaces/Inventory.cs b/Facepunch.Steamworks/Interfaces/Inventory.cs
index cc9dbb1..89dd992 100644
--- a/Facepunch.Steamworks/Interfaces/Inventory.cs
+++ b/Facepunch.Steamworks/Interfaces/Inventory.cs
@@ -98,10 +98,7 @@ internal void FetchItemDefinitions()
int[] ids;
if ( !inventory.GetItemDefinitionIDs( out ids ) )
- {
- Console.WriteLine( "Couldn't load definitions" );
return;
- }
Definitions = ids.Select( x =>
{
diff --git a/Facepunch.Steamworks/Interfaces/Workshop.Editor.cs b/Facepunch.Steamworks/Interfaces/Workshop.Editor.cs
new file mode 100644
index 0000000..0950718
--- /dev/null
+++ b/Facepunch.Steamworks/Interfaces/Workshop.Editor.cs
@@ -0,0 +1,120 @@
+using System;
+using Facepunch.Steamworks.Callbacks.Workshop;
+
+namespace Facepunch.Steamworks
+{
+ public partial class Workshop
+ {
+ public class Editor
+ {
+ internal Workshop workshop;
+
+ internal CreateItem CreateItem;
+ internal SubmitItemUpdate SubmitItemUpdate;
+
+ public ulong Id { get; internal set; }
+ public string Title { get; set; }
+ public string Description { get; set; }
+ public bool Publishing { get; internal set; }
+ public ItemType? Type { get; set; }
+
+ public string ChangeNote { get; set; } = "";
+
+ public bool NeedToAgreeToWorkshopLegal { get; internal set; }
+
+ public void Publish()
+ {
+ Publishing = true;
+
+ if ( Id == 0 )
+ {
+ StartCreatingItem();
+ return;
+ }
+
+ PublishChanges();
+ }
+
+ private void StartCreatingItem()
+ {
+ if ( !Type.HasValue )
+ throw new System.Exception( "Editor.Type must be set when creating a new item!" );
+
+ CreateItem = new CreateItem();
+ CreateItem.Handle = workshop.ugc.CreateItem( workshop.steamworks.AppId, (uint)Type );
+ CreateItem.OnResult = OnItemCreated;
+ workshop.steamworks.AddCallResult( CreateItem );
+ }
+
+ private void OnItemCreated( CreateItem.Data obj )
+ {
+ NeedToAgreeToWorkshopLegal = obj.NeedsLegalAgreement;
+ CreateItem = null;
+
+ if ( obj.Result == Callbacks.Result.OK )
+ {
+ Id = obj.FileId;
+ PublishChanges();
+ return;
+ }
+
+ Console.WriteLine( "File publish error: " + obj );
+ Publishing = false;
+ }
+
+ private void PublishChanges()
+ {
+ Publishing = false;
+
+ ulong UpdateId = workshop.ugc.StartItemUpdate( workshop.steamworks.AppId, Id );
+
+ if ( Title != null )
+ workshop.ugc.SetItemTitle( UpdateId, Title );
+
+ if ( Description != null )
+ workshop.ugc.SetItemDescription( UpdateId, Description );
+
+ /*
+ workshop.ugc.SetItemUpdateLanguage( UpdateId, const char *pchLanguage ) = 0; // specify the language of the title or description that will be set
+ workshop.ugc.SetItemMetadata( UpdateId, const char *pchMetaData ) = 0; // change the metadata of an UGC item (max = k_cchDeveloperMetadataMax)
+ workshop.ugc.SetItemVisibility( UpdateId, ERemoteStoragePublishedFileVisibility eVisibility ) = 0; // change the visibility of an UGC item
+ workshop.ugc.SetItemTags( UpdateId, const SteamParamStringArray_t *pTags ) = 0; // change the tags of an UGC item
+ workshop.ugc.SetItemContent( UpdateId, const char *pszContentFolder ) = 0; // update item content from this local folder
+ workshop.ugc.SetItemPreview( UpdateId, const char *pszPreviewFile ) = 0; // change preview image file for this item. pszPreviewFile points to local image file, which must be under 1MB in size
+ workshop.ugc.RemoveItemKeyValueTags( UpdateId, const char *pchKey ) = 0; // remove any existing key-value tags with the specified key
+ workshop.ugc.AddItemKeyValueTag( UpdateId, const char *pchKey, const char *pchValue ) = 0; // add new key-value tags for the item. Note that there can be multiple values for a tag.
+ workshop.ugc.AddItemPreviewFile( UpdateId, const char *pszPreviewFile, EItemPreviewType type ) = 0; // add preview file for this item. pszPreviewFile points to local file, which must be under 1MB in size
+ workshop.ugc.AddItemPreviewVideo( UpdateId, const char *pszVideoID ) = 0; // add preview video for this item
+ workshop.ugc.UpdateItemPreviewFile( UpdateId, uint32 index, const char *pszPreviewFile ) = 0; // updates an existing preview file for this item. pszPreviewFile points to local file, which must be under 1MB in size
+ workshop.ugc.UpdateItemPreviewVideo( UpdateId, uint32 index, const char *pszVideoID ) = 0; // updates an existing preview video for this item
+ workshop.ugc.RemoveItemPreview( UpdateId, uint32 index ) = 0; // remove a preview by index starting at 0 (previews are sorted)
+
+ */
+
+ SubmitItemUpdate = new SubmitItemUpdate();
+ SubmitItemUpdate.Handle = workshop.ugc.SubmitItemUpdate( UpdateId, ChangeNote );
+ SubmitItemUpdate.OnResult = OnChangesSubmitted;
+ workshop.steamworks.AddCallResult( SubmitItemUpdate );
+ }
+
+ private void OnChangesSubmitted( SubmitItemUpdate.Data obj )
+ {
+ SubmitItemUpdate = null;
+
+ NeedToAgreeToWorkshopLegal = obj.NeedsLegalAgreement;
+
+ if ( obj.Result == Callbacks.Result.OK )
+ {
+ Publishing = false;
+ return;
+ }
+ }
+
+ public void Delete()
+ {
+ workshop.remoteStorage.DeletePublishedFile( Id );
+ Id = 0;
+ }
+ }
+ }
+}
diff --git a/Facepunch.Steamworks/Interfaces/Workshop.Query.cs b/Facepunch.Steamworks/Interfaces/Workshop.Query.cs
new file mode 100644
index 0000000..dd453a2
--- /dev/null
+++ b/Facepunch.Steamworks/Interfaces/Workshop.Query.cs
@@ -0,0 +1,150 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using Facepunch.Steamworks.Callbacks.Networking;
+using Facepunch.Steamworks.Callbacks.Workshop;
+using Facepunch.Steamworks.Interop;
+using Valve.Steamworks;
+
+namespace Facepunch.Steamworks
+{
+ public partial class Workshop
+ {
+ public class Query : IDisposable
+ {
+ internal ulong Handle;
+ internal QueryCompleted Callback;
+
+ ///
+ /// The AppId you're querying. This defaults to this appid.
+ ///
+ public uint AppId { get; set; }
+
+ ///
+ /// The AppId of the app used to upload the item. This defaults to 0
+ /// which means all/any.
+ ///
+ public uint UploaderAppId { get; set; }
+
+ public QueryType QueryType { get; set; } = QueryType.Items;
+ public Order Order { get; set; } = Order.RankedByVote;
+
+ public string SearchText { get; set; }
+
+ public Item[] Items { get; set; }
+
+ public int TotalResults { get; set; }
+
+ ///
+ /// Page starts at 1 !!
+ ///
+ public int Page { get; set; } = 1;
+ internal Workshop workshop;
+
+ public unsafe void Run()
+ {
+ if ( Callback != null )
+ return;
+
+ if ( Page <= 0 )
+ throw new System.Exception( "Page should be 1 or above" );
+
+ if ( FileId.Count != 0 )
+ {
+ var fileArray = FileId.ToArray();
+
+ fixed ( ulong* array = fileArray )
+ {
+ Handle = workshop.ugc.CreateQueryUGCDetailsRequest( (IntPtr)array, (uint)fileArray.Length );
+ }
+ }
+ else
+ {
+ Handle = workshop.ugc.CreateQueryAllUGCRequest( (uint)Order, (uint)QueryType, UploaderAppId, AppId, (uint)Page );
+ }
+
+ if ( !string.IsNullOrEmpty( SearchText ) )
+ workshop.ugc.SetSearchText( Handle, SearchText );
+
+ foreach ( var tag in RequireTags )
+ workshop.ugc.AddRequiredTag( Handle, tag );
+
+ if ( RequireTags.Count > 0 )
+ workshop.ugc.SetMatchAnyTag( Handle, RequireAllTags );
+
+ foreach ( var tag in ExcludeTags )
+ workshop.ugc.AddExcludedTag( Handle, tag );
+
+ Callback = new QueryCompleted();
+ Callback.Handle = workshop.ugc.SendQueryUGCRequest( Handle );
+ Callback.OnResult = OnResult;
+ workshop.steamworks.AddCallResult( Callback );
+ }
+
+ void OnResult( QueryCompleted.Data data )
+ {
+ Items = new Item[data.m_unNumResultsReturned];
+ for ( int i = 0; i < data.m_unNumResultsReturned; i++ )
+ {
+ SteamUGCDetails_t details = new SteamUGCDetails_t();
+ workshop.ugc.GetQueryUGCResult( data.Handle, (uint)i, ref details );
+
+ Items[i] = Item.From( details, workshop );
+ }
+
+ TotalResults = (int)data.m_unTotalMatchingResults;
+
+ Callback.Dispose();
+ Callback = null;
+ }
+
+ public bool IsRunning
+ {
+ get { return Callback != null; }
+ }
+
+ ///
+ /// Only return items with these tags
+ ///
+ public List RequireTags { get; set; } = new List();
+
+ ///
+ /// If true, return items that have all RequireTags
+ /// If false, return items that have any tags in RequireTags
+ ///
+ public bool RequireAllTags { get; set; } = false;
+
+ ///
+ /// Don't return any items with this tag
+ ///
+ public List ExcludeTags { get; set; } = new List();
+
+ ///
+ /// If you're querying for a particular file or files, add them to this.
+ ///
+ public List FileId { get; set; } = new List();
+
+ ///
+ /// Don't call this in production!
+ ///
+ public void Block()
+ {
+ workshop.steamworks.Update();
+
+ while ( IsRunning )
+ {
+ System.Threading.Thread.Sleep( 10 );
+ workshop.steamworks.Update();
+ }
+ }
+
+ public void Dispose()
+ {
+ // ReleaseQueryUGCRequest
+ }
+ }
+ }
+}
diff --git a/Facepunch.Steamworks/Interfaces/Workshop.cs b/Facepunch.Steamworks/Interfaces/Workshop.cs
index 8d241c9..4f2e8f9 100644
--- a/Facepunch.Steamworks/Interfaces/Workshop.cs
+++ b/Facepunch.Steamworks/Interfaces/Workshop.cs
@@ -1,11 +1,6 @@
using System;
using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
using Facepunch.Steamworks.Callbacks.Workshop;
-using Facepunch.Steamworks.Interop;
using Valve.Steamworks;
namespace Facepunch.Steamworks
@@ -16,35 +11,47 @@ public partial class Workshop
internal ISteamUGC ugc;
internal BaseSteamworks steamworks;
+ internal ISteamRemoteStorage remoteStorage;
internal event Action OnFileDownloaded;
internal event Action OnItemInstalled;
- internal Workshop( BaseSteamworks sw, ISteamUGC ugc )
+ internal Workshop( BaseSteamworks steamworks, ISteamUGC ugc, ISteamRemoteStorage remoteStorage )
{
this.ugc = ugc;
- this.steamworks = sw;
+ this.steamworks = steamworks;
+ this.remoteStorage = remoteStorage;
- sw.AddCallback( onDownloadResult, DownloadResult.CallbackId );
- sw.AddCallback( onItemInstalled, ItemInstalled.CallbackId );
+ steamworks.AddCallback( onDownloadResult, DownloadResult.CallbackId );
+ steamworks.AddCallback( onItemInstalled, ItemInstalled.CallbackId );
}
private void onItemInstalled( ItemInstalled obj )
{
- Console.WriteLine( "OnItemInstalled" );
-
if ( OnItemInstalled != null )
OnItemInstalled( obj.FileId );
}
private void onDownloadResult( DownloadResult obj )
{
- Console.WriteLine( "onDownloadResult" );
-
if ( OnFileDownloaded != null )
OnFileDownloaded( obj.FileId, obj.Result );
}
+ public Query CreateQuery()
+ {
+ return new Query()
+ {
+ AppId = steamworks.AppId,
+ workshop = this
+ };
+ }
+
+ public Editor CreateItem( ItemType type )
+ {
+ return new Editor() { workshop = this, Type = type };
+ }
+
public enum Order
{
RankedByVote = 0,
@@ -64,9 +71,18 @@ public enum Order
public enum QueryType
{
- Items = 0, // both mtx items and ready-to-use items
- Items_Mtx = 1,
- Items_ReadyToUse = 2,
+ ///
+ /// Both MicrotransactionItems and subscriptionItems
+ ///
+ Items = 0,
+ ///
+ /// Workshop item that is meant to be voted on for the purpose of selling in-game
+ ///
+ MicrotransactionItems = 1,
+ ///
+ /// normal Workshop item that can be subscribed to
+ ///
+ subscriptionItems = 2,
Collections = 3,
Artwork = 4,
Videos = 5,
@@ -79,146 +95,27 @@ public enum QueryType
GameManagedItems = 12, // game managed items (not managed by users)
};
- public WorkshopQuery CreateQuery()
+ public enum ItemType
{
- var q = new WorkshopQuery();
- q.AppId = steamworks.AppId;
- q.workshop = this;
- return q;
- }
+ Community = 0, // normal Workshop item that can be subscribed to
+ Microtransaction = 1, // Workshop item that is meant to be voted on for the purpose of selling in-game
+ Collection = 2, // a collection of Workshop or Greenlight items
+ Art = 3, // artwork
+ Video = 4, // external video
+ Screenshot = 5, // screenshot
+ Game = 6, // Greenlight game entry
+ Software = 7, // Greenlight software entry
+ Concept = 8, // Greenlight concept
+ WebGuide = 9, // Steam web guide
+ IntegratedGuide = 10, // application integrated guide
+ Merch = 11, // Workshop merchandise meant to be voted on for the purpose of being sold
+ ControllerBinding = 12, // Steam Controller bindings
+ SteamworksAccessInvite = 13, // internal
+ SteamVideo = 14, // Steam video
+ GameManagedItem = 15, // managed completely by the game, not the user, and not shown on the web
+ };
- public class WorkshopQuery : IDisposable
- {
- internal ulong Handle;
- internal QueryCompleted Callback;
- ///
- /// The AppId you're querying. This defaults to this appid.
- ///
- public uint AppId { get; set; }
- ///
- /// The AppId of the app used to upload the item. This defaults to 0
- /// which means all/any.
- ///
- public uint UploaderAppId { get; set; }
-
- public QueryType QueryType { get; set; } = QueryType.Items;
- public Order Order { get; set; } = Order.RankedByVote;
-
- public string SearchText { get; set; }
-
- public Item[] Items { get; set; }
-
- public int TotalResults { get; set; }
-
- ///
- /// Page starts at 1 !!
- ///
- public int Page { get; set; } = 1;
- internal Workshop workshop;
-
- public unsafe void Run()
- {
- if ( Callback != null )
- return;
-
- if ( Page <= 0 )
- throw new System.Exception( "Page should be 1 or above" );
-
- if ( FileId.Count != 0 )
- {
- var fileArray = FileId.ToArray();
-
- fixed ( ulong* array = fileArray )
- {
- Handle = workshop.ugc.CreateQueryUGCDetailsRequest( (IntPtr) array, (uint)fileArray.Length );
- }
- }
- else
- {
- Handle = workshop.ugc.CreateQueryAllUGCRequest( (uint)Order, (uint)QueryType, UploaderAppId, AppId, (uint)Page );
- }
-
- if ( !string.IsNullOrEmpty( SearchText ) )
- workshop.ugc.SetSearchText( Handle, SearchText );
-
- foreach ( var tag in RequireTags )
- workshop.ugc.AddRequiredTag( Handle, tag );
-
- if ( RequireTags.Count > 0 )
- workshop.ugc.SetMatchAnyTag( Handle, RequireAllTags );
-
- foreach ( var tag in ExcludeTags )
- workshop.ugc.AddExcludedTag( Handle, tag );
-
- Callback = new QueryCompleted();
- Callback.Handle = workshop.ugc.SendQueryUGCRequest( Handle );
- Callback.OnResult = OnResult;
- workshop.steamworks.AddCallResult( Callback );
- }
-
- void OnResult( QueryCompleted.Data data )
- {
- Items = new Item[data.m_unNumResultsReturned];
- for ( int i = 0; i < data.m_unNumResultsReturned; i++ )
- {
- SteamUGCDetails_t details = new SteamUGCDetails_t();
- workshop.ugc.GetQueryUGCResult( data.Handle, (uint) i, ref details );
-
- Items[i] = Item.From( details, workshop );
- }
-
- TotalResults = (int) data.m_unTotalMatchingResults;
-
- Callback.Dispose();
- Callback = null;
- }
-
- public bool IsRunning
- {
- get { return Callback != null; }
- }
-
- ///
- /// Only return items with these tags
- ///
- public List RequireTags { get; set; } = new List();
-
- ///
- /// If true, return items that have all RequireTags
- /// If false, return items that have any tags in RequireTags
- ///
- public bool RequireAllTags { get; set; } = false;
-
- ///
- /// Don't return any items with this tag
- ///
- public List ExcludeTags { get; set; } = new List();
-
- ///
- /// If you're querying for a particular file or files, add them to this.
- ///
- public List FileId { get; set; } = new List();
-
- ///
- /// Don't call this in production!
- ///
- public void Block()
- {
- workshop.steamworks.Update();
-
- while ( IsRunning )
- {
- System.Threading.Thread.Sleep( 10 );
- workshop.steamworks.Update();
- }
- }
-
- public void Dispose()
- {
- // ReleaseQueryUGCRequest
- }
- }
}
}
diff --git a/Facepunch.Steamworks/Interop/Native.cs b/Facepunch.Steamworks/Interop/Native.cs
index b0196d4..ba67aa2 100644
--- a/Facepunch.Steamworks/Interop/Native.cs
+++ b/Facepunch.Steamworks/Interop/Native.cs
@@ -21,6 +21,7 @@ internal class NativeInterface : IDisposable
internal Valve.Steamworks.ISteamUGC ugc;
internal Valve.Steamworks.ISteamGameServer gameServer;
internal Valve.Steamworks.ISteamGameServerStats gameServerStats;
+ internal Valve.Steamworks.ISteamRemoteStorage remoteStorage;
internal bool InitClient()
{
@@ -75,6 +76,7 @@ public void FillInterfaces( int hpipe, int huser )
servers = client.GetISteamMatchmakingServers( huser, hpipe, "SteamMatchMakingServers002" );
userstats = client.GetISteamUserStats( huser, hpipe, "STEAMUSERSTATS_INTERFACE_VERSION011" );
screenshots = client.GetISteamScreenshots( huser, hpipe, "STEAMSCREENSHOTS_INTERFACE_VERSION002" );
+ remoteStorage = client.GetISteamRemoteStorage( huser, hpipe, "STEAMREMOTESTORAGE_INTERFACE_VERSION013" );
}
public void Dispose()
diff --git a/Facepunch.Steamworks/Interop/steam_api_interop.cs b/Facepunch.Steamworks/Interop/steam_api_interop.cs
index f1effb0..7f6de1e 100644
--- a/Facepunch.Steamworks/Interop/steam_api_interop.cs
+++ b/Facepunch.Steamworks/Interop/steam_api_interop.cs
@@ -2513,7 +2513,7 @@ internal override ISteamRemoteStorage GetISteamRemoteStorage( int hSteamUser, in
{
CheckIfUsable();
IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamRemoteStorage(m_pSteamClient,hSteamUser,hSteamPipe,pchVersion);
- return (ISteamRemoteStorage)Marshal.PtrToStructure( result, typeof( ISteamRemoteStorage ) );
+ return new CSteamRemoteStorage( result );
}
internal override ISteamScreenshots GetISteamScreenshots( int hSteamUser, int hSteamPipe, string pchVersion )
{