diff --git a/Facepunch.Steamworks/SteamUgc.cs b/Facepunch.Steamworks/SteamUgc.cs index e53ebbe..e3a8654 100644 --- a/Facepunch.Steamworks/SteamUgc.cs +++ b/Facepunch.Steamworks/SteamUgc.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; +using System.Threading; using System.Threading.Tasks; using Steamworks.Data; @@ -38,11 +39,91 @@ namespace Steamworks return r?.Result == Result.OK; } + /// + /// Start downloading this item. You'll get notified of completion via OnDownloadItemResult. + /// + /// The ID of the file you want to download + /// If true this should go straight to the top of the download list + /// true if nothing went wrong and the download is started public static bool Download( PublishedFileId fileId, bool highPriority = false ) { return Internal.DownloadItem( fileId, highPriority ); } + /// + /// Will attempt to download this item asyncronously - allowing you to instantly react to its installation + /// + /// The ID of the file you want to download + /// An optional callback + /// Allows you to send a message to cancel the download anywhere during the process + /// How often to call the progress function + /// true if downloaded and installed correctly + public static async Task DownloadAsync( PublishedFileId fileId, Action progress = null, CancellationToken ct = default, int milisecondsUpdateDelay = 60 ) + { + var item = new Steamworks.Ugc.Item( fileId ); + + if ( ct == default ) + ct = new CancellationTokenSource( TimeSpan.FromSeconds( 60 ) ).Token; + + progress?.Invoke( 0.0f ); + + if ( Download( fileId, true ) == false ) + return item.IsInstalled; + + // Steam docs about Download: + // If the return value is true then register and wait + // for the Callback DownloadItemResult_t before calling + // GetItemInstallInfo or accessing the workshop item on disk. + + // Wait for DownloadItemResult_t + { + Action onDownloadStarted = null; + + try + { + var downloadStarted = false; + + onDownloadStarted = r => downloadStarted = true; + OnDownloadItemResult += onDownloadStarted; + + while ( downloadStarted == false ) + { + if ( ct.IsCancellationRequested ) + break; + + await Task.Delay( milisecondsUpdateDelay ); + } + } + finally + { + OnDownloadItemResult -= onDownloadStarted; + } + } + + progress?.Invoke( 0.2f ); + await Task.Delay( milisecondsUpdateDelay ); + + //Wait for downloading completion + { + while ( true ) + { + if ( ct.IsCancellationRequested ) + break; + + progress?.Invoke( 0.2f + item.DownloadAmount * 0.8f ); + + if ( !item.IsDownloading && item.IsInstalled ) + break; + + await Task.Delay( milisecondsUpdateDelay ); + } + } + + progress?.Invoke( 1.0f ); + + return item.IsInstalled; + } + /// /// Utility function to fetch a single item. Internally this uses Ugc.FileQuery - /// which you can use to query multiple items if you need to. diff --git a/Facepunch.Steamworks/Structs/UgcItem.cs b/Facepunch.Steamworks/Structs/UgcItem.cs index fe5dd05..a614789 100644 --- a/Facepunch.Steamworks/Structs/UgcItem.cs +++ b/Facepunch.Steamworks/Structs/UgcItem.cs @@ -126,11 +126,11 @@ namespace Steamworks.Ugc /// /// Start downloading this item. - /// If this returns false the item isn#t getting downloaded. + /// If this returns false the item isn't getting downloaded. /// public bool Download( bool highPriority = false ) { - return SteamUGC.Internal.DownloadItem( Id, highPriority ); + return SteamUGC.Download( Id, highPriority ); } /// @@ -258,79 +258,13 @@ namespace Steamworks.Ugc } /// - /// Allows the user to subscribe to this item and wait for it to be downloaded + /// 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 /// - public async Task SubscribeDownloadAsync( Action progress = null, CancellationToken ct = default, int milisecondsUpdateDelay = 60 ) + public async Task DownloadAsync( Action progress = null, CancellationToken ct = default, int milisecondsUpdateDelay = 60 ) { - if ( ct == default ) - ct = new CancellationTokenSource( TimeSpan.FromSeconds( 60 ) ).Token; - - progress?.Invoke( 0 ); - await Task.Delay( milisecondsUpdateDelay ); - - //Subscribe - { - var subResult = await SteamUGC.Internal.SubscribeItem( _id ); - if ( subResult?.Result != Result.OK ) - return false; - } - - progress?.Invoke( 0.1f ); - await Task.Delay( milisecondsUpdateDelay ); - - //Try to start downloading - { - if ( Download( true ) == false ) - return State.HasFlag( ItemState.Installed ); - - //Steam docs about Download: - //If the return value is true then register and wait - //for the Callback DownloadItemResult_t before calling - //GetItemInstallInfo or accessing the workshop item on disk. - - //Wait for DownloadItemResult_t - { - var downloadStarted = false; - Action onDownloadStarted = null; - onDownloadStarted = r => - { - SteamUGC.OnDownloadItemResult -= onDownloadStarted; - downloadStarted = true; - }; - SteamUGC.OnDownloadItemResult += onDownloadStarted; - - while ( downloadStarted == false ) - { - if ( ct.IsCancellationRequested ) - break; - - await Task.Delay( milisecondsUpdateDelay ); - } - } - } - - progress?.Invoke( 0.2f ); - await Task.Delay( milisecondsUpdateDelay ); - - //Wait for downloading completion - { - while ( true ) - { - if ( ct.IsCancellationRequested ) - break; - - progress?.Invoke( 0.2f + DownloadAmount * 0.8f ); - - if ( !IsDownloading && State.HasFlag( ItemState.Installed ) ) - break; - - await Task.Delay( milisecondsUpdateDelay ); - } - } - - return State.HasFlag( ItemState.Installed ); + return await SteamUGC.DownloadAsync( Id, progress, ct, milisecondsUpdateDelay ); } ///