(965c31410a) Unstable v0.10.4.0
This commit is contained in:
@@ -75,12 +75,12 @@ namespace Steamworks.Data
|
||||
var ident = Identifier;
|
||||
bool gotCallback = false;
|
||||
|
||||
Action<string, int> f = ( x, icon ) =>
|
||||
void f( string x, int icon )
|
||||
{
|
||||
if ( x != ident ) return;
|
||||
i = icon;
|
||||
gotCallback = true;
|
||||
};
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Steamworks
|
||||
{
|
||||
public struct Clan
|
||||
{
|
||||
public SteamId Id;
|
||||
|
||||
public Clan(SteamId id)
|
||||
{
|
||||
Id = id;
|
||||
}
|
||||
|
||||
public string Name => SteamFriends.Internal.GetClanName(Id);
|
||||
|
||||
public string Tag => SteamFriends.Internal.GetClanTag(Id);
|
||||
|
||||
public int ChatMemberCount => SteamFriends.Internal.GetClanChatMemberCount(Id);
|
||||
|
||||
public Friend Owner => new Friend(SteamFriends.Internal.GetClanOwner(Id));
|
||||
|
||||
public bool Public => SteamFriends.Internal.IsClanPublic(Id);
|
||||
|
||||
/// <summary>
|
||||
/// Is the clan an official game group?
|
||||
/// </summary>
|
||||
public bool Official => SteamFriends.Internal.IsClanOfficialGameGroup(Id);
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously fetches the officer list for a given clan
|
||||
/// </summary>
|
||||
/// <returns>Whether the request was successful or not</returns>
|
||||
public async Task<bool> RequestOfficerList()
|
||||
{
|
||||
var req = await SteamFriends.Internal.RequestClanOfficerList(Id);
|
||||
return req.HasValue && req.Value.Success != 0x0;
|
||||
}
|
||||
|
||||
public IEnumerable<Friend> GetOfficers()
|
||||
{
|
||||
for (int i = 0; i < SteamFriends.Internal.GetClanOfficerCount(Id); i++)
|
||||
{
|
||||
yield return new Friend(SteamFriends.Internal.GetClanOfficerByIndex(Id, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Steamworks.Data
|
||||
{
|
||||
public struct Connection
|
||||
{
|
||||
internal uint Id;
|
||||
|
||||
public override string ToString() => Id.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Accept an incoming connection that has been received on a listen socket.
|
||||
/// </summary>
|
||||
public Result Accept()
|
||||
{
|
||||
return SteamNetworkingSockets.Internal.AcceptConnection( this );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disconnects from the remote host and invalidates the connection handle. Any unread data on the connection is discarded..
|
||||
/// reasonCode is defined and used by you.
|
||||
/// </summary>
|
||||
public bool Close( bool linger = false, int reasonCode = 0, string debugString = "Closing Connection" )
|
||||
{
|
||||
return SteamNetworkingSockets.Internal.CloseConnection( this, reasonCode, debugString, linger );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set connection user data
|
||||
/// </summary>
|
||||
public long UserData
|
||||
{
|
||||
get => SteamNetworkingSockets.Internal.GetConnectionUserData( this );
|
||||
set => SteamNetworkingSockets.Internal.SetConnectionUserData( this, value );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A name for the connection, used mostly for debugging
|
||||
/// </summary>
|
||||
public string ConnectionName
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( !SteamNetworkingSockets.Internal.GetConnectionName( this, out var strVal ) )
|
||||
return "ERROR";
|
||||
|
||||
return strVal;
|
||||
}
|
||||
|
||||
set => SteamNetworkingSockets.Internal.SetConnectionName( this, value );
|
||||
}
|
||||
|
||||
|
||||
public Result SendMessage( IntPtr ptr, int size, SendType sendType = SendType.Reliable )
|
||||
{
|
||||
return SteamNetworkingSockets.Internal.SendMessageToConnection( this, ptr, (uint) size, (int)sendType );
|
||||
}
|
||||
|
||||
public unsafe Result SendMessage( byte[] data, SendType sendType = SendType.Reliable )
|
||||
{
|
||||
fixed ( byte* ptr = data )
|
||||
{
|
||||
return SendMessage( (IntPtr)ptr, data.Length, sendType );
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe Result SendMessage( byte[] data, int offset, int length, SendType sendType = SendType.Reliable )
|
||||
{
|
||||
fixed ( byte* ptr = data )
|
||||
{
|
||||
return SendMessage( (IntPtr)ptr + offset, length, sendType );
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe Result SendMessage( string str, SendType sendType = SendType.Reliable )
|
||||
{
|
||||
var bytes = System.Text.Encoding.UTF8.GetBytes( str );
|
||||
return SendMessage( bytes, sendType );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flush any messages waiting on the Nagle timer and send them at the next transmission opportunity (often that means right now).
|
||||
/// </summary>
|
||||
public Result Flush() => SteamNetworkingSockets.Internal.FlushMessagesOnConnection( this );
|
||||
|
||||
public string DetailedStatus()
|
||||
{
|
||||
if ( SteamNetworkingSockets.Internal.GetDetailedConnectionStatus( this, out var strVal ) != 0 )
|
||||
return null;
|
||||
|
||||
return strVal;
|
||||
}
|
||||
|
||||
/*
|
||||
[ThreadStatic]
|
||||
private static SteamNetworkingMessage_t[] messageBuffer;
|
||||
|
||||
public IEnumerable<SteamNetworkingMessage_t> Messages
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( messageBuffer == null )
|
||||
messageBuffer = new SteamNetworkingMessage_t[128];
|
||||
|
||||
var num = SteamNetworkingSockets.Internal.ReceiveMessagesOnConnection( this, ref messageBuffer, messageBuffer.Length );
|
||||
|
||||
for ( int i = 0; i < num; i++)
|
||||
{
|
||||
yield return messageBuffer[i];
|
||||
messageBuffer[i].Release();
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Steamworks.Data
|
||||
{
|
||||
[StructLayout( LayoutKind.Sequential, Size = 696 )]
|
||||
public struct ConnectionInfo
|
||||
{
|
||||
internal NetIdentity identity;
|
||||
internal long userData;
|
||||
internal Socket listenSocket;
|
||||
internal NetAddress address;
|
||||
internal ushort pad;
|
||||
internal SteamNetworkingPOPID popRemote;
|
||||
internal SteamNetworkingPOPID popRelay;
|
||||
internal ConnectionState state;
|
||||
internal int endReason;
|
||||
[MarshalAs( UnmanagedType.ByValTStr, SizeConst = 128 )]
|
||||
internal string endDebug;
|
||||
[MarshalAs( UnmanagedType.ByValTStr, SizeConst = 128 )]
|
||||
internal string connectionDescription;
|
||||
|
||||
public ConnectionState State => state;
|
||||
public SteamId SteamId => identity.steamID;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Steamworks.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Sent for games with enabled anti indulgence / duration control, for enabled users.
|
||||
/// Lets the game know whether persistent rewards or XP should be granted at normal rate, half rate, or zero rate.
|
||||
/// </summary>
|
||||
public struct DurationControl
|
||||
{
|
||||
internal DurationControl_t _inner;
|
||||
|
||||
/// <summary>
|
||||
/// appid generating playtime
|
||||
/// </summary>
|
||||
public AppId Appid => _inner.Appid;
|
||||
|
||||
/// <summary>
|
||||
/// is duration control applicable to user + game combination
|
||||
/// </summary>
|
||||
public bool Applicable => _inner.Applicable;
|
||||
|
||||
/// <summary>
|
||||
/// playtime since most recent 5 hour gap in playtime, only counting up to regulatory limit of playtime, in seconds
|
||||
/// </summary>
|
||||
internal TimeSpan PlaytimeInLastFiveHours => TimeSpan.FromSeconds( _inner.CsecsLast5h );
|
||||
|
||||
/// <summary>
|
||||
/// playtime on current calendar day
|
||||
/// </summary>
|
||||
internal TimeSpan PlaytimeToday => TimeSpan.FromSeconds( _inner.CsecsLast5h );
|
||||
|
||||
/// <summary>
|
||||
/// recommended progress
|
||||
/// </summary>
|
||||
internal DurationControlProgress Progress => _inner.Progress;
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ namespace Steamworks
|
||||
/// Sometimes we don't know the user's name. This will wait until we have
|
||||
/// downloaded the information on this user.
|
||||
/// </summary>
|
||||
public async Task RequestInfoAsync( int timeout = 5000 )
|
||||
public async Task RequestInfoAsync()
|
||||
{
|
||||
await SteamFriends.CacheUserInformationAsync( Id, true );
|
||||
}
|
||||
@@ -99,7 +99,7 @@ namespace Steamworks
|
||||
{
|
||||
get
|
||||
{
|
||||
FriendGameInfo_t gameInfo = default( FriendGameInfo_t );
|
||||
FriendGameInfo_t gameInfo = default;
|
||||
if ( !SteamFriends.Internal.GetFriendGamePlayed( Id, ref gameInfo ) )
|
||||
return null;
|
||||
|
||||
@@ -184,5 +184,80 @@ namespace Steamworks
|
||||
return SteamFriends.Internal.ReplyToFriendMessage( Id, message );
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get download the latest user stats
|
||||
/// </summary>
|
||||
/// <returns>True if successful, False if failure</returns>
|
||||
public async Task<bool> RequestUserStatsAsync()
|
||||
{
|
||||
var result = await SteamUserStats.Internal.RequestUserStats( Id );
|
||||
return result.HasValue && result.Value.Result == Result.OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a user stat. Must call RequestUserStats first.
|
||||
/// </summary>
|
||||
/// <param name="statName">The name of the stat you want to get</param>
|
||||
/// <param name="defult">Will return this value if not available</param>
|
||||
/// <returns>The value, or defult if not available</returns>
|
||||
public float GetStatFloat( string statName, float defult = 0 )
|
||||
{
|
||||
var val = defult;
|
||||
|
||||
if ( !SteamUserStats.Internal.GetUserStat( Id, statName, ref val ) )
|
||||
return defult;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a user stat. Must call RequestUserStats first.
|
||||
/// </summary>
|
||||
/// <param name="statName">The name of the stat you want to get</param>
|
||||
/// <param name="defult">Will return this value if not available</param>
|
||||
/// <returns>The value, or defult if not available</returns>
|
||||
public int GetStatInt( string statName, int defult = 0 )
|
||||
{
|
||||
var val = defult;
|
||||
|
||||
if ( !SteamUserStats.Internal.GetUserStat( Id, statName, ref val ) )
|
||||
return defult;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a user achievement state. Must call RequestUserStats first.
|
||||
/// </summary>
|
||||
/// <param name="statName">The name of the achievement you want to get</param>
|
||||
/// <param name="defult">Will return this value if not available</param>
|
||||
/// <returns>The value, or defult if not available</returns>
|
||||
public bool GetAchievement( string statName, bool defult = false )
|
||||
{
|
||||
var val = defult;
|
||||
|
||||
if ( !SteamUserStats.Internal.GetUserAchievement( Id, statName, ref val ) )
|
||||
return defult;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a the time this achievement was unlocked.
|
||||
/// </summary>
|
||||
/// <param name="statName">The name of the achievement you want to get</param>
|
||||
/// <returns>The time unlocked. If it wasn't unlocked, or you haven't downloaded the stats yet - will return DateTime.MinValue</returns>
|
||||
public DateTime GetAchievementUnlockTime( string statName )
|
||||
{
|
||||
bool val = false;
|
||||
uint time = 0;
|
||||
|
||||
if ( !SteamUserStats.Internal.GetUserAchievementAndUnlockTime( Id, statName, ref val, ref time ) || !val )
|
||||
return DateTime.MinValue;
|
||||
|
||||
return Epoch.ToDateTime( time );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -98,11 +98,14 @@ namespace Steamworks
|
||||
if ( _properties!= null && _properties.TryGetValue( name, out string val ) )
|
||||
return val;
|
||||
|
||||
uint _ = (uint)Helpers.MaxStringSize;
|
||||
uint _ = (uint)Helpers.MemoryBufferSize;
|
||||
|
||||
if ( !SteamInventory.Internal.GetItemDefinitionProperty( Id, name, out var vl, ref _ ) )
|
||||
return null;
|
||||
|
||||
|
||||
if (name == null) //return keys string
|
||||
return vl;
|
||||
|
||||
if ( _properties == null )
|
||||
_properties = new Dictionary<string, string>();
|
||||
|
||||
@@ -132,7 +135,7 @@ namespace Steamworks
|
||||
string val = GetProperty( name );
|
||||
|
||||
if ( string.IsNullOrEmpty( val ) )
|
||||
return default( T );
|
||||
return default;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -140,7 +143,7 @@ namespace Steamworks
|
||||
}
|
||||
catch ( System.Exception )
|
||||
{
|
||||
return default( T );
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,4 +238,4 @@ namespace Steamworks
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Steamworks
|
||||
/// </summary>
|
||||
public async Task<InventoryResult?> ConsumeAsync( int amount = 1 )
|
||||
{
|
||||
var sresult = default( SteamInventoryResult_t );
|
||||
var sresult = Defines.k_SteamInventoryResultInvalid;
|
||||
if ( !SteamInventory.Internal.ConsumeItem( ref sresult, Id, (uint)amount ) )
|
||||
return null;
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace Steamworks
|
||||
/// </summary>
|
||||
public async Task<InventoryResult?> SplitStackAsync( int quantity = 1 )
|
||||
{
|
||||
var sresult = default( SteamInventoryResult_t );
|
||||
var sresult = Defines.k_SteamInventoryResultInvalid;
|
||||
if ( !SteamInventory.Internal.TransferItemQuantity( ref sresult, Id, (uint)quantity, ulong.MaxValue ) )
|
||||
return null;
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace Steamworks
|
||||
/// </summary>
|
||||
public async Task<InventoryResult?> AddAsync( InventoryItem add, int quantity = 1 )
|
||||
{
|
||||
var sresult = default( SteamInventoryResult_t );
|
||||
var sresult = Defines.k_SteamInventoryResultInvalid;
|
||||
if ( !SteamInventory.Internal.TransferItemQuantity( ref sresult, add.Id, (uint)quantity, Id ) )
|
||||
return null;
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace Steamworks
|
||||
|
||||
internal static Dictionary<string, string> GetProperties( SteamInventoryResult_t result, int index )
|
||||
{
|
||||
var strlen = (uint) Helpers.MaxStringSize;
|
||||
var strlen = (uint) Helpers.MemoryBufferSize;
|
||||
|
||||
if ( !SteamInventory.Internal.GetResultItemProperty( result, (uint)index, null, out var propNames, ref strlen ) )
|
||||
return null;
|
||||
@@ -109,7 +109,7 @@ namespace Steamworks
|
||||
|
||||
foreach ( var propertyName in propNames.Split( ',' ) )
|
||||
{
|
||||
strlen = (uint)Helpers.MaxStringSize;
|
||||
strlen = (uint)Helpers.MemoryBufferSize;
|
||||
|
||||
if ( SteamInventory.Internal.GetResultItemProperty( result, (uint)index, propertyName, out var strVal, ref strlen ) )
|
||||
{
|
||||
@@ -130,17 +130,20 @@ namespace Steamworks
|
||||
{
|
||||
if ( Properties == null ) return DateTime.UtcNow;
|
||||
|
||||
var str = Properties["acquired"];
|
||||
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 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 ) );
|
||||
|
||||
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 new DateTime( y, m, d, h, mn, s, DateTimeKind.Utc );
|
||||
return DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +156,11 @@ namespace Steamworks
|
||||
get
|
||||
{
|
||||
if ( Properties == null ) return null;
|
||||
return Properties["origin"];
|
||||
|
||||
if ( Properties.TryGetValue( "origin", out var str ) )
|
||||
return str;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,10 @@ namespace Steamworks.Data
|
||||
public string Name => SteamUserStats.Internal.GetLeaderboardName( Id );
|
||||
public LeaderboardSort Sort => SteamUserStats.Internal.GetLeaderboardSortMethod( Id );
|
||||
public LeaderboardDisplay Display => SteamUserStats.Internal.GetLeaderboardDisplayType( Id );
|
||||
public int EntryCount => SteamUserStats.Internal.GetLeaderboardEntryCount(Id);
|
||||
|
||||
static int[] detailsBuffer = new int[64];
|
||||
static int[] noDetails = new int[0];
|
||||
static int[] noDetails = Array.Empty<int>();
|
||||
|
||||
/// <summary>
|
||||
/// Submit your score and replace your old score even if it was better
|
||||
@@ -58,6 +59,21 @@ namespace Steamworks.Data
|
||||
return r.Value.Result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches leaderboard entries for an arbitrary set of users on a specified leaderboard.
|
||||
/// </summary>
|
||||
public async Task<LeaderboardEntry[]> GetScoresForUsersAsync( SteamId[] users )
|
||||
{
|
||||
if ( users == null || users.Length == 0 )
|
||||
return null;
|
||||
|
||||
var r = await SteamUserStats.Internal.DownloadLeaderboardEntriesForUsers( Id, users, users.Length );
|
||||
if ( !r.HasValue )
|
||||
return null;
|
||||
|
||||
return await LeaderboardResultToEntries( r.Value );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to query for a sequential range of leaderboard entries by leaderboard Sort.
|
||||
/// </summary>
|
||||
@@ -65,7 +81,7 @@ namespace Steamworks.Data
|
||||
{
|
||||
if ( offset <= 0 ) throw new System.ArgumentException( "Should be 1+", nameof( offset ) );
|
||||
|
||||
var r = await SteamUserStats.Internal.DownloadLeaderboardEntries( Id, LeaderboardDataRequest.Global, offset, offset + count );
|
||||
var r = await SteamUserStats.Internal.DownloadLeaderboardEntries( Id, LeaderboardDataRequest.Global, offset, offset + count - 1 );
|
||||
if ( !r.HasValue )
|
||||
return null;
|
||||
|
||||
@@ -121,7 +137,7 @@ namespace Steamworks.Data
|
||||
return output;
|
||||
}
|
||||
|
||||
internal async Task WaitForUserNames( LeaderboardEntry[] entries)
|
||||
internal static async Task WaitForUserNames( LeaderboardEntry[] entries)
|
||||
{
|
||||
bool gotAll = false;
|
||||
while ( !gotAll )
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Steamworks.Data
|
||||
public SteamId Id { get; internal set; }
|
||||
|
||||
|
||||
internal Lobby( SteamId id )
|
||||
public Lobby( SteamId id )
|
||||
{
|
||||
Id = id;
|
||||
}
|
||||
@@ -123,7 +123,7 @@ namespace Steamworks.Data
|
||||
/// <summary>
|
||||
/// Sets per-user metadata (for the local user implicitly)
|
||||
/// </summary>
|
||||
public void SetMemberData( Friend member, string key, string value )
|
||||
public void SetMemberData( string key, string value )
|
||||
{
|
||||
SteamMatchmaking.Internal.SetLobbyMemberData( Id, key, value );
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Runtime.InteropServices;
|
||||
namespace Steamworks.Data
|
||||
{
|
||||
[StructLayout( LayoutKind.Sequential, Pack = Platform.StructPackSize )]
|
||||
internal struct MatchMakingKeyValuePair
|
||||
internal partial struct MatchMakingKeyValuePair
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
|
||||
internal string Key;
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
using System.Net;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Steamworks.Data
|
||||
{
|
||||
[StructLayout( LayoutKind.Explicit, Size = 18, Pack = 1 )]
|
||||
public struct NetAddress
|
||||
{
|
||||
[FieldOffset( 0 )]
|
||||
internal IPV4 ip;
|
||||
|
||||
[FieldOffset( 16 )]
|
||||
internal ushort port;
|
||||
|
||||
internal struct IPV4
|
||||
{
|
||||
internal ulong m_8zeros;
|
||||
internal ushort m_0000;
|
||||
internal ushort m_ffff;
|
||||
internal byte ip0;
|
||||
internal byte ip1;
|
||||
internal byte ip2;
|
||||
internal byte ip3;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Any IP, specific port
|
||||
/// </summary>
|
||||
public static NetAddress AnyIp( ushort port )
|
||||
{
|
||||
return new NetAddress
|
||||
{
|
||||
ip = new IPV4
|
||||
{
|
||||
m_8zeros = 0,
|
||||
m_0000 = 0,
|
||||
m_ffff = 0,
|
||||
ip0 = 0,
|
||||
ip1 = 0,
|
||||
ip2 = 0,
|
||||
ip3 = 0,
|
||||
},
|
||||
|
||||
port = port
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Localhost IP, specific port
|
||||
/// </summary>
|
||||
public static NetAddress LocalHost( ushort port )
|
||||
{
|
||||
return new NetAddress
|
||||
{
|
||||
ip = new IPV4
|
||||
{
|
||||
m_8zeros = 0,
|
||||
m_0000 = 0,
|
||||
m_ffff = 0,
|
||||
ip0 = 0,
|
||||
ip1 = 0,
|
||||
ip2 = 0,
|
||||
ip3 = 1,
|
||||
},
|
||||
|
||||
port = port
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specific IP, specific port
|
||||
/// </summary>
|
||||
public static NetAddress From( string addrStr, ushort port )
|
||||
{
|
||||
return From( IPAddress.Parse( addrStr ), port );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specific IP, specific port
|
||||
/// </summary>
|
||||
public static NetAddress From( IPAddress address, ushort port )
|
||||
{
|
||||
var addr = address.GetAddressBytes();
|
||||
|
||||
if ( addr.Length == 4 )
|
||||
{
|
||||
return new NetAddress
|
||||
{
|
||||
ip = new IPV4
|
||||
{
|
||||
m_8zeros = 0,
|
||||
m_0000 = 0,
|
||||
m_ffff = 0xffff,
|
||||
ip0 = addr[0],
|
||||
ip1 = addr[1],
|
||||
ip2 = addr[2],
|
||||
ip3 = addr[3],
|
||||
},
|
||||
|
||||
port = port
|
||||
};
|
||||
}
|
||||
|
||||
throw new System.NotImplementedException( "Oops - no IPV6 support yet?" );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Steamworks.Data
|
||||
{
|
||||
[StructLayout( LayoutKind.Explicit, Size = 136, Pack = 1 )]
|
||||
public struct NetIdentity
|
||||
{
|
||||
[FieldOffset( 0 )]
|
||||
internal IdentityType type;
|
||||
|
||||
[FieldOffset( 4 )]
|
||||
internal int m_cbSize;
|
||||
|
||||
[FieldOffset( 8 )]
|
||||
internal SteamId steamID;
|
||||
|
||||
public static implicit operator NetIdentity( SteamId value )
|
||||
{
|
||||
return new NetIdentity { steamID = value, type = IdentityType.SteamID, m_cbSize = 8 };
|
||||
}
|
||||
|
||||
public static implicit operator SteamId( NetIdentity value )
|
||||
{
|
||||
return value.steamID;
|
||||
}
|
||||
|
||||
public override string ToString() => $"{type};{m_cbSize};{steamID}";
|
||||
|
||||
internal enum IdentityType
|
||||
{
|
||||
Invalid = 0,
|
||||
IPAddress = 1,
|
||||
GenericString = 2,
|
||||
GenericBytes = 3,
|
||||
SteamID = 16
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using Steamworks.Data;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Steamworks.Data
|
||||
{
|
||||
[StructLayout( LayoutKind.Sequential )]
|
||||
internal struct NetMsg
|
||||
{
|
||||
internal IntPtr DataPtr;
|
||||
internal int DataSize;
|
||||
internal Connection Connection;
|
||||
internal NetIdentity Identity;
|
||||
internal long ConnectionUserData;
|
||||
internal long RecvTime;
|
||||
internal long MessageNumber;
|
||||
internal IntPtr FreeDataPtr;
|
||||
internal IntPtr ReleasePtr;
|
||||
internal int Channel;
|
||||
|
||||
internal delegate void ReleaseDelegate( IntPtr msg );
|
||||
|
||||
public void Release( IntPtr data )
|
||||
{
|
||||
//
|
||||
// I think this function might be a static global, so we could probably
|
||||
// cache this release call.
|
||||
//
|
||||
var d = Marshal.GetDelegateForFunctionPointer<ReleaseDelegate>( ReleasePtr );
|
||||
d( data );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Steamworks.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Steamworks
|
||||
{
|
||||
public struct P2PSessionState
|
||||
{
|
||||
public byte ConnectionActive;
|
||||
public byte Connecting;
|
||||
public P2PSessionError P2PSessionError;
|
||||
public byte UsingRelay;
|
||||
public int BytesQueuedForSend;
|
||||
public int PacketsQueuedForSend;
|
||||
public uint RemoteIP;
|
||||
public ushort RemotePort;
|
||||
|
||||
internal P2PSessionState(P2PSessionState_t s)
|
||||
{
|
||||
this.ConnectionActive = s.ConnectionActive;
|
||||
this.Connecting = s.Connecting;
|
||||
this.P2PSessionError = (P2PSessionError)s.P2PSessionError;
|
||||
this.UsingRelay = s.UsingRelay;
|
||||
this.BytesQueuedForSend = s.BytesQueuedForSend;
|
||||
this.PacketsQueuedForSend = s.PacketsQueuedForSend;
|
||||
this.RemoteIP = s.RemoteIP;
|
||||
this.RemotePort = s.RemotePort;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace Steamworks
|
||||
{
|
||||
var owner = default( SteamId );
|
||||
var location = default( SteamPartyBeaconLocation_t );
|
||||
Internal.GetBeaconDetails( Id, ref owner, ref location, out var strVal );
|
||||
Internal.GetBeaconDetails( Id, ref owner, ref location, out _ );
|
||||
return owner;
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ namespace Steamworks
|
||||
{
|
||||
var owner = default( SteamId );
|
||||
var location = default( SteamPartyBeaconLocation_t );
|
||||
Internal.GetBeaconDetails( Id, ref owner, ref location, out var strVal );
|
||||
_ = Internal.GetBeaconDetails( Id, ref owner, ref location, out var strVal );
|
||||
return strVal;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Steamworks.Data
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// Object that describes a "location" on the Internet with sufficient
|
||||
/// detail that we can reasonably estimate an upper bound on the ping between
|
||||
/// the two hosts, even if a direct route between the hosts is not possible,
|
||||
/// and the connection must be routed through the Steam Datagram Relay network.
|
||||
/// This does not contain any information that identifies the host. Indeed,
|
||||
/// if two hosts are in the same building or otherwise have nearly identical
|
||||
/// networking characteristics, then it's valid to use the same location
|
||||
/// object for both of them.
|
||||
///
|
||||
/// NOTE: This object should only be used in the same process! Do not serialize it,
|
||||
/// send it over the wire, or persist it in a file or database! If you need
|
||||
/// to do that, convert it to a string representation using the methods in
|
||||
/// ISteamNetworkingUtils().
|
||||
///
|
||||
/// </summary>
|
||||
[StructLayout( LayoutKind.Explicit, Size = 512 )]
|
||||
public struct PingLocation
|
||||
{
|
||||
public static PingLocation? TryParseFromString( string str )
|
||||
{
|
||||
var result = default( PingLocation );
|
||||
if ( !SteamNetworkingUtils.Internal.ParsePingLocationString( str, ref result ) )
|
||||
return null;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
SteamNetworkingUtils.Internal.ConvertPingLocationToString( ref this, out var strVal );
|
||||
return strVal;
|
||||
}
|
||||
|
||||
/// Estimate the round-trip latency between two arbitrary locations, in
|
||||
/// milliseconds. This is a conservative estimate, based on routing through
|
||||
/// the relay network. For most basic relayed connections, this ping time
|
||||
/// will be pretty accurate, since it will be based on the route likely to
|
||||
/// be actually used.
|
||||
///
|
||||
/// If a direct IP route is used (perhaps via NAT traversal), then the route
|
||||
/// will be different, and the ping time might be better. Or it might actually
|
||||
/// be a bit worse! Standard IP routing is frequently suboptimal!
|
||||
///
|
||||
/// But even in this case, the estimate obtained using this method is a
|
||||
/// reasonable upper bound on the ping time. (Also it has the advantage
|
||||
/// of returning immediately and not sending any packets.)
|
||||
///
|
||||
/// In a few cases we might not able to estimate the route. In this case
|
||||
/// a negative value is returned. k_nSteamNetworkingPing_Failed means
|
||||
/// the reason was because of some networking difficulty. (Failure to
|
||||
/// ping, etc) k_nSteamNetworkingPing_Unknown is returned if we cannot
|
||||
/// currently answer the question for some other reason.
|
||||
///
|
||||
/// Do you need to be able to do this from a backend/matchmaking server?
|
||||
/// You are looking for the "ticketgen" library.
|
||||
public int EstimatePingTo( PingLocation target )
|
||||
{
|
||||
return SteamNetworkingUtils.Internal.EstimatePingTimeBetweenTwoLocations( ref this, ref target );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Steamworks.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a RemotePlaySession from the SteamRemotePlay interface
|
||||
/// </summary>
|
||||
public struct RemotePlaySession
|
||||
{
|
||||
public uint Id { get; set; }
|
||||
|
||||
public override string ToString() => Id.ToString();
|
||||
public static implicit operator RemotePlaySession( uint value ) => new RemotePlaySession() { Id = value };
|
||||
public static implicit operator uint( RemotePlaySession value ) => value.Id;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this session was valid when created. This will stay true even
|
||||
/// after disconnection - so be sure to watch SteamRemotePlay.OnSessionDisconnected
|
||||
/// </summary>
|
||||
public bool IsValid => Id > 0;
|
||||
|
||||
/// <summary>
|
||||
/// Get the SteamID of the connected user
|
||||
/// </summary>
|
||||
public SteamId SteamId => SteamRemotePlay.Internal.GetSessionSteamID( Id );
|
||||
|
||||
/// <summary>
|
||||
/// Get the name of the session client device
|
||||
/// </summary>
|
||||
public string ClientName => SteamRemotePlay.Internal.GetSessionClientName( Id );
|
||||
|
||||
/// <summary>
|
||||
/// Get the name of the session client device
|
||||
/// </summary>
|
||||
public SteamDeviceFormFactor FormFactor => SteamRemotePlay.Internal.GetSessionClientFormFactor( Id );
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,6 @@ namespace Steamworks.Data
|
||||
{
|
||||
public struct ServerInfo : IEquatable<ServerInfo>
|
||||
{
|
||||
static ISteamMatchmakingServers Internal => Steamworks.ServerList.Base.Internal;
|
||||
|
||||
public string Name { get; set; }
|
||||
public int Ping { get; set; }
|
||||
public string GameDir { get; set; }
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
namespace Steamworks.Data
|
||||
{
|
||||
public struct Socket
|
||||
{
|
||||
internal uint Id;
|
||||
public override string ToString() => Id.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Destroy a listen socket. All the connections that were accepting on the listen
|
||||
/// socket are closed ungracefully.
|
||||
/// </summary>
|
||||
public bool Close()
|
||||
{
|
||||
return SteamNetworkingSockets.Internal.CloseListenSocket( this );
|
||||
}
|
||||
|
||||
public SocketInterface Interface
|
||||
{
|
||||
get => SteamNetworkingSockets.GetSocketInterface( Id );
|
||||
set => SteamNetworkingSockets.SetSocketInterface( Id, value );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ namespace Steamworks.Data
|
||||
{
|
||||
double val = 0.0;
|
||||
|
||||
if ( SteamUserStats.Internal.GetGlobalStat2( Name, ref val ) )
|
||||
if ( SteamUserStats.Internal.GetGlobalStat( Name, ref val ) )
|
||||
return val;
|
||||
|
||||
return 0;
|
||||
@@ -45,7 +45,7 @@ namespace Steamworks.Data
|
||||
public long GetGlobalInt()
|
||||
{
|
||||
long val = 0;
|
||||
SteamUserStats.Internal.GetGlobalStat1( Name, ref val );
|
||||
SteamUserStats.Internal.GetGlobalStat( Name, ref val );
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace Steamworks.Data
|
||||
|
||||
var r = new long[days];
|
||||
|
||||
var rows = SteamUserStats.Internal.GetGlobalStatHistory1( Name, r, (uint) r.Length * sizeof(long) );
|
||||
var rows = SteamUserStats.Internal.GetGlobalStatHistory( Name, r, (uint) r.Length * sizeof(long) );
|
||||
|
||||
if ( days != rows )
|
||||
r = r.Take( rows ).ToArray();
|
||||
@@ -71,7 +71,7 @@ namespace Steamworks.Data
|
||||
|
||||
var r = new double[days];
|
||||
|
||||
var rows = SteamUserStats.Internal.GetGlobalStatHistory2( Name, r, (uint)r.Length * sizeof( double ) );
|
||||
var rows = SteamUserStats.Internal.GetGlobalStatHistory( Name, r, (uint)r.Length * sizeof( double ) );
|
||||
|
||||
if ( days != rows )
|
||||
r = r.Take( rows ).ToArray();
|
||||
@@ -85,11 +85,11 @@ namespace Steamworks.Data
|
||||
|
||||
if ( UserId > 0 )
|
||||
{
|
||||
SteamUserStats.Internal.GetUserStat2( UserId, Name, ref val );
|
||||
SteamUserStats.Internal.GetUserStat( UserId, Name, ref val );
|
||||
}
|
||||
else
|
||||
{
|
||||
SteamUserStats.Internal.GetStat2( Name, ref val );
|
||||
SteamUserStats.Internal.GetStat( Name, ref val );
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -101,11 +101,11 @@ namespace Steamworks.Data
|
||||
|
||||
if ( UserId > 0 )
|
||||
{
|
||||
SteamUserStats.Internal.GetUserStat1( UserId, Name, ref val );
|
||||
SteamUserStats.Internal.GetUserStat( UserId, Name, ref val );
|
||||
}
|
||||
else
|
||||
{
|
||||
SteamUserStats.Internal.GetStat1( Name, ref val );
|
||||
SteamUserStats.Internal.GetStat( Name, ref val );
|
||||
}
|
||||
|
||||
return val;
|
||||
@@ -114,13 +114,13 @@ namespace Steamworks.Data
|
||||
public bool Set( int val )
|
||||
{
|
||||
LocalUserOnly();
|
||||
return SteamUserStats.Internal.SetStat1( Name, val );
|
||||
return SteamUserStats.Internal.SetStat( Name, val );
|
||||
}
|
||||
|
||||
public bool Set( float val )
|
||||
{
|
||||
LocalUserOnly();
|
||||
return SteamUserStats.Internal.SetStat2( Name, val );
|
||||
return SteamUserStats.Internal.SetStat( Name, val );
|
||||
}
|
||||
|
||||
public bool Add( int val )
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Steamworks.Data
|
||||
{
|
||||
[StructLayout( LayoutKind.Explicit, Pack = Platform.StructPlatformPackSize )]
|
||||
internal partial struct SteamIPAddress
|
||||
{
|
||||
[FieldOffset( 0 )]
|
||||
public uint Ip4Address; // Host Order
|
||||
|
||||
[FieldOffset( 16 )]
|
||||
internal SteamIPType Type; // m_eType ESteamIPType
|
||||
|
||||
public static implicit operator System.Net.IPAddress( SteamIPAddress value )
|
||||
{
|
||||
if ( value.Type == SteamIPType.Type4 )
|
||||
return Utility.Int32ToIp( value.Ip4Address );
|
||||
|
||||
throw new System.Exception( $"Oops - can't convert SteamIPAddress to System.Net.IPAddress because no-one coded support for {value.Type} yet" );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Steamworks.Data
|
||||
{
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void FSteamNetworkingSocketsDebugOutput (DebugOutputType nType, string pszMsg );
|
||||
|
||||
public struct SteamNetworkingPOPID
|
||||
{
|
||||
public uint Value;
|
||||
|
||||
public static implicit operator SteamNetworkingPOPID( uint value )
|
||||
{
|
||||
return new SteamNetworkingPOPID { Value = value };
|
||||
}
|
||||
|
||||
public static implicit operator uint( SteamNetworkingPOPID value )
|
||||
{
|
||||
return value.Value;
|
||||
}
|
||||
|
||||
public override string ToString() => Value.ToString();
|
||||
}
|
||||
|
||||
[StructLayout( LayoutKind.Sequential )]
|
||||
public struct SteamNetworkingQuickConnectionStatus
|
||||
{
|
||||
public ConnectionState state;
|
||||
public int ping;
|
||||
public float connectionQualityLocal;
|
||||
public float connectionQualityRemote;
|
||||
public float outPacketsPerSecond;
|
||||
public float outBytesPerSecond;
|
||||
public float inPacketsPerSecond;
|
||||
public float inBytesPerSecond;
|
||||
public int sendRateBytesPerSecond;
|
||||
public int pendingUnreliable;
|
||||
public int pendingReliable;
|
||||
public int sentUnackedReliable;
|
||||
public long queueTime;
|
||||
|
||||
[MarshalAs( UnmanagedType.ByValArray, SizeConst = 16 )]
|
||||
uint[] reserved;
|
||||
}
|
||||
|
||||
struct SteamDatagramRelayAuthTicket
|
||||
{
|
||||
// Not implemented
|
||||
};
|
||||
|
||||
struct SteamDatagramHostedAddress
|
||||
{
|
||||
// Not implemented
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,13 @@
|
||||
using System.Linq;
|
||||
|
||||
#pragma warning disable 649
|
||||
|
||||
namespace Steamworks.Data
|
||||
{
|
||||
public struct Ugc
|
||||
{
|
||||
internal UGCHandle_t Handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning restore 649
|
||||
|
||||
@@ -14,29 +14,36 @@ namespace Steamworks.Ugc
|
||||
public PublishedFileId FileId { get; private set; }
|
||||
|
||||
bool creatingNew;
|
||||
WorkshopFileType creatingType;
|
||||
AppId consumerAppId;
|
||||
|
||||
internal Editor(WorkshopFileType filetype) : this()
|
||||
{
|
||||
this.creatingNew = true;
|
||||
this.creatingType = filetype;
|
||||
}
|
||||
WorkshopFileType creatingType;
|
||||
AppId consumerAppId;
|
||||
|
||||
public Editor(PublishedFileId fileId) : this()
|
||||
{
|
||||
this.FileId = fileId;
|
||||
}
|
||||
internal Editor( WorkshopFileType filetype ) : this()
|
||||
{
|
||||
this.creatingNew = true;
|
||||
this.creatingType = filetype;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a Normal Workshop item that can be subscribed to
|
||||
/// </summary>
|
||||
public static Editor CreateCommunityFile() { return new Editor(WorkshopFileType.Community); }
|
||||
public Editor( PublishedFileId fileId ) : this()
|
||||
{
|
||||
this.FileId = fileId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Workshop item that is meant to be voted on for the purpose of selling in-game
|
||||
/// </summary>
|
||||
public static Editor CreateMicrotransactionFile() { return new Editor(WorkshopFileType.Microtransaction ); }
|
||||
/// <summary>
|
||||
/// Create a Normal Workshop item that can be subscribed to
|
||||
/// </summary>
|
||||
public static Editor NewCommunityFile => new Editor( WorkshopFileType.Community );
|
||||
|
||||
/// <summary>
|
||||
/// Create a Collection
|
||||
/// Add items using Item.AddDependency()
|
||||
/// </summary>
|
||||
public static Editor NewCollection => new Editor( WorkshopFileType.Collection );
|
||||
|
||||
/// <summary>
|
||||
/// Workshop item that is meant to be voted on for the purpose of selling in-game
|
||||
/// </summary>
|
||||
public static Editor NewMicrotransactionFile => new Editor( WorkshopFileType.Microtransaction );
|
||||
|
||||
public Editor ForAppId( AppId id ) { this.consumerAppId = id; return this; }
|
||||
|
||||
@@ -68,11 +75,14 @@ namespace Steamworks.Ugc
|
||||
public Editor WithFriendsOnlyVisibility() { Visibility = RemoteStoragePublishedFileVisibility.FriendsOnly; return this; }
|
||||
public Editor WithPrivateVisibility() { Visibility = RemoteStoragePublishedFileVisibility.Private; return this; }
|
||||
|
||||
public List<string> Tags { get; private set; }
|
||||
Dictionary<string, List<string>> KeyValueTags;
|
||||
HashSet<string> KeyValueTagsToRemove;
|
||||
|
||||
public bool IsPublic => Visibility == RemoteStoragePublishedFileVisibility.Public;
|
||||
public bool IsFriendsOnly => Visibility == RemoteStoragePublishedFileVisibility.FriendsOnly;
|
||||
public bool IsPrivate => Visibility == RemoteStoragePublishedFileVisibility.Private;
|
||||
|
||||
public List<string> Tags { get; private set; }
|
||||
public Editor WithTag( string tag )
|
||||
{
|
||||
if ( Tags == null ) Tags = new List<string>();
|
||||
@@ -82,22 +92,56 @@ namespace Steamworks.Ugc
|
||||
return this;
|
||||
}
|
||||
|
||||
public Editor WithTags( IEnumerable<string> tags )
|
||||
{
|
||||
if (Tags == null) Tags = new List<string>();
|
||||
public Editor WithTags(IEnumerable<string> tags)
|
||||
{
|
||||
if (Tags == null) Tags = new List<string>();
|
||||
|
||||
Tags.AddRange(tags);
|
||||
Tags.AddRange(tags);
|
||||
|
||||
return this;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Editor WithoutTag( string tag )
|
||||
public Editor WithoutTag(string tag)
|
||||
{
|
||||
if (Tags != null && Tags.Contains(tag)) Tags.Remove(tag);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a key-value tag pair to an item.
|
||||
/// Keys can map to multiple different values (1-to-many relationship).
|
||||
/// Key names are restricted to alpha-numeric characters and the '_' character.
|
||||
/// Both keys and values cannot exceed 255 characters in length. Key-value tags are searchable by exact match only.
|
||||
/// To replace all values associated to one key use RemoveKeyValueTags then AddKeyValueTag.
|
||||
/// </summary>
|
||||
public Editor AddKeyValueTag(string key, string value)
|
||||
{
|
||||
if (KeyValueTags == null)
|
||||
KeyValueTags = new Dictionary<string, List<string>>();
|
||||
|
||||
if ( KeyValueTags.TryGetValue( key, out var list ) )
|
||||
list.Add( value );
|
||||
else
|
||||
KeyValueTags[key] = new List<string>() { value };
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a key and all values associated to it.
|
||||
/// You can remove up to 100 keys per item update.
|
||||
/// If you need remove more tags than that you'll need to make subsequent item updates.
|
||||
/// </summary>
|
||||
public Editor RemoveKeyValueTags(string key)
|
||||
{
|
||||
if (KeyValueTagsToRemove == null)
|
||||
KeyValueTagsToRemove = new HashSet<string>();
|
||||
|
||||
KeyValueTagsToRemove.Add(key);
|
||||
return this;
|
||||
}
|
||||
|
||||
public bool HasTag( string tag )
|
||||
{
|
||||
if (Tags != null && Tags.Contains(tag)) { return true; }
|
||||
@@ -114,6 +158,19 @@ namespace Steamworks.Ugc
|
||||
if ( consumerAppId == 0 )
|
||||
consumerAppId = SteamClient.AppId;
|
||||
|
||||
//
|
||||
// Checks
|
||||
//
|
||||
if ( ContentFolder != null )
|
||||
{
|
||||
if ( !System.IO.Directory.Exists( ContentFolder.FullName ) )
|
||||
throw new System.Exception( $"UgcEditor - Content Folder doesn't exist ({ContentFolder.FullName})" );
|
||||
|
||||
if ( !ContentFolder.EnumerateFiles( "*", System.IO.SearchOption.AllDirectories ).Any() )
|
||||
throw new System.Exception( $"UgcEditor - Content Folder is empty" );
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Item Create
|
||||
//
|
||||
@@ -160,6 +217,22 @@ namespace Steamworks.Ugc
|
||||
}
|
||||
}
|
||||
|
||||
if ( KeyValueTagsToRemove != null)
|
||||
{
|
||||
foreach ( var key in KeyValueTagsToRemove )
|
||||
SteamUGC.Internal.RemoveItemKeyValueTags( handle, key );
|
||||
}
|
||||
|
||||
if ( KeyValueTags != null )
|
||||
{
|
||||
foreach ( var keyWithValues in KeyValueTags )
|
||||
{
|
||||
var key = keyWithValues.Key;
|
||||
foreach ( var value in keyWithValues.Value )
|
||||
SteamUGC.Internal.AddItemKeyValueTag( handle, key, value );
|
||||
}
|
||||
}
|
||||
|
||||
result.Result = Steamworks.Result.Fail;
|
||||
|
||||
if ( ChangeLog == null )
|
||||
@@ -197,7 +270,7 @@ namespace Steamworks.Ugc
|
||||
}
|
||||
case ItemUpdateStatus.UploadingPreviewFile:
|
||||
{
|
||||
progress?.Report( 8f );
|
||||
progress?.Report( 0.8f );
|
||||
break;
|
||||
}
|
||||
case ItemUpdateStatus.CommittingChanges:
|
||||
@@ -213,7 +286,7 @@ namespace Steamworks.Ugc
|
||||
|
||||
progress?.Report( 1 );
|
||||
|
||||
var updated = updating.Result;
|
||||
var updated = updating.GetResult();
|
||||
|
||||
if ( !updated.HasValue ) return result;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Steamworks.Data;
|
||||
|
||||
@@ -38,6 +39,11 @@ namespace Steamworks.Ugc
|
||||
/// </summary>
|
||||
public string[] Tags { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// A dictionary of key value tags for this item, only available from queries WithKeyValueTags(true)
|
||||
/// </summary>
|
||||
public Dictionary<string,string> KeyValueTags { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// App Id of the app that created this item
|
||||
/// </summary>
|
||||
@@ -125,7 +131,7 @@ namespace Steamworks.Ugc
|
||||
|
||||
/// <summary>
|
||||
/// Start downloading this item.
|
||||
/// If this returns false the item isn#t getting downloaded.
|
||||
/// If this returns false the item isn't getting downloaded.
|
||||
/// </summary>
|
||||
public bool Download( Action onInstalled = null, bool highPriority = false )
|
||||
{
|
||||
@@ -182,8 +188,7 @@ namespace Steamworks.Ugc
|
||||
|
||||
ulong size = 0;
|
||||
uint ts = 0;
|
||||
|
||||
if ( !SteamUGC.Internal.GetItemInstallInfo( Id, ref size, out var strVal, ref ts ) )
|
||||
if ( !SteamUGC.Internal.GetItemInstallInfo( Id, ref size, out _, ref ts ) )
|
||||
return 0;
|
||||
|
||||
return (long) size;
|
||||
@@ -197,7 +202,9 @@ namespace Steamworks.Ugc
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( !NeedsUpdate ) return 1;
|
||||
//changed from NeedsUpdate as it's false when validating and redownloading ugc
|
||||
//possibly similar properties should also be changed
|
||||
if ( !IsDownloading ) return 1;
|
||||
|
||||
ulong downloaded = 0;
|
||||
ulong total = 0;
|
||||
@@ -215,10 +222,18 @@ namespace Steamworks.Ugc
|
||||
|
||||
public static async Task<Item?> GetAsync( PublishedFileId id, int maxageseconds = 60 * 30 )
|
||||
{
|
||||
var result = await SteamUGC.Internal.RequestUGCDetails( id, (uint) maxageseconds );
|
||||
if ( !result.HasValue ) return null;
|
||||
var file = await Steamworks.Ugc.Query.All
|
||||
.WithFileId( id )
|
||||
.WithLongDescription( true )
|
||||
.GetPageAsync( 1 );
|
||||
|
||||
return From( result.Value.Details );
|
||||
if ( !file.HasValue ) return null;
|
||||
using ( file.Value )
|
||||
{
|
||||
if ( file.Value.ResultCount == 0 ) return null;
|
||||
|
||||
return file.Value.Entries.First();
|
||||
}
|
||||
}
|
||||
|
||||
internal static Item From( SteamUGCDetails_t details )
|
||||
@@ -254,28 +269,67 @@ namespace Steamworks.Ugc
|
||||
return result?.Result == Result.OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows the user to unsubscribe from this item
|
||||
/// </summary>
|
||||
public async Task<bool> Unsubscribe ()
|
||||
/// <summary>
|
||||
/// Allows the user to subscribe to download this item asyncronously
|
||||
/// If CancellationToken is default then there is 60 seconds timeout
|
||||
/// Progress will be set to 0-1
|
||||
/// </summary>
|
||||
public async Task<bool> DownloadAsync( Action<float> progress = null, int milisecondsUpdateDelay = 60, CancellationToken ct = default )
|
||||
{
|
||||
return await SteamUGC.DownloadAsync( Id, progress, milisecondsUpdateDelay, ct );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows the user to unsubscribe from this item
|
||||
/// </summary>
|
||||
public async Task<bool> Unsubscribe ()
|
||||
{
|
||||
var result = await SteamUGC.Internal.UnsubscribeItem( _id );
|
||||
return result?.Result == Result.OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds item to user favorite list
|
||||
/// </summary>
|
||||
public async Task<bool> AddFavorite()
|
||||
{
|
||||
var result = await SteamUGC.Internal.AddItemToFavorites(details.ConsumerAppID, _id);
|
||||
return result?.Result == Result.OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes item from user favorite list
|
||||
/// </summary>
|
||||
public async Task<bool> RemoveFavorite()
|
||||
{
|
||||
var result = await SteamUGC.Internal.RemoveItemFromFavorites(details.ConsumerAppID, _id);
|
||||
return result?.Result == Result.OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows the user to rate a workshop item up or down.
|
||||
/// </summary>
|
||||
public async Task<bool> Vote( bool up )
|
||||
public async Task<Result?> Vote( bool up )
|
||||
{
|
||||
var r = await SteamUGC.Internal.SetUserItemVote( Id, up );
|
||||
return r?.Result == Result.OK;
|
||||
return r?.Result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a URL to view this item online
|
||||
/// </summary>
|
||||
public string Url => $"http://steamcommunity.com/sharedfiles/filedetails/?source=Facepunch.Steamworks&id={Id}";
|
||||
/// <summary>
|
||||
/// Gets the current users vote on the item
|
||||
/// </summary>
|
||||
public async Task<UserItemVote?> GetUserVote()
|
||||
{
|
||||
var result = await SteamUGC.Internal.GetUserItemVote(_id);
|
||||
if (!result.HasValue)
|
||||
return null;
|
||||
return UserItemVote.From(result.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a URL to view this item online
|
||||
/// </summary>
|
||||
public string Url => $"http://steamcommunity.com/sharedfiles/filedetails/?source=Facepunch.Steamworks&id={Id}";
|
||||
|
||||
/// <summary>
|
||||
/// The URl to view this item's changelog
|
||||
@@ -311,10 +365,15 @@ namespace Steamworks.Ugc
|
||||
public ulong NumSecondsPlayedDuringTimePeriod { get; internal set; }
|
||||
public ulong NumPlaytimeSessionsDuringTimePeriod { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The URL to the preview image for this item
|
||||
/// </summary>
|
||||
public string PreviewImageUrl { get; internal set; }
|
||||
/// <summary>
|
||||
/// The URL to the preview image for this item
|
||||
/// </summary>
|
||||
public string PreviewImageUrl { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The metadata string for this item, only available from queries WithMetadata(true)
|
||||
/// </summary>
|
||||
public string Metadata { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Edit this item
|
||||
@@ -323,6 +382,7 @@ namespace Steamworks.Ugc
|
||||
{
|
||||
return new Ugc.Editor( Id );
|
||||
}
|
||||
|
||||
public Result Result => details.Result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,9 +137,16 @@ namespace Steamworks.Ugc
|
||||
}
|
||||
else
|
||||
{
|
||||
handle = SteamUGC.Internal.CreateQueryAllUGCRequest1( queryType, matchingType, creatorApp.Value, consumerApp.Value, (uint)page );
|
||||
handle = SteamUGC.Internal.CreateQueryAllUGCRequest( queryType, matchingType, creatorApp.Value, consumerApp.Value, (uint)page );
|
||||
}
|
||||
|
||||
ApplyReturns(handle);
|
||||
|
||||
if (maxCacheAge.HasValue)
|
||||
{
|
||||
SteamUGC.Internal.SetAllowCachedResponse(handle, (uint)maxCacheAge.Value);
|
||||
}
|
||||
|
||||
ApplyConstraints( handle );
|
||||
|
||||
var result = await SteamUGC.Internal.SendQueryUGCRequest( handle );
|
||||
@@ -154,29 +161,15 @@ namespace Steamworks.Ugc
|
||||
Handle = result.Value.Handle,
|
||||
ResultCount = (int) result.Value.NumResultsReturned,
|
||||
TotalCount = (int)result.Value.TotalMatchingResults,
|
||||
CachedData = result.Value.CachedData
|
||||
CachedData = result.Value.CachedData,
|
||||
ReturnsKeyValueTags = WantsReturnKeyValueTags ?? false,
|
||||
ReturnsDefaultStats = WantsDefaultStats ?? true, //true by default
|
||||
ReturnsMetadata = WantsReturnMetadata ?? false,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#region SharedConstraints
|
||||
#region SharedConstraints
|
||||
public QueryType WithType( UgcType type ) { matchingType = type; return this; }
|
||||
bool? WantsReturnOnlyIDs;
|
||||
public QueryType WithOnlyIDs( bool b ) { WantsReturnOnlyIDs = b; return this; }
|
||||
bool? WantsReturnKeyValueTags;
|
||||
public QueryType WithKeyValueTag( bool b ) { WantsReturnKeyValueTags = b; return this; }
|
||||
bool? WantsReturnLongDescription;
|
||||
public QueryType WithLongDescription( bool b ) { WantsReturnLongDescription = b; return this; }
|
||||
bool? WantsReturnMetadata;
|
||||
public QueryType WithMetadata( bool b ) { WantsReturnMetadata = b; return this; }
|
||||
bool? WantsReturnChildren;
|
||||
public QueryType WithChildren( bool b ) { WantsReturnChildren = b; return this; }
|
||||
bool? WantsReturnAdditionalPreviews;
|
||||
public QueryType WithAdditionalPreviews( bool b ) { WantsReturnAdditionalPreviews = b; return this; }
|
||||
bool? WantsReturnTotalOnly;
|
||||
public QueryType WithTotalOnly( bool b ) { WantsReturnTotalOnly = b; return this; }
|
||||
bool? WantsReturnPlaytimeStats;
|
||||
public QueryType WithPlaytimeStats( bool b ) { WantsReturnPlaytimeStats = b; return this; }
|
||||
int? maxCacheAge;
|
||||
public QueryType AllowCachedResponse( int maxSecondsAge ) { maxCacheAge = maxSecondsAge; return this; }
|
||||
string language;
|
||||
@@ -221,6 +214,13 @@ namespace Steamworks.Ugc
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryType AddRequiredKeyValueTag(string key, string value)
|
||||
{
|
||||
if (requiredKv == null) requiredKv = new Dictionary<string, string>();
|
||||
requiredKv.Add(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
void ApplyConstraints( UGCQueryHandle_t handle )
|
||||
{
|
||||
if ( requiredTags != null )
|
||||
@@ -259,7 +259,82 @@ namespace Steamworks.Ugc
|
||||
SteamUGC.Internal.SetReturnLongDescription( handle, returnLongDescription );
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region ReturnValues
|
||||
|
||||
bool? WantsReturnOnlyIDs;
|
||||
public QueryType WithOnlyIDs(bool b) { WantsReturnOnlyIDs = b; return this; }
|
||||
bool? WantsReturnKeyValueTags;
|
||||
public QueryType WithKeyValueTags(bool b) { WantsReturnKeyValueTags = b; return this; }
|
||||
[Obsolete( "Renamed to WithKeyValueTags" )]
|
||||
public QueryType WithKeyValueTag(bool b) { WantsReturnKeyValueTags = b; return this; }
|
||||
bool? WantsReturnLongDescription;
|
||||
public QueryType WithLongDescription(bool b) { WantsReturnLongDescription = b; return this; }
|
||||
bool? WantsReturnMetadata;
|
||||
public QueryType WithMetadata(bool b) { WantsReturnMetadata = b; return this; }
|
||||
bool? WantsReturnChildren;
|
||||
public QueryType WithChildren(bool b) { WantsReturnChildren = b; return this; }
|
||||
bool? WantsReturnAdditionalPreviews;
|
||||
public QueryType WithAdditionalPreviews(bool b) { WantsReturnAdditionalPreviews = b; return this; }
|
||||
bool? WantsReturnTotalOnly;
|
||||
public QueryType WithTotalOnly(bool b) { WantsReturnTotalOnly = b; return this; }
|
||||
uint? WantsReturnPlaytimeStats;
|
||||
public QueryType WithPlaytimeStats(uint unDays) { WantsReturnPlaytimeStats = unDays; return this; }
|
||||
|
||||
private void ApplyReturns(UGCQueryHandle_t handle)
|
||||
{
|
||||
if (WantsReturnOnlyIDs.HasValue)
|
||||
{
|
||||
SteamUGC.Internal.SetReturnOnlyIDs(handle, WantsReturnOnlyIDs.Value);
|
||||
}
|
||||
|
||||
if (WantsReturnKeyValueTags.HasValue)
|
||||
{
|
||||
SteamUGC.Internal.SetReturnKeyValueTags(handle, WantsReturnKeyValueTags.Value);
|
||||
}
|
||||
|
||||
if (WantsReturnLongDescription.HasValue)
|
||||
{
|
||||
SteamUGC.Internal.SetReturnLongDescription(handle, WantsReturnLongDescription.Value);
|
||||
}
|
||||
|
||||
if (WantsReturnMetadata.HasValue)
|
||||
{
|
||||
SteamUGC.Internal.SetReturnMetadata(handle, WantsReturnMetadata.Value);
|
||||
}
|
||||
|
||||
if (WantsReturnChildren.HasValue)
|
||||
{
|
||||
SteamUGC.Internal.SetReturnChildren(handle, WantsReturnChildren.Value);
|
||||
}
|
||||
|
||||
if (WantsReturnAdditionalPreviews.HasValue)
|
||||
{
|
||||
SteamUGC.Internal.SetReturnAdditionalPreviews(handle, WantsReturnAdditionalPreviews.Value);
|
||||
}
|
||||
|
||||
if (WantsReturnTotalOnly.HasValue)
|
||||
{
|
||||
SteamUGC.Internal.SetReturnTotalOnly(handle, WantsReturnTotalOnly.Value);
|
||||
}
|
||||
|
||||
if (WantsReturnPlaytimeStats.HasValue)
|
||||
{
|
||||
SteamUGC.Internal.SetReturnPlaytimeStats(handle, WantsReturnPlaytimeStats.Value);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LoadingBehaviour
|
||||
|
||||
bool? WantsDefaultStats; //true by default
|
||||
/// <summary>
|
||||
/// Set to false to disable, by default following stats are loaded: NumSubscriptions, NumFavorites, NumFollowers, NumUniqueSubscriptions, NumUniqueFavorites, NumUniqueFollowers, NumUniqueWebsiteViews, ReportScore, NumSecondsPlayed, NumPlaytimeSessions, NumComments, NumSecondsPlayedDuringTimePeriod, NumPlaytimeSessionsDuringTimePeriod
|
||||
/// </summary>
|
||||
public QueryType WithDefaultStats( bool b ) { WantsDefaultStats = b; return this; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,10 @@ namespace Steamworks.Ugc
|
||||
|
||||
public bool CachedData;
|
||||
|
||||
internal bool ReturnsKeyValueTags;
|
||||
internal bool ReturnsDefaultStats;
|
||||
internal bool ReturnsMetadata;
|
||||
|
||||
public IEnumerable<Item> Entries
|
||||
{
|
||||
get
|
||||
@@ -24,30 +28,53 @@ namespace Steamworks.Ugc
|
||||
{
|
||||
var item = Item.From( details );
|
||||
|
||||
item.NumSubscriptions = GetStat( i, ItemStatistic.NumSubscriptions );
|
||||
item.NumFavorites = GetStat( i, ItemStatistic.NumFavorites );
|
||||
item.NumFollowers = GetStat( i, ItemStatistic.NumFollowers );
|
||||
item.NumUniqueSubscriptions = GetStat( i, ItemStatistic.NumUniqueSubscriptions );
|
||||
item.NumUniqueFavorites = GetStat( i, ItemStatistic.NumUniqueFavorites );
|
||||
item.NumUniqueFollowers = GetStat( i, ItemStatistic.NumUniqueFollowers );
|
||||
item.NumUniqueWebsiteViews = GetStat( i, ItemStatistic.NumUniqueWebsiteViews );
|
||||
item.ReportScore = GetStat( i, ItemStatistic.ReportScore );
|
||||
item.NumSecondsPlayed = GetStat( i, ItemStatistic.NumSecondsPlayed );
|
||||
item.NumPlaytimeSessions = GetStat( i, ItemStatistic.NumPlaytimeSessions );
|
||||
item.NumComments = GetStat( i, ItemStatistic.NumComments );
|
||||
item.NumSecondsPlayedDuringTimePeriod = GetStat( i, ItemStatistic.NumSecondsPlayedDuringTimePeriod );
|
||||
item.NumPlaytimeSessionsDuringTimePeriod = GetStat( i, ItemStatistic.NumPlaytimeSessionsDuringTimePeriod );
|
||||
|
||||
if ( ReturnsDefaultStats )
|
||||
{
|
||||
item.NumSubscriptions = GetStat( i, ItemStatistic.NumSubscriptions );
|
||||
item.NumFavorites = GetStat( i, ItemStatistic.NumFavorites );
|
||||
item.NumFollowers = GetStat( i, ItemStatistic.NumFollowers );
|
||||
item.NumUniqueSubscriptions = GetStat( i, ItemStatistic.NumUniqueSubscriptions );
|
||||
item.NumUniqueFavorites = GetStat( i, ItemStatistic.NumUniqueFavorites );
|
||||
item.NumUniqueFollowers = GetStat( i, ItemStatistic.NumUniqueFollowers );
|
||||
item.NumUniqueWebsiteViews = GetStat( i, ItemStatistic.NumUniqueWebsiteViews );
|
||||
item.ReportScore = GetStat( i, ItemStatistic.ReportScore );
|
||||
item.NumSecondsPlayed = GetStat( i, ItemStatistic.NumSecondsPlayed );
|
||||
item.NumPlaytimeSessions = GetStat( i, ItemStatistic.NumPlaytimeSessions );
|
||||
item.NumComments = GetStat( i, ItemStatistic.NumComments );
|
||||
item.NumSecondsPlayedDuringTimePeriod = GetStat( i, ItemStatistic.NumSecondsPlayedDuringTimePeriod );
|
||||
item.NumPlaytimeSessionsDuringTimePeriod = GetStat( i, ItemStatistic.NumPlaytimeSessionsDuringTimePeriod );
|
||||
}
|
||||
|
||||
if ( SteamUGC.Internal.GetQueryUGCPreviewURL( Handle, i, out string preview ) )
|
||||
{
|
||||
item.PreviewImageUrl = preview;
|
||||
}
|
||||
|
||||
if ( ReturnsKeyValueTags )
|
||||
{
|
||||
var keyValueTagsCount = SteamUGC.Internal.GetQueryUGCNumKeyValueTags( Handle, i );
|
||||
|
||||
item.KeyValueTags = new Dictionary<string, string>( (int)keyValueTagsCount );
|
||||
for ( uint j = 0; j < keyValueTagsCount; j++ )
|
||||
{
|
||||
string key, value;
|
||||
if ( SteamUGC.Internal.GetQueryUGCKeyValueTag( Handle, i, j, out key, out value ) )
|
||||
item.KeyValueTags[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
if (ReturnsMetadata)
|
||||
{
|
||||
string metadata;
|
||||
if (SteamUGC.Internal.GetQueryUGCMetadata(Handle, i, out metadata))
|
||||
{
|
||||
item.Metadata = metadata;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO GetQueryUGCAdditionalPreview
|
||||
// TODO GetQueryUGCChildren
|
||||
// TODO GetQueryUGCKeyValueTag
|
||||
// TODO GetQueryUGCMetadata
|
||||
|
||||
|
||||
yield return item;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using Steamworks.Data;
|
||||
|
||||
namespace Steamworks.Ugc
|
||||
{
|
||||
public struct UserItemVote
|
||||
{
|
||||
public bool VotedUp;
|
||||
public bool VotedDown;
|
||||
public bool VoteSkipped;
|
||||
|
||||
internal static UserItemVote? From(GetUserItemVoteResult_t result)
|
||||
{
|
||||
return new UserItemVote
|
||||
{
|
||||
VotedUp = result.VotedUp,
|
||||
VotedDown = result.VotedDown,
|
||||
VoteSkipped = result.VoteSkipped
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user