Files
LuaCsForBarotraumaEP/Libraries/Facepunch.Steamworks/SteamUgc.cs
T
2022-04-08 00:34:17 +09:00

202 lines
5.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Steamworks.Data;
namespace Steamworks
{
/// <summary>
/// Functions for accessing and manipulating Steam user information.
/// This is also where the APIs for Steam Voice are exposed.
/// </summary>
public class SteamUGC : SteamSharedClass<SteamUGC>
{
internal static ISteamUGC Internal => Interface as ISteamUGC;
internal override void InitializeInterface( bool server )
{
SetInterface( server, new ISteamUGC( server ) );
InstallEvents( server );
}
internal static void InstallEvents( bool server )
{
Dispatch.Install<DownloadItemResult_t>( x =>
{
if (x.AppID == SteamClient.AppId)
{
OnDownloadItemResult?.Invoke(x.Result, x.PublishedFileId);
}
}, server );
Dispatch.Install<ItemInstalled_t>(x =>
{
if (x.AppID == SteamClient.AppId)
{
GlobalOnItemInstalled?.Invoke(x.PublishedFileId);
}
}, server);
}
/// <summary>
/// Posted after Download call
/// </summary>
public static event Action<Result, ulong> OnDownloadItemResult;
public static async Task<bool> DeleteFileAsync( PublishedFileId fileId )
{
var r = await Internal.DeleteItem( fileId );
return r?.Result == Result.OK;
}
/// <summary>
/// Start downloading this item. You'll get notified of completion via OnDownloadItemResult.
/// </summary>
/// <param name="fileId">The ID of the file you want to download</param>
/// <param name="highPriority">If true this should go straight to the top of the download list</param>
/// <returns>true if nothing went wrong and the download is started</returns>
public static bool Download( PublishedFileId fileId, bool highPriority = false )
{
return Internal.DownloadItem( fileId, highPriority );
}
/// <summary>
/// Will attempt to download this item asyncronously - allowing you to instantly react to its installation
/// </summary>
/// <param name="fileId">The ID of the file you want to download</param>
/// <param name="progress">An optional callback</param>
/// <param name="ct">Allows you to send a message to cancel the download anywhere during the process</param>
/// <param name="milisecondsUpdateDelay">How often to call the progress function</param>
/// <returns>true if downloaded and installed correctly</returns>
public static async Task<bool> DownloadAsync( PublishedFileId fileId, Action<float> 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, highPriority: 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<Result, ulong> onDownloadStarted = null;
try
{
var downloadStarted = false;
onDownloadStarted = (r, id) => downloadStarted = true;
OnDownloadItemResult += onDownloadStarted;
int iters = 0;
while ( downloadStarted == false )
{
ct.ThrowIfCancellationRequested();
iters++;
if (iters >= 1000 / milisecondsUpdateDelay)
{
if (!item.IsDownloading && !item.IsInstalled)
{
//force download to start if it's not started
if ( Download( fileId, highPriority: true ) == false )
return item.IsInstalled;
}
iters = 0;
}
await Task.Delay( milisecondsUpdateDelay );
}
}
finally
{
OnDownloadItemResult -= onDownloadStarted;
}
}
progress?.Invoke( 0.2f );
await Task.Delay( milisecondsUpdateDelay );
//Wait for downloading completion
{
while ( true )
{
ct.ThrowIfCancellationRequested();
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;
}
/// <summary>
/// Utility function to fetch a single item. Internally this uses Ugc.FileQuery -
/// which you can use to query multiple items if you need to.
/// </summary>
public static async Task<Ugc.Item?> QueryFileAsync( PublishedFileId fileId )
{
var result = await Ugc.Query.All
.WithFileId( fileId )
.GetPageAsync( 1 );
if ( !result.HasValue || result.Value.ResultCount != 1 )
return null;
var item = result.Value.Entries.First();
result.Value.Dispose();
return item;
}
public static async Task<bool> StartPlaytimeTracking(PublishedFileId fileId)
{
var result = await Internal.StartPlaytimeTracking(new[] {fileId}, 1);
return result.Value.Result == Result.OK;
}
public static async Task<bool> StopPlaytimeTracking(PublishedFileId fileId)
{
var result = await Internal.StopPlaytimeTracking(new[] {fileId}, 1);
return result.Value.Result == Result.OK;
}
public static async Task<bool> StopPlaytimeTrackingForAllItems()
{
var result = await Internal.StopPlaytimeTrackingForAllItems();
return result.Value.Result == Result.OK;
}
public static Action<ulong> GlobalOnItemInstalled;
public static uint NumSubscribedItems { get { return Internal.GetNumSubscribedItems(); } }
public static PublishedFileId[] GetSubscribedItems()
{
uint numSubscribed = NumSubscribedItems;
PublishedFileId[] ids = new PublishedFileId[numSubscribed];
Internal.GetSubscribedItems(ids, numSubscribed);
return ids;
}
}
}