264 lines
8.9 KiB
C#
264 lines
8.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace Facepunch.Steamworks
|
|
{
|
|
public partial class Workshop
|
|
{
|
|
public class Query : IDisposable
|
|
{
|
|
internal const int SteamResponseSize = 50;
|
|
|
|
internal SteamNative.UGCQueryHandle_t Handle;
|
|
internal SteamNative.CallbackHandle Callback;
|
|
|
|
/// <summary>
|
|
/// The AppId you're querying. This defaults to this appid.
|
|
/// </summary>
|
|
public uint AppId { get; set; }
|
|
|
|
/// <summary>
|
|
/// The AppId of the app used to upload the item. This defaults to 0
|
|
/// which means all/any.
|
|
/// </summary>
|
|
public uint UploaderAppId { get; set; }
|
|
|
|
public QueryType QueryType { get; set; } = QueryType.Items;
|
|
public Order Order { get; set; } = Order.RankedByVote;
|
|
|
|
public string SearchText { get; set; }
|
|
|
|
public Item[] Items { get; set; }
|
|
|
|
public int TotalResults { get; set; }
|
|
|
|
public ulong? UserId { get; set; }
|
|
|
|
/// <summary>
|
|
/// If order is RankedByTrend, this value represents how many days to take
|
|
/// into account.
|
|
/// </summary>
|
|
public int RankedByTrendDays { get; set; }
|
|
|
|
public UserQueryType UserQueryType { get; set; } = UserQueryType.Published;
|
|
|
|
/// <summary>
|
|
/// Called when the query finishes
|
|
/// </summary>
|
|
public Action<Query> OnResult;
|
|
|
|
/// <summary>
|
|
/// Page starts at 1 !!
|
|
/// </summary>
|
|
public int Page { get; set; } = 1;
|
|
|
|
public int PerPage { get; set; } = SteamResponseSize;
|
|
|
|
internal Workshop workshop;
|
|
internal Friends friends;
|
|
|
|
private int _resultPage = 0;
|
|
private int _resultsRemain = 0;
|
|
private int _resultSkip = 0;
|
|
private List<Item> _results;
|
|
|
|
public void Run()
|
|
{
|
|
if ( Callback != null )
|
|
return;
|
|
|
|
if ( Page <= 0 )
|
|
throw new System.Exception( "Page should be 1 or above" );
|
|
|
|
var actualOffset = ((Page-1) * PerPage);
|
|
|
|
TotalResults = 0;
|
|
|
|
_resultSkip = actualOffset % SteamResponseSize;
|
|
_resultsRemain = PerPage;
|
|
_resultPage = (int) Math.Floor( (float) actualOffset / (float)SteamResponseSize );
|
|
_results = new List<Item>();
|
|
|
|
RunInternal();
|
|
}
|
|
|
|
unsafe void RunInternal()
|
|
{
|
|
if ( FileId.Count != 0 )
|
|
{
|
|
var fileArray = FileId.Select( x => (SteamNative.PublishedFileId_t)x ).ToArray();
|
|
_resultsRemain = fileArray.Length;
|
|
|
|
Handle = workshop.ugc.CreateQueryUGCDetailsRequest( fileArray );
|
|
}
|
|
else if ( UserId.HasValue )
|
|
{
|
|
uint accountId = (uint)( UserId.Value & 0xFFFFFFFFul );
|
|
Handle = workshop.ugc.CreateQueryUserUGCRequest( accountId, (SteamNative.UserUGCList)( int)UserQueryType, (SteamNative.UGCMatchingUGCType)( int)QueryType, SteamNative.UserUGCListSortOrder.LastUpdatedDesc, UploaderAppId, AppId, (uint)_resultPage + 1 );
|
|
}
|
|
else
|
|
{
|
|
Handle = workshop.ugc.CreateQueryAllUGCRequest( (SteamNative.UGCQuery)(int)Order, (SteamNative.UGCMatchingUGCType)(int)QueryType, UploaderAppId, AppId, (uint)_resultPage + 1 );
|
|
}
|
|
|
|
if ( !string.IsNullOrEmpty( SearchText ) )
|
|
workshop.ugc.SetSearchText( Handle, SearchText );
|
|
|
|
foreach ( var tag in RequireTags )
|
|
workshop.ugc.AddRequiredTag( Handle, tag );
|
|
|
|
if ( RequireTags.Count > 0 )
|
|
workshop.ugc.SetMatchAnyTag( Handle, !RequireAllTags );
|
|
|
|
if ( RankedByTrendDays > 0 )
|
|
workshop.ugc.SetRankedByTrendDays( Handle, (uint) RankedByTrendDays );
|
|
|
|
foreach ( var tag in ExcludeTags )
|
|
workshop.ugc.AddExcludedTag( Handle, tag );
|
|
|
|
Callback = workshop.ugc.SendQueryUGCRequest( Handle, ResultCallback );
|
|
}
|
|
|
|
void ResultCallback( SteamNative.SteamUGCQueryCompleted_t data, bool bFailed )
|
|
{
|
|
if ( bFailed )
|
|
throw new System.Exception( "bFailed!" );
|
|
|
|
var gotFiles = 0;
|
|
for ( int i = 0; i < data.NumResultsReturned; i++ )
|
|
{
|
|
if ( _resultSkip > 0 )
|
|
{
|
|
_resultSkip--;
|
|
continue;
|
|
}
|
|
|
|
SteamNative.SteamUGCDetails_t details = new SteamNative.SteamUGCDetails_t();
|
|
if ( !workshop.ugc.GetQueryUGCResult( data.Handle, (uint)i, ref details ) )
|
|
continue;
|
|
|
|
// We already have this file, so skip it
|
|
if ( _results.Any( x => x.Id == details.PublishedFileId ) )
|
|
continue;
|
|
|
|
var item = Item.From( details, workshop );
|
|
|
|
item.SubscriptionCount = GetStat( data.Handle, i, ItemStatistic.NumSubscriptions );
|
|
item.FavouriteCount = GetStat( data.Handle, i, ItemStatistic.NumFavorites );
|
|
item.FollowerCount = GetStat( data.Handle, i, ItemStatistic.NumFollowers );
|
|
item.WebsiteViews = GetStat( data.Handle, i, ItemStatistic.NumUniqueWebsiteViews );
|
|
item.ReportScore = GetStat( data.Handle, i, ItemStatistic.ReportScore );
|
|
|
|
string url = null;
|
|
if ( workshop.ugc.GetQueryUGCPreviewURL( data.Handle, (uint)i, out url ) )
|
|
item.PreviewImageUrl = url;
|
|
|
|
_results.Add( item );
|
|
|
|
_resultsRemain--;
|
|
gotFiles++;
|
|
|
|
if ( _resultsRemain <= 0 )
|
|
break;
|
|
}
|
|
|
|
TotalResults = TotalResults > data.TotalMatchingResults ? TotalResults : (int)data.TotalMatchingResults;
|
|
|
|
Callback.Dispose();
|
|
Callback = null;
|
|
|
|
_resultPage++;
|
|
|
|
if ( _resultsRemain > 0 && gotFiles > 0 )
|
|
{
|
|
RunInternal();
|
|
}
|
|
else
|
|
{
|
|
Items = _results.ToArray();
|
|
|
|
if ( OnResult != null )
|
|
{
|
|
OnResult( this );
|
|
}
|
|
}
|
|
}
|
|
|
|
private int GetStat( ulong handle, int index, ItemStatistic stat )
|
|
{
|
|
ulong val = 0;
|
|
if ( !workshop.ugc.GetQueryUGCStatistic( handle, (uint)index, (SteamNative.ItemStatistic)(uint)stat, out val ) )
|
|
return 0;
|
|
|
|
return (int) val;
|
|
}
|
|
|
|
public bool IsRunning
|
|
{
|
|
get { return Callback != null; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Only return items with these tags
|
|
/// </summary>
|
|
public List<string> RequireTags { get; set; } = new List<string>();
|
|
|
|
/// <summary>
|
|
/// If true, return items that have all RequireTags
|
|
/// If false, return items that have any tags in RequireTags
|
|
/// </summary>
|
|
public bool RequireAllTags { get; set; } = false;
|
|
|
|
/// <summary>
|
|
/// Don't return any items with this tag
|
|
/// </summary>
|
|
public List<string> ExcludeTags { get; set; } = new List<string>();
|
|
|
|
/// <summary>
|
|
/// If you're querying for a particular file or files, add them to this.
|
|
/// </summary>
|
|
public List<ulong> FileId { get; set; } = new List<ulong>();
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Don't call this in production!
|
|
/// </summary>
|
|
public void Block()
|
|
{
|
|
const int sleepMs = 10;
|
|
|
|
workshop.steamworks.Update();
|
|
|
|
while ( IsRunning )
|
|
{
|
|
#if NET_CORE
|
|
System.Threading.Tasks.Task.Delay( sleepMs ).Wait();
|
|
#else
|
|
System.Threading.Thread.Sleep( sleepMs );
|
|
#endif
|
|
workshop.steamworks.Update();
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
// ReleaseQueryUGCRequest
|
|
}
|
|
}
|
|
|
|
private enum ItemStatistic : uint
|
|
{
|
|
NumSubscriptions = 0,
|
|
NumFavorites = 1,
|
|
NumFollowers = 2,
|
|
NumUniqueSubscriptions = 3,
|
|
NumUniqueFavorites = 4,
|
|
NumUniqueFollowers = 5,
|
|
NumUniqueWebsiteViews = 6,
|
|
ReportScore = 7,
|
|
};
|
|
}
|
|
}
|