Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Alex Mein 2019-12-16 09:49:24 +00:00
commit 19e64429c4
15 changed files with 158 additions and 53 deletions

View File

@ -211,7 +211,7 @@ public enum AuthResponse : int
//
// EUserHasLicenseForAppResult
//
internal enum UserHasLicenseForAppResult : int
public enum UserHasLicenseForAppResult : int
{
HasLicense = 0,
DoesNotHaveLicense = 1,
@ -585,7 +585,7 @@ public enum FriendState : int
//
// EFriendFlags
//
internal enum FriendFlags : int
public enum FriendFlags : int
{
None = 0,
Blocked = 1,

View File

@ -111,21 +111,23 @@ static unsafe void OnFriendChatMessage( GameConnectedFriendChatMsg_t data )
OnChatMessage( friend, typeName, message );
}
}
public static IEnumerable<Friend> GetFriendsWithFlag(FriendFlags flag)
{
for ( int i=0; i<Internal.GetFriendCount( (int)flag); i++ )
{
yield return new Friend( Internal.GetFriendByIndex( i, (int)flag ) );
}
}
public static IEnumerable<Friend> GetFriends()
{
for ( int i=0; i<Internal.GetFriendCount( (int) FriendFlags.Immediate ); i++ )
{
yield return new Friend( Internal.GetFriendByIndex( i, (int)FriendFlags.Immediate ) );
}
return GetFriendsWithFlag(FriendFlags.Immediate);
}
public static IEnumerable<Friend> GetBlocked()
{
for ( int i = 0; i < Internal.GetFriendCount( (int)FriendFlags.Blocked ); i++ )
{
yield return new Friend( Internal.GetFriendByIndex( i, (int)FriendFlags.Blocked) );
}
return GetFriendsWithFlag(FriendFlags.Blocked);
}
public static IEnumerable<Friend> GetPlayedWith()

View File

@ -91,10 +91,10 @@ public static bool IsP2PPacketAvailable( int channel = 0 )
var buffer = Helpers.TakeBuffer( (int) size );
fixed ( byte* p = buffer )
{
SteamId steamid = 1;
if ( !Internal.ReadP2PPacket( (IntPtr)p, (uint) buffer.Length, ref size, ref steamid, channel ) || size == 0 )
return null;
{
SteamId steamid = 1;
if ( !Internal.ReadP2PPacket( (IntPtr)p, (uint) buffer.Length, ref size, ref steamid, channel ) || size == 0 )
return null;
var data = new byte[size];
Array.Copy( buffer, 0, data, 0, size );
@ -104,7 +104,25 @@ public static bool IsP2PPacketAvailable( int channel = 0 )
SteamId = steamid,
Data = data
};
}
}
}
/// <summary>
/// Reads in a packet that has been sent from another user via SendP2PPacket..
/// </summary>
public unsafe static bool ReadP2PPacket( byte[] buffer, ref uint size, ref SteamId steamid, int channel = 0 )
{
fixed (byte* p = buffer) {
return Internal.ReadP2PPacket( (IntPtr)p, (uint)buffer.Length, ref size, ref steamid, channel );
}
}
/// <summary>
/// Reads in a packet that has been sent from another user via SendP2PPacket..
/// </summary>
public unsafe static bool ReadP2PPacket( byte* buffer, uint cbuf, ref uint size, ref SteamId steamid, int channel = 0 )
{
return Internal.ReadP2PPacket( (IntPtr)buffer, cbuf, ref size, ref steamid, channel );
}
/// <summary>
@ -123,6 +141,15 @@ public static unsafe bool SendP2PPacket( SteamId steamid, byte[] data, int lengt
}
}
/// <summary>
/// Sends a P2P packet to the specified user.
/// This is a session-less API which automatically establishes NAT-traversing or Steam relay server connections.
/// NOTE: The first packet send may be delayed as the NAT-traversal code runs.
/// </summary>
public static unsafe bool SendP2PPacket( SteamId steamid, byte* data, uint length, int nChannel = 1, P2PSend sendType = P2PSend.Reliable )
{
return Internal.SendP2PPacket( steamid, (IntPtr)data, (uint)length, (P2PSend)sendType, nChannel );
}
}
}
}

View File

@ -464,6 +464,14 @@ public static unsafe void HandleIncomingPacket( byte[] data, int size, uint addr
public static unsafe void HandleIncomingPacket( IntPtr ptr, int size, uint address, ushort port )
{
Internal.HandleIncomingPacket( ptr, size, address, port );
}
/// <summary>
/// Does the user own this app (which could be DLC)
/// </summary>
public static UserHasLicenseForAppResult UserHasLicenseForApp( SteamId steamid, AppId appid )
{
return Internal.UserHasLicenseForApp( steamid, appid );
}
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Steamworks.Data;
@ -254,10 +255,46 @@ public async Task<bool> Subscribe ()
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 this item and wait for it to be downloaded
/// If CancellationToken is default then there is 60 seconds timeout
/// Progress will be set to 0-1
/// </summary>
public async Task<bool> SubscribeDownloadAsync( Action<float> progress = null, CancellationToken ct = default, int milisecondsUpdateDelay = 60 )
{
if ( ct == default )
ct = new CancellationTokenSource( TimeSpan.FromSeconds( 60 ) ).Token;
progress?.Invoke( 0 );
var subResult = await SteamUGC.Internal.SubscribeItem( _id );
if ( subResult?.Result != Result.OK )
return false;
var downloading = Download( true );
if ( !downloading )
return State.HasFlag( ItemState.Installed );
while ( true )
{
if ( ct.IsCancellationRequested )
break;
progress?.Invoke( DownloadAmount );
if ( !IsDownloading && State.HasFlag( ItemState.Installed ) )
break;
await Task.Delay( milisecondsUpdateDelay );
}
return State.HasFlag( ItemState.Installed );
}
/// <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;

View File

@ -15,26 +15,53 @@ internal static class SourceServerQuery
// private static readonly byte A2S_PLAYER = 0x55;
private static readonly byte A2S_RULES = 0x56;
internal static async Task<Dictionary<string, string>> GetRules( ServerInfo server )
{
try
{
var endpoint = new IPEndPoint( server.Address, server.QueryPort );
private static readonly Dictionary<IPEndPoint, Task<Dictionary<string, string>>> PendingQueries =
new Dictionary<IPEndPoint, Task<Dictionary<string, string>>>();
using ( var client = new UdpClient() )
{
client.Client.SendTimeout = 3000;
client.Client.ReceiveTimeout = 3000;
client.Connect( endpoint );
internal static Task<Dictionary<string, string>> GetRules( ServerInfo server )
{
var endpoint = new IPEndPoint(server.Address, server.QueryPort);
return await GetRules( client );
}
}
catch ( System.Exception e )
{
Console.Error.WriteLine( e.Message );
return null;
}
lock (PendingQueries)
{
if (PendingQueries.TryGetValue(endpoint, out var pending))
return pending;
var task = GetRulesImpl(endpoint, server)
.ContinueWith(t =>
{
lock (PendingQueries)
{
PendingQueries.Remove(endpoint);
}
return t;
})
.Unwrap();
PendingQueries.Add(endpoint, task);
return task;
}
}
private static async Task<Dictionary<string, string>> GetRulesImpl( IPEndPoint endpoint, ServerInfo server )
{
try
{
using (var client = new UdpClient())
{
client.Client.SendTimeout = 3000;
client.Client.ReceiveTimeout = 3000;
client.Connect(endpoint);
return await GetRules(client);
}
}
catch (System.Exception e)
{
//Console.Error.WriteLine( e.Message );
return null;
}
}
static async Task<Dictionary<string, string>> GetRules( UdpClient client )
@ -54,14 +81,14 @@ static async Task<Dictionary<string, string>> GetRules( UdpClient client )
var numRules = br.ReadUInt16();
for ( int index = 0; index < numRules; index++ )
{
rules.Add( br.ReadNullTerminatedUTF8String( readBuffer ), br.ReadNullTerminatedUTF8String( readBuffer ) );
rules.Add( br.ReadNullTerminatedUTF8String(), br.ReadNullTerminatedUTF8String() );
}
}
return rules;
}
static byte[] readBuffer = new byte[1024 * 8];
static async Task<byte[]> Receive( UdpClient client )
{
@ -120,10 +147,10 @@ private static async Task<byte[]> GetChallengeData( UdpClient client )
return challengeData;
}
static byte[] sendBuffer = new byte[1024];
static async Task Send( UdpClient client, byte[] message )
{
var sendBuffer = new byte[message.Length + 4];
sendBuffer[0] = 0xFF;
sendBuffer[1] = 0xFF;
sendBuffer[2] = 0xFF;

View File

@ -80,20 +80,22 @@ public static string FormatPrice(string currency, double price)
}
}
public static string ReadNullTerminatedUTF8String( this BinaryReader br, byte[] buffer = null )
static byte[] readBuffer = new byte[1024 * 8];
public static string ReadNullTerminatedUTF8String( this BinaryReader br )
{
if ( buffer == null )
buffer = new byte[1024];
byte chr;
int i = 0;
while ( (chr = br.ReadByte()) != 0 && i < buffer.Length )
lock ( readBuffer )
{
buffer[i] = chr;
i++;
}
byte chr;
int i = 0;
while ( (chr = br.ReadByte()) != 0 && i < readBuffer.Length )
{
readBuffer[i] = chr;
i++;
}
return Encoding.UTF8.GetString( buffer, 0, i );
return Encoding.UTF8.GetString( readBuffer, 0, i );
}
}
}
}

View File

@ -65,6 +65,7 @@ public static bool ShouldCreate( string type )
internal static string Expose( string name )
{
if ( name == "FriendState" ) return "public";
if (name == "FriendFlags") return "public";
if ( name == "MusicStatus" ) return "public";
if ( name == "ParentalFeature" ) return "public";
if ( name == "AuthResponse" ) return "public";
@ -86,6 +87,7 @@ internal static string Expose( string name )
if ( name == "P2PSessionError" ) return "public";
if ( name == "InputType" ) return "public";
if ( name == "InputSourceMode" ) return "public";
if ( name == "UserHasLicenseForAppResult" ) return "public";
return "internal";
}