From 3c705d631584318a604e709eb875fa8bfd98c236 Mon Sep 17 00:00:00 2001 From: SeaFood6913 <139745960+SeaFood6913@users.noreply.github.com> Date: Tue, 27 Feb 2024 15:26:27 +0100 Subject: [PATCH] Patched SteamUGC Bad DownloadAsync implementation --- Facepunch.Steamworks/SteamUgc.cs | 85 +++++++++++++------------ Facepunch.Steamworks/Structs/UgcItem.cs | 4 +- 2 files changed, 45 insertions(+), 44 deletions(-) diff --git a/Facepunch.Steamworks/SteamUgc.cs b/Facepunch.Steamworks/SteamUgc.cs index 57c484f..2160291 100644 --- a/Facepunch.Steamworks/SteamUgc.cs +++ b/Facepunch.Steamworks/SteamUgc.cs @@ -29,7 +29,7 @@ internal override bool InitializeInterface( bool server ) internal static void InstallEvents( bool server ) { - Dispatch.Install( x => OnDownloadItemResult?.Invoke( x.Result ), server ); + Dispatch.Install( x => OnDownloadItemResult?.Invoke( x.AppID.Value, x.PublishedFileId, x.Result ), server ); Dispatch.Install( x => OnItemSubscribed?.Invoke( x.AppID.Value, x.PublishedFileId ), server ); Dispatch.Install( x => OnItemUnsubscribed?.Invoke( x.AppID.Value, x.PublishedFileId ), server ); Dispatch.Install( x => OnItemInstalled?.Invoke( x.AppID.Value, x.PublishedFileId ), server ); @@ -38,7 +38,7 @@ internal static void InstallEvents( bool server ) /// /// Invoked after an item is downloaded. /// - public static event Action OnDownloadItemResult; + public static event Action OnDownloadItemResult; /// /// Invoked when a new item is subscribed. @@ -67,74 +67,63 @@ public static bool Download( PublishedFileId fileId, bool highPriority = false ) /// /// Will attempt to download this item asyncronously - allowing you to instantly react to its installation. /// + /// /// The ID of the file you download. /// An optional callback /// Allows to send a message to cancel the download anywhere during the process. /// How often to call the progress function. /// if downloaded and installed properly. - public static async Task DownloadAsync( PublishedFileId fileId, Action progress = null, int milisecondsUpdateDelay = 60, CancellationToken ct = default ) + public static async Task DownloadAsync( AppId appId, PublishedFileId fileId, Action progress = null, int milisecondsUpdateDelay = 60, CancellationToken ct = default ) { 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; + Result result = Result.None; - // 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 = ( appIdCallback, fileIdInCallback, resultInCallback ) => { - Action onDownloadStarted = null; + if ( appIdCallback == appId && fileIdInCallback == fileId ) + result = resultInCallback; + }; - try - { - var downloadStarted = false; - - onDownloadStarted = r => downloadStarted = true; - OnDownloadItemResult += onDownloadStarted; - - while ( downloadStarted == false ) - { - if ( ct.IsCancellationRequested ) - break; - - await Task.Delay( milisecondsUpdateDelay ); - } - } - finally - { - OnDownloadItemResult -= onDownloadStarted; - } + SteamUGC.OnDownloadItemResult += onDownloadStarted; + if ( SteamUGC.Download( fileId, true ) == false ) + { + SteamUGC.OnDownloadItemResult -= onDownloadStarted; + return item.IsInstalled; } - progress?.Invoke( 0.2f ); - await Task.Delay( milisecondsUpdateDelay ); - - //Wait for downloading completion + try { while ( true ) { - if ( ct.IsCancellationRequested ) + if ( ct != default && ct.IsCancellationRequested ) break; - progress?.Invoke( 0.2f + item.DownloadAmount * 0.8f ); + if ( !item.IsDownloading ) + progress?.Invoke( 0.1f ); + else + progress?.Invoke( 0.1f + item.DownloadAmount * 0.85f ); - if ( !item.IsDownloading && item.IsInstalled ) + if ( !item.IsDownloading && item.IsInstalled && result != Result.None ) break; await Task.Delay( milisecondsUpdateDelay ); } + + if ( result != Result.OK && result != Result.None ) + return false; + + if ( ct.IsCancellationRequested ) + return false; + } + finally + { + SteamUGC.OnDownloadItemResult -= onDownloadStarted; } progress?.Invoke( 1.0f ); - return item.IsInstalled; } @@ -176,6 +165,18 @@ public static async Task StopPlaytimeTrackingForAllItems() return result.Value.Result == Result.OK; } + public static uint GetSubscribedItems(List subscribedItems) + { + if (subscribedItems == null) return 0; + + uint numItems = Internal.GetNumSubscribedItems(); + PublishedFileId[] items = new PublishedFileId[numItems]; + numItems = Internal.GetSubscribedItems( items, numItems ); + for ( int i = 0; i < numItems; i++ ) + subscribedItems.Add( items[i] ); + return numItems; + } + /// /// Suspends all workshop downloads. /// Downloads will be suspended until you resume them by calling or when the game ends. diff --git a/Facepunch.Steamworks/Structs/UgcItem.cs b/Facepunch.Steamworks/Structs/UgcItem.cs index fb63898..35ef770 100644 --- a/Facepunch.Steamworks/Structs/UgcItem.cs +++ b/Facepunch.Steamworks/Structs/UgcItem.cs @@ -283,9 +283,9 @@ public async Task Subscribe () /// If CancellationToken is default then there is 60 seconds timeout /// Progress will be set to 0-1 /// - public async Task DownloadAsync( Action progress = null, int milisecondsUpdateDelay = 60, CancellationToken ct = default ) + public async Task DownloadAsync( AppId appId, Action progress = null, int milisecondsUpdateDelay = 60, CancellationToken ct = default ) { - return await SteamUGC.DownloadAsync( Id, progress, milisecondsUpdateDelay, ct ); + return await SteamUGC.DownloadAsync( appId, Id, progress, milisecondsUpdateDelay, ct ); } ///