using System; using System.Collections.Generic; using System.Threading.Tasks; using Facepunch.Steamworks.Data; namespace Facepunch.Steamworks { public struct InventoryItem : IEquatable { internal InventoryItemId _id; internal InventoryDefId _def; internal SteamItemFlags _flags; internal ushort _quantity; internal Dictionary _properties; public InventoryItemId Id => _id; public InventoryDefId DefId => _def; public int Quantity => _quantity; public InventoryDef Def => SteamInventory.FindDefinition( DefId ); /// /// Only available if the result set was created with the getproperties /// public Dictionary Properties => _properties; /// /// This item is account-locked and cannot be traded or given away. /// This is an item status flag which is permanently attached to specific item instances /// public bool IsNoTrade => _flags.HasFlag( SteamItemFlags.NoTrade ); /// /// The item has been destroyed, traded away, expired, or otherwise invalidated. /// This is an action confirmation flag which is only set one time, as part of a result set. /// public bool IsRemoved => _flags.HasFlag( SteamItemFlags.Removed ); /// /// The item quantity has been decreased by 1 via ConsumeItem API. /// This is an action confirmation flag which is only set one time, as part of a result set. /// public bool IsConsumed => _flags.HasFlag( SteamItemFlags.Consumed ); /// /// Consumes items from a user's inventory. If the quantity of the given item goes to zero, it is permanently removed. /// Once an item is removed it cannot be recovered.This is not for the faint of heart - if your game implements item removal at all, /// a high-friction UI confirmation process is highly recommended.ConsumeItem can be restricted to certain item definitions or fully /// blocked via the Steamworks website to minimize support/abuse issues such as the classic "my brother borrowed my laptop and deleted all of my rare items". /// public async Task ConsumeAsync( int amount = 1 ) { var sresult = Defines.k_SteamInventoryResultInvalid; if ( !SteamInventory.Internal.ConsumeItem( ref sresult, Id, (uint)amount ) ) return null; return await InventoryResult.GetAsync( sresult ); } /// /// Split stack into two items /// public async Task SplitStackAsync( int quantity = 1 ) { var sresult = Defines.k_SteamInventoryResultInvalid; if ( !SteamInventory.Internal.TransferItemQuantity( ref sresult, Id, (uint)quantity, ulong.MaxValue ) ) return null; return await InventoryResult.GetAsync( sresult ); } /// /// Add x units of the target item to this item /// public async Task AddAsync( InventoryItem add, int quantity = 1 ) { var sresult = Defines.k_SteamInventoryResultInvalid; if ( !SteamInventory.Internal.TransferItemQuantity( ref sresult, add.Id, (uint)quantity, Id ) ) return null; return await InventoryResult.GetAsync( sresult ); } internal static InventoryItem From( SteamItemDetails_t details ) { var i = new InventoryItem { _id = details.ItemId, _def = details.Definition, _flags = (SteamItemFlags) details.Flags, _quantity = details.Quantity }; return i; } internal static Dictionary GetProperties( SteamInventoryResult_t result, int index ) { var strlen = (uint) Helpers.MemoryBufferSize; if ( !SteamInventory.Internal.GetResultItemProperty( result, (uint)index, null, out var propNames, ref strlen ) ) return null; var props = new Dictionary(); foreach ( var propertyName in propNames.Split( ',' ) ) { strlen = (uint)Helpers.MemoryBufferSize; if ( SteamInventory.Internal.GetResultItemProperty( result, (uint)index, propertyName, out var strVal, ref strlen ) ) { props.Add( propertyName, strVal ); } } return props; } /// /// Will try to return the date that this item was aquired. You need to have for the items /// with their properties for this to work. /// public DateTime Acquired { get { if ( Properties == null ) return DateTime.UtcNow; if ( Properties.TryGetValue( "acquired", out var str ) ) { var y = int.Parse( str.Substring( 0, 4 ) ); var m = int.Parse( str.Substring( 4, 2 ) ); var d = int.Parse( str.Substring( 6, 2 ) ); var h = int.Parse( str.Substring( 9, 2 ) ); var mn = int.Parse( str.Substring( 11, 2 ) ); var s = int.Parse( str.Substring( 13, 2 ) ); return new DateTime( y, m, d, h, mn, s, DateTimeKind.Utc ); } return DateTime.UtcNow; } } /// /// Tries to get the origin property. Need properties for this to work. /// Will return a string like "market" /// public string Origin { get { if ( Properties == null ) return null; if ( Properties.TryGetValue( "origin", out var str ) ) return str; return null; } } /// /// Small utility class to describe an item with a quantity /// public struct Amount { public InventoryItem Item; public int Quantity; } public static bool operator ==( InventoryItem a, InventoryItem b ) => a._id == b._id; public static bool operator !=( InventoryItem a, InventoryItem b ) => a._id != b._id; public override bool Equals( object p ) => this.Equals( (InventoryItem)p ); public override int GetHashCode() => _id.GetHashCode(); public bool Equals( InventoryItem p ) => p._id == _id; } }