diff --git a/Facepunch.Steamworks.Test/Client/Inventory.cs b/Facepunch.Steamworks.Test/Client/Inventory.cs index d9c65c2..b076046 100644 --- a/Facepunch.Steamworks.Test/Client/Inventory.cs +++ b/Facepunch.Steamworks.Test/Client/Inventory.cs @@ -113,5 +113,46 @@ namespace Facepunch.Steamworks.Test } } } + + [TestMethod] + public void Deserialize() + { + using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) + { + Assert.IsTrue( client.IsValid ); + + client.Inventory.Refresh(); + + // + // Block until we have the items + // + while ( client.Inventory.SerializedItems == null ) + { + client.Update(); + } + + Assert.IsNotNull( client.Inventory.SerializedItems ); + Assert.IsTrue( client.Inventory.SerializedItems.Length > 4 ); + + using ( var server = new Facepunch.Steamworks.Server( 252490, 0, 30002, true, "VersionString" ) ) + { + server.LogOnAnonymous(); + Assert.IsTrue( server.IsValid ); + + var result = server.Inventory.Deserialize( client.Inventory.SerializedItems ); + + server.UpdateWhile( () => result.IsPending ); + + Assert.IsFalse( result.IsPending ); + Assert.IsNotNull( result.Items ); + + foreach ( var item in result.Items ) + { + Console.WriteLine( "Item: {0} ({1})", item.Id, item.DefinitionId ); + Console.WriteLine( "Item: {0} ({1})", item.Id, item.DefinitionId ); + } + } + } + } } } diff --git a/Facepunch.Steamworks.Test/Facepunch.Steamworks.Test.csproj b/Facepunch.Steamworks.Test/Facepunch.Steamworks.Test.csproj index 250379b..f38be94 100644 --- a/Facepunch.Steamworks.Test/Facepunch.Steamworks.Test.csproj +++ b/Facepunch.Steamworks.Test/Facepunch.Steamworks.Test.csproj @@ -99,7 +99,6 @@ - diff --git a/Facepunch.Steamworks.Test/Server/Inventory.cs b/Facepunch.Steamworks.Test/Server/Inventory.cs deleted file mode 100644 index 9d8445c..0000000 --- a/Facepunch.Steamworks.Test/Server/Inventory.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Text; -using System.Threading; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System.Linq; - -namespace Facepunch.Steamworks.Test -{ - public partial class Server - { - [TestMethod] - public void InventoryDeserialize() - { - using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) - { - Assert.IsTrue( client.IsValid ); - - Assert.IsNull( client.Inventory.SerializedItems ); - - client.Inventory.Refresh(); - - // - // Block until we have the items - // - while ( client.Inventory.SerializedItems == null ) - { - client.Update(); - } - - Assert.IsNotNull( client.Inventory.SerializedItems ); - Assert.IsTrue( client.Inventory.SerializedItems.Length > 4 ); - - using ( var server = new Facepunch.Steamworks.Server( 252490, 0, 30002, true, "VersionString" ) ) - { - server.LogOnAnonymous(); - Assert.IsTrue( server.IsValid ); - - var result = server.Inventory.Deserialize( client.Inventory.SerializedItems ); - - Assert.IsTrue( result.Block() ); - Assert.IsNotNull( result.Items ); - - foreach ( var item in result.Items ) - { - Console.WriteLine( "Item: {0} ({1})", item.Id, item.DefinitionId ); - Console.WriteLine( "Item: {0} ({1})", item.Id, item.DefinitionId ); - } - } - } - } - - } -} diff --git a/Facepunch.Steamworks/Interfaces/Inventory.Result.cs b/Facepunch.Steamworks/Interfaces/Inventory.Result.cs index fce45fc..2931297 100644 --- a/Facepunch.Steamworks/Interfaces/Inventory.Result.cs +++ b/Facepunch.Steamworks/Interfaces/Inventory.Result.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; +using SteamNative; namespace Facepunch.Steamworks { @@ -10,27 +11,37 @@ namespace Facepunch.Steamworks { public class Result : IDisposable { + internal static Dictionary< int, Result > Pending; internal Inventory inventory; private SteamNative.SteamInventoryResult_t Handle { get; set; } + + /// + /// Called when result is successfully returned + /// + public Action OnResult; + + /// + /// Items that exist, or that have been created, or changed + /// public Item[] Items { get; internal set; } + /// + /// Items that have been removed or somehow destroyed + /// public Item[] Removed { get; internal set; } + /// + /// Items that have been consumed, like in a craft or something + /// public Item[] Consumed { get; internal set; } - public bool IsPending - { - get - { - if ( Items != null ) return false; - if ( Handle == -1 ) return false; - if ( Status() == Callbacks.Result.Pending ) return true; + /// + /// Returns true if this result is still pending + /// + public bool IsPending { get; internal set; } - TryFill(); - return false; - } - } + internal uint Timestamp { get; private set; } internal bool IsSuccess { @@ -42,40 +53,29 @@ namespace Facepunch.Steamworks } } - internal uint Timestamp { get; private set; } - internal Callbacks.Result Status() { if ( Handle == -1 ) return Callbacks.Result.InvalidParam; return (Callbacks.Result)inventory.inventory.GetResultStatus( Handle ); } - - internal Result( Inventory inventory, int Handle ) + internal Result( Inventory inventory, int Handle, bool pending ) { - this.Handle = Handle; - this.inventory = inventory; - - TryFill(); - } - - public bool Block( float maxWait = 5.0f ) - { - while ( IsPending ) + if ( pending ) { - System.Threading.Thread.Sleep( 5 ); + Pending.Add( Handle, this ); } - return IsSuccess; + this.Handle = Handle; + this.inventory = inventory; } - internal void TryFill() + internal void Fill() { if ( Items != null ) return; - if ( !IsSuccess ) - return; + this.IsPending = false; Timestamp = inventory.inventory.GetResultTimestamp( Handle ); @@ -127,7 +127,20 @@ namespace Facepunch.Steamworks }; } ).ToArray(); - inventory.ApplyResult( this ); + if ( OnResult != null ) + { + OnResult( this ); + } + } + + internal void OnSteamResult( SteamInventoryResultReady_t data, bool error ) + { + var success = data.Esult == SteamNative.Result.OK && !error; + + if ( success ) + { + Fill(); + } } internal unsafe byte[] Serialize() diff --git a/Facepunch.Steamworks/Interfaces/Inventory.cs b/Facepunch.Steamworks/Interfaces/Inventory.cs index 43c7593..ef643c3 100644 --- a/Facepunch.Steamworks/Interfaces/Inventory.cs +++ b/Facepunch.Steamworks/Interfaces/Inventory.cs @@ -43,48 +43,76 @@ namespace Facepunch.Steamworks IsServer = server; inventory = c; + Result.Pending = new Dictionary(); + inventory.LoadItemDefinitions(); FetchItemDefinitions(); if ( !server ) { - // SteamNative.SteamInventoryResultReady_t.RegisterCallback( steamworks, onResultReady ); + SteamNative.SteamInventoryResultReady_t.RegisterCallback( steamworks, onResultReady ); SteamNative.SteamInventoryFullUpdate_t.RegisterCallback( steamworks, onFullUpdate ); + + // + // Get a list of our items immediately + // Refresh(); } } + /// + /// We've received a FULL update + /// private void onFullUpdate( SteamInventoryFullUpdate_t data, bool error ) { if ( error ) return; - onResult( data.Handle, true ); + var result = new Result( this, data.Handle, false ); + result.Fill(); + + onResult( result, true ); } + /// + /// A generic result has returned. + /// private void onResultReady( SteamInventoryResultReady_t data, bool error ) { - if ( error ) return; - if ( data.Esult != SteamNative.Result.OK ) return; + if ( Result.Pending.ContainsKey( data.Handle ) ) + { + var result = Result.Pending[data.Handle]; - onResult( data.Handle, false ); + result.OnSteamResult( data, error ); + + if ( !error && data.Esult == SteamNative.Result.OK ) + { + onResult( result, false ); + } + + Result.Pending.Remove( data.Handle ); + } } - private void onResult( int Handle, bool serialize ) + private void onResult( Result r, bool serialize ) { - var r = new Result( this, Handle ); if ( r.IsSuccess ) { + // + // We only serialize FULL updates + // if ( serialize ) { + // + // Only serialize if this result is newer than the last one + // if ( r.Timestamp < LastTimestamp ) return; - LastTimestamp = r.Timestamp; - SerializedItems = r.Serialize(); SerializedExpireTime = DateTime.Now.Add( TimeSpan.FromMinutes( 60 ) ); } + LastTimestamp = r.Timestamp; ApplyResult( r ); } @@ -92,6 +120,11 @@ namespace Facepunch.Steamworks r = null; } + /// + /// Apply this result to our current stack of Items + /// Here we're trying to keep our stack up to date with whatever happens + /// with the crafting, stacking etc + /// internal void ApplyResult( Result r ) { if ( IsServer ) return; @@ -121,6 +154,8 @@ namespace Facepunch.Steamworks Items = null; SerializedItems = null; + + Result.Pending = null; } /// @@ -170,11 +205,7 @@ namespace Facepunch.Steamworks if ( ids == null ) return; - Definitions = ids.Select( x => - { - return CreateDefinition( x ); - - } ).ToArray(); + Definitions = ids.Select( x => CreateDefinition( x ) ).ToArray(); foreach ( var def in Definitions ) { @@ -241,7 +272,9 @@ namespace Facepunch.Steamworks if ( !result || resultHandle == -1 ) return null; - return new Result( this, resultHandle ); + var r = new Result( this, resultHandle, false ); + r.Fill(); + return r; } } @@ -263,7 +296,7 @@ namespace Facepunch.Steamworks if ( !inventory.ExchangeItems( ref resultHandle, newItems, newItemC, 1, takeItems, takeItemsC, (uint)takeItems.Length ) ) return null; - return new Result( this, resultHandle ); + return new Result( this, resultHandle, true ); } /// @@ -275,7 +308,7 @@ namespace Facepunch.Steamworks if ( !inventory.TransferItemQuantity( ref resultHandle, item.Id, (uint)quantity, ulong.MaxValue ) ) return null; - return new Result( this, resultHandle ); + return new Result( this, resultHandle, true ); } /// @@ -287,7 +320,7 @@ namespace Facepunch.Steamworks if ( !inventory.TransferItemQuantity( ref resultHandle, source.Id, (uint)quantity, dest.Id ) ) return null; - return new Result( this, resultHandle ); + return new Result( this, resultHandle, true ); } } }